I'm hoping to be able to modify a MultiPolygon in Openlayers that consists of several sub-polygons. I've activated the standard Modify-interaction, and dragging both vertices and creating new line segments when dragging on the line works fine. However, it seems that it is inconsistent when it comes to the edit operation.
The behaviour is very inconsice. For some vertices, it will drag all connected vertices (desired behaviour) like this:
For other locations, it will drag only some, but not all vertices:
It will not (always, but sometimes) modify both sub-entities when dragging to add new segments:
This is code to reproduce the unexpected behaviour:
var multiPolygon = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": "1.1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
1193836.0495014254,
8383930.129123866
],
[
1193847.7380479588,
8383914.044627354
],
[
1193861.7086440534,
8383894.250081073
],
[
1193873.9649199897,
8383877.232589948
],
[
1193883.717211206,
8383863.628916129
],
[
1193894.5047360454,
8383944.666907605
],
[
1193881.5012495161,
8383963.164657038
],
[
1193860.4841296545,
8383947.813224077
],
[
1193843.674886545,
8383935.594306091
],
[
1193836.0495014254,
8383930.129123866
]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": "2.1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
1193883.717211206,
8383863.628916128
],
[
1193889.0153151448,
8383856.238480768
],
[
1193890.5403921688,
8383857.260414857
],
[
1193909.1752749276,
8383870.745514915
],
[
1193929.301838863,
8383884.8526888145
],
[
1193934.6451744211,
8383888.740497403
],
[
1193929.168255474,
8383896.316176012
],
[
1193903.787411573,
8383931.462094758
],
[
1193894.5047360454,
8383944.666907605
],
[
1193883.717211206,
8383863.628916128
]
]
]
}
}
]
}
const styleFunction = () => {
const style = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0,0,255,0.4)',
width: 2,
}),
fill: new ol.style.Fill({
color: `rgba(0,0,255,0.2)`,
}),
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: 3,
fill: new ol.style.Fill({
color: 'rgba(0,0,255,0.4)',
}),
}),
geometry: function(feature) {
// return the coordinates of the first ring of the polygon
const type = feature.getGeometry().getType();
let coordinates;
if (type === 'Polygon') {
coordinates = feature.getGeometry().getCoordinates()[0];
} else if (type === 'MultiPolygon') {
const coordArray = feature.getGeometry().getCoordinates();
coordinates = [];
coordArray.forEach((ring) => {
coordinates.push(...ring[0]);
});
}
return new ol.geom.MultiPoint(coordinates);
},
}),
];
return style;
};
var multiPolygonFeatures = new ol.format.GeoJSON().readFeatures(multiPolygon);
var vectorSource = new ol.source.Vector({
features: multiPolygonFeatures,
});
var viewCenter = [1193887, 8383870];
var view = new ol.View({
projection: 'EPSG:3857',
center: viewCenter,
zoom: 18,
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: vectorSource,
style: styleFunction
})
],
target: 'map',
view: view,
});
const modify = new ol.interaction.Modify({
source: vectorSource
});
map.addInteraction(modify);
html,
body,
.map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.ol-dragbox {
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(100, 150, 0, 1);
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<div id="map" class="map"></div>
Only one of the coordinates was an exact match between both polygons, The other differed in the last digit.
The Modify interaction will update one coordinate of each geometry at the same position. (There was a bug in older versions of OpenLayers where multiple coordinates of the same geometry were modified when they were the same. You may want to use the latest version in that case.)
Here is the updated example:
var multiPolygon = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": "1.1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
1193836.0495014254,
8383930.129123866
],
[
1193847.7380479588,
8383914.044627354
],
[
1193861.7086440534,
8383894.250081073
],
[
1193873.9649199897,
8383877.232589948
],
[
1193883.717211206,
8383863.628916129
],
[
1193894.5047360454,
8383944.666907605
],
[
1193881.5012495161,
8383963.164657038
],
[
1193860.4841296545,
8383947.813224077
],
[
1193843.674886545,
8383935.594306091
],
[
1193836.0495014254,
8383930.129123866
]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": "2.1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
1193883.717211206,
8383863.628916129
],
[
1193889.0153151448,
8383856.238480768
],
[
1193890.5403921688,
8383857.260414857
],
[
1193909.1752749276,
8383870.745514915
],
[
1193929.301838863,
8383884.8526888145
],
[
1193934.6451744211,
8383888.740497403
],
[
1193929.168255474,
8383896.316176012
],
[
1193903.787411573,
8383931.462094758
],
[
1193894.5047360454,
8383944.666907605
],
[
1193883.717211206,
8383863.628916129
]
]
]
}
}
]
}
const styleFunction = () => {
const style = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0,0,255,0.4)',
width: 2,
}),
fill: new ol.style.Fill({
color: `rgba(0,0,255,0.2)`,
}),
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: 3,
fill: new ol.style.Fill({
color: 'rgba(0,0,255,0.4)',
}),
}),
geometry: function(feature) {
// return the coordinates of the first ring of the polygon
const type = feature.getGeometry().getType();
let coordinates;
if (type === 'Polygon') {
coordinates = feature.getGeometry().getCoordinates()[0];
} else if (type === 'MultiPolygon') {
const coordArray = feature.getGeometry().getCoordinates();
coordinates = [];
coordArray.forEach((ring) => {
coordinates.push(...ring[0]);
});
}
return new ol.geom.MultiPoint(coordinates);
},
}),
];
return style;
};
var multiPolygonFeatures = new ol.format.GeoJSON().readFeatures(multiPolygon);
var vectorSource = new ol.source.Vector({
features: multiPolygonFeatures,
});
var viewCenter = [1193887, 8383870];
var view = new ol.View({
projection: 'EPSG:3857',
center: viewCenter,
zoom: 18,
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: vectorSource,
style: styleFunction
})
],
target: 'map',
view: view,
});
const modify = new ol.interaction.Modify({
source: vectorSource
});
map.addInteraction(modify);
html,
body,
.map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.ol-dragbox {
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(100, 150, 0, 1);
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<div id="map" class="map"></div>