I am trying to implement feature rotation in my project. So far I have added select interaction, to select feature that needs to be rotated, and pass it to function, that contains almost all the code, that is provided in Openlayers example of how to achieve this.
This is the function i use to select feature from map:
setRotateElement() {
this.drawInteraction = new olSelectInteraction({
style: null,
layers: (layer) => {
return layer.get('layerName') !== 'geolocation';
},
hitTolerance: 4
});
if (this.map) {
this.map.addInteraction(this.drawInteraction);
}
this.drawInteraction.on('select', (data) => this.onRotateSelectEnd(data));
}
And this is onRotateSelectEnd
(please don't mind random console logs, i have set them to check for feature,that is being modified and other things). For now, I have simply copied the solution from Openlayers example, but it seems, that something is off.
onRotateSelectEnd(data) {
if(data.selected[0]) {
console.log('selected');
const source = new VectorSource();
source.addFeature(data.selected[0]);
const style = new Style({
geometry: (feature) => {
const modifyGeometry = feature.get('modifyGeometry');
return modifyGeometry ? modifyGeometry.geometry : feature.getGeometry();
},
fill: new Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2,
}),
image: new CircleStyle({
radius: 7,
fill: new Fill({
color: '#ffcc33',
}),
}),
});
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];
} else if (type === 'LineString') {
center = geometry.getCoordinateAt(0.5);
coordinates = geometry.getCoordinates();
} else {
center = getCenter(geometry.getExtent());
}
let sqDistances;
if (coordinates) {
sqDistances = coordinates.map(function (coordinate) {
const dx = coordinate[0] - center[0];
const dy = coordinate[1] - center[1];
return dx * dx + dy * dy;
});
minRadius = Math.sqrt(Math.max.apply(Math, sqDistances)) / 3;
} else {
minRadius =
Math.max(
getWidth(geometry.getExtent()),
getHeight(geometry.getExtent())
) / 3;
}
return {
center: center,
coordinates: coordinates,
minRadius: minRadius,
sqDistances: sqDistances,
};
}
const vector = new VectorLayer({
source: source,
style: (feature) => {
console.log(feature);
const styles = [style];
const modifyGeometry = feature.get('modifyGeometry');
const geometry = modifyGeometry
? modifyGeometry.geometry
: feature.getGeometry();
const result = calculateCenter(geometry);
const center = result.center;
console.log(center);
if (center) {
styles.push(
new Style({
geometry: new Point(center),
image: new CircleStyle({
radius: 4,
fill: new Fill({
color: '#ff3333',
}),
}),
})
);
const coordinates = result.coordinates;
if (coordinates) {
const minRadius = result.minRadius;
const sqDistances = result.sqDistances;
const rsq = minRadius * minRadius;
const points = coordinates.filter(function (coordinate, index) {
return sqDistances[index] > rsq;
});
styles.push(
new Style({
geometry: new MultiPoint(points),
image: new CircleStyle({
radius: 4,
fill: new Fill({
color: '#33cc33',
}),
}),
})
);
}
}
return styles;
},
});
this.map.addLayer(vector);
const defaultStyle1 = new Modify({source: source})
.getOverlay()
.getStyleFunction();
const modify = new Modify({
source: source,
condition: function (event) {
return primaryAction(event) && !platformModifierKeyOnly(event);
},
deleteCondition: never,
insertVertexCondition: never,
style: (feature) => {
feature.get('features').forEach(function (modifyFeature) {
const modifyGeometry = modifyFeature.get('modifyGeometry');
if (modifyGeometry) {
const point = (<any>feature.getGeometry()).getCoordinates();
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.minRadius = result.minRadius;
}
const center = modifyGeometry.center;
const minRadius = modifyGeometry.minRadius;
let dx, dy;
dx = modifyPoint[0] - center[0];
dy = modifyPoint[1] - center[1];
const initialRadius = Math.sqrt(dx * dx + dy * dy);
if (initialRadius > minRadius) {
const initialAngle = Math.atan2(dy, dx);
dx = point[0] - center[0];
dy = point[1] - center[1];
const currentRadius = Math.sqrt(dx * dx + dy * dy);
if (currentRadius > 0) {
const currentAngle = Math.atan2(dy, dx);
const geometry = modifyGeometry.geometry0.clone();
geometry.rotate(currentAngle - initialAngle, center);
modifyGeometry.geometry = geometry;
}
}
}
});
return defaultStyle1(feature, null);
},
});
modify.on('modifystart', function (event) {
event.features.forEach(function (feature) {
feature.set(
'modifyGeometry',
{geometry: feature.getGeometry().clone()},
true
);
});
});
modify.on('modifyend', function (event) {
event.features.forEach(function (feature) {
const modifyGeometry = feature.get('modifyGeometry');
if (modifyGeometry) {
feature.setGeometry(modifyGeometry.geometry);
feature.unset('modifyGeometry', true);
}
});
});
this.map.addInteraction(modify);
}
if(data.deselected[0]) {
console.log('deselected');
console.log(data);
}
}
I tried to test code from example in a sandbox, there it seems to work just fine. I can draw the feature, and then it creates points on vertexes and allows to rotate the feature. In my project, Modify interaction is trying to modify the feature (see screenshot 2), and if I try to rotate it, after I release the mouse button, it rotates, but it is not the behaviour I want to achieve.
Is there anything that I forgot to add / modify, so the example from Openlayers works with selected feature? Thank you all in advance!
Versions I am using:
Angular 15.1.3, Openlayers 7.2.2, Typescript 4.9.
P.S - Don't mind that I just copied the example from Openlayers and didn't format it properly, so the synax is not so "Vanilla JS style". I wanted to make it work first, and then I will format it properly and make an seperate service for it in my project.
Screenshot 1 (original geometry)
Screenshot 2 (trying to rotate it)
Screenshot 3 (geometry after I release the point I pulled)