1

Using the ol.Draw interaction and ol.interaction.Draw.createBox() geometry function we can draw a regular rectangle:

let geomFunction = ol.interaction.Draw.createBox();
let draw = new ol.interaction.Draw({
  source: layer.getSource(),
  type: 'Circle',
  geometryFunction: geomFunction
});

but when using ol.Modify interaction to modify the rectangle I can't ensure the geometry will still a regular rectangle because I can't set a geometry function to the modifying interaction! How can I ensure or preserve the geometry shape when modifying?

4
  • Any help will be appreciated. If question is not clear enough plz tell me.
    – abd0991
    May 7, 2018 at 11:30
  • 1
    Have a look at this. Might help u!!! -->viglino.github.io/ol-ext/examples/interaction/…
    – pavlos
    May 7, 2018 at 12:25
  • I already looked at this extension, but I want I simple code to apply to my app not an extension. If there is a way to preserve the geometry shape on modifying plz let me know.
    – abd0991
    May 7, 2018 at 16:19
  • Any updates ???
    – abd0991
    May 10, 2018 at 12:30

2 Answers 2

1

It is possible to use directly OpenLayers library without ol-ex (at least with last version of OpenLayers 7). See code snippet: https://jsfiddle.net/pfavero/pnLajvwt/27/

The example is based on Scale and Rotate using Modify Interaction of the official OpenLayers examples.

The ol.Draw interaction has the possibility via the method ol.interaction.Draw.createBox() to draw only boxes, but ol.Modify interaction does not have the same option. Therefore, it is necessary to extend the standard behavior of ol.Modify interaction.

Look at the JS code. At the beginning of the modification process, the selected geometry will be temporarily saved inside the feature as “modifyGeometry”. During the modification process (inside the style function) modifyGeometry will be adjusted to preserve the box shape with the correct dimension. And at the end of the modification process, “modifyGeometry” substitutes the original geometry…

Here the JS code of my fiddle example:


const source = new ol.source.Vector();
const style = new ol.style.Style({
    geometry: function (feature) {
        const modifyGeometry = feature.get('modifyGeometry');
        return modifyGeometry ? modifyGeometry.geometry : feature.getGeometry();
    },
    fill: new ol.style.Fill({
        color: 'rgba(255, 255, 255, 0.6)',
    }),
    stroke: new ol.style.Stroke({
        color: '#ffcc33',
        width: 2,
    })
});

const vector = new ol.layer.Vector({
    source: source,
    style: function (feature) {
        return style;
    },
});

const map = new ol.Map({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM(),
        }), 
        vector
    ],
    target: 'map',
    view: new ol.View({
        center: [1800000, 6400000],
        zoom: 5,
    }),
});


// add draw interaction
const draw = new ol.interaction.Draw({
    source: source,
    type: 'Circle',
    geometryFunction: ol.interaction.Draw.createBox()
});
map.addInteraction(draw);

// add modify interaction
const defaultModify = new ol.interaction.Modify({source: source});
const defaultModifyStyle = defaultModify.getOverlay().getStyleFunction();
const modify = new ol.interaction.Modify({
    source: source,
    deleteCondition: ol.events.condition.never,
    insertVertexCondition: ol.events.condition.never,
    style: function (feature) {
        source.getFeatures().forEach(function (modifyFeature) {
            const modifyGeometry = modifyFeature.get('modifyGeometry');
            if (modifyGeometry) {
                const point = feature.getGeometry().getCoordinates();
                console.log(point);
                let modifyPoint = modifyGeometry.point;
                if (!modifyPoint) {
                    // save the initial geometry and vertex position
                    modifyPoint = point;
                    modifyGeometry.point = modifyPoint;
                    modifyGeometry.geometry0 = modifyGeometry.geometry;
                    // get anchor and minimum radius of vertices to be used
                    const result = calculateCenter(modifyGeometry.geometry0);
                    modifyGeometry.center = result.center;
                    modifyGeometry.deltas = result.deltas;
                }

                const center = modifyGeometry.center;
                const minRadius = modifyGeometry.minRadius;
                let dx, dy;
                let dx0 = modifyPoint[0] - center[0];
                let dy0 = modifyPoint[1] - center[1];
                
                dx = point[0] - center[0];
                dy = point[1] - center[1];
                const geometry = modifyGeometry.geometry0.clone();
                geometry.scale(dx / dx0, dy / dy0, center);
                modifyGeometry.geometry = geometry;
                
            }
        });
        return defaultModifyStyle(feature);
    }
});
map.addInteraction(modify);
addEventsToModInteraction();


// change 'draw' from/to 'modify'
const typeSelect = document.getElementById('type');
typeSelect.onchange = function () {
    if (typeSelect.value === 'draw') {
        draw.setActive(true);
        modify.setActive(false);
    } else {
        draw.setActive(false);
        modify.setActive(true);
    }
};


function addEventsToModInteraction(){
    modify.setActive(false);
    modify.on('modifystart', function (event) {
        console.log('event.features', event.features);
        event.features.forEach(function (feature) {
            // geometry -> modifyGeometry
            feature.set(
                'modifyGeometry',
                {geometry: feature.getGeometry().clone()},
                true
            );
        });
    });
    modify.on('modifyend', function (event) {
        event.features.forEach(function (feature) {
            const modifyGeometry = feature.get('modifyGeometry');
            // modifyGeometry -> geometry
            if (modifyGeometry) {
                feature.setGeometry(modifyGeometry.geometry);
                feature.unset('modifyGeometry', true);
            }
        });
    });
}

function calculateCenter(geometry) {
    let center, coordinates, minRadius;
    const type = geometry.getType();
    if (type === 'Polygon') {
        let x = 0;
        let y = 0;
        let i = 0;
        coordinates = geometry.getCoordinates()[0].slice(1);
        coordinates.forEach(function (coordinate) {
            x += coordinate[0];
            y += coordinate[1];
            i++;
        });
        center = [x / i, y / i];
    }
    let deltas;
    if (coordinates) {
        deltas = coordinates.map(function (coordinate) {
            const dx = coordinate[0] - center[0];
            const dy = coordinate[1] - center[1];
            return dx, dy;
        });
        // minRadius = Math.sqrt(Math.max.apply(Math, sqDistances)) / 3;
    } 
    return {
        center: center,
        deltas: deltas,
    };
}
1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Sep 2, 2022 at 6:40
0

I finally used ol-ext, it do the job.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.