Skip to content

Commit 42c0979

Browse files
authored
Merge pull request #5079 from mind84/circle_measurement
[Feature] Circular geometry measurement on draw
2 parents eb7e9c6 + 9864a3d commit 42c0979

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed

assets/src/modules/Digitizing.js

+59-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Vector as VectorLayer } from 'ol/layer.js';
2424
import { Feature } from 'ol';
2525

2626
import { Point, LineString, Polygon, Circle as CircleGeom, MultiPoint, GeometryCollection } from 'ol/geom.js';
27-
import { circular } from 'ol/geom/Polygon.js';
27+
import { circular, fromCircle } from 'ol/geom/Polygon.js';
2828

2929
import { getArea, getLength } from 'ol/sphere.js';
3030
import Overlay from 'ol/Overlay.js';
@@ -480,11 +480,7 @@ export class Digitizing {
480480
geom.set('totalOverlay', Array.from(this._measureTooltips).pop()[1], true);
481481
geom.on('change', (e) => {
482482
const geom = e.target;
483-
if (geom instanceof Polygon) {
484-
this._updateTotalMeasureTooltip(geom.getCoordinates()[0], geom, 'Polygon', geom.get('totalOverlay'));
485-
} else if (geom instanceof LineString) {
486-
this._updateTotalMeasureTooltip(geom.getCoordinates(), geom, 'Linestring', geom.get('totalOverlay'));
487-
}
483+
this._setTooltipContentByGeom(geom);
488484
});
489485

490486
this._constraintLayer.setVisible(false);
@@ -809,7 +805,10 @@ export class Digitizing {
809805

810806
// Total length for LineStrings
811807
// Perimeter and area for Polygons
812-
if (coords.length > 2) {
808+
// Radius and area for Circles
809+
if(geomType == 'Circle') {
810+
this._updateTotalMeasureTooltip(coords, geom, geomType, Array.from(this._measureTooltips).pop()[1]);
811+
} else if (coords.length > 2) {
813812
this._updateTotalMeasureTooltip(coords, geom, geomType, Array.from(this._measureTooltips).pop()[1]);
814813

815814
// Display angle ABC between three points. B is center
@@ -830,8 +829,8 @@ export class Digitizing {
830829
segmentTooltipContent += '<br>' + angleInDegrees + '°';
831830
}
832831

833-
// Display current segment measure only when drawing lines, polygons or circles
834-
if (['line', 'polygon', 'circle'].includes(this.toolSelected)) {
832+
// Display current segment measure only when drawing lines or polygons
833+
if (['line', 'polygon'].includes(this.toolSelected)) {
835834
this._segmentMeasureTooltipElement.innerHTML = segmentTooltipContent;
836835
Array.from(this._measureTooltips).pop()[0].setPosition(geom.getLastCoordinate());
837836
}
@@ -847,7 +846,16 @@ export class Digitizing {
847846

848847
overlay.getElement().innerHTML = totalTooltipContent;
849848
overlay.setPosition(geom.getInteriorPoint().getCoordinates());
850-
} else {
849+
} else if(geomType == 'Circle') {
850+
// get polygon from circular geometry by approximating the circle with a 128-sided polygon
851+
let circularGeom = fromCircle(geom,128);
852+
let totalTooltipContent = this.formatLength(new LineString([coords[0], coords[1]]));
853+
totalTooltipContent += '<br>' + this.formatArea(circularGeom);
854+
855+
overlay.getElement().innerHTML = totalTooltipContent;
856+
overlay.setPosition(circularGeom.getInteriorPoint().getCoordinates());
857+
}
858+
else {
851859
overlay.getElement().innerHTML = this.formatLength(geom);
852860
overlay.setPosition(geom.getCoordinateAt(0.5));
853861
}
@@ -885,6 +893,43 @@ export class Digitizing {
885893
return output;
886894
}
887895

896+
/**
897+
* Initializes measure tooltip and change event on a feature loaded from local storage.
898+
* @param {Geometry} geom The geometry.
899+
*/
900+
_initMeasureTooltipOnLoadedFeatures(geom){
901+
// create overlays
902+
this.createMeasureTooltips();
903+
904+
geom.set('totalOverlay', Array.from(this._measureTooltips).pop()[1], true);
905+
// calculate measures
906+
this._setTooltipContentByGeom(geom);
907+
geom.on('change', (e) => {
908+
const geom = e.target;
909+
this._setTooltipContentByGeom(geom);
910+
});
911+
// make measure tooltip static and hidden
912+
this._totalMeasureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
913+
this._totalMeasureTooltipElement.classList.toggle('hide', !this._hasMeasureVisible);
914+
915+
// reset measureTooltip element
916+
this._totalMeasureTooltipElement = null;
917+
}
918+
919+
/**
920+
* Calculates measuements for a specific geometry.
921+
* @param {Geometry} geom The geometry.
922+
*/
923+
_setTooltipContentByGeom(geom){
924+
if (geom instanceof Polygon) {
925+
this._updateTotalMeasureTooltip(geom.getCoordinates()[0], geom, 'Polygon', geom.get('totalOverlay'));
926+
} else if (geom instanceof LineString) {
927+
this._updateTotalMeasureTooltip(geom.getCoordinates(), geom, 'Linestring', geom.get('totalOverlay'));
928+
} else if ( geom instanceof CircleGeom) {
929+
this._updateTotalMeasureTooltip([geom.getFirstCoordinate(), geom.getLastCoordinate()], geom, 'Circle', geom.get('totalOverlay'));
930+
}
931+
}
932+
888933
/**
889934
* Creates measure tooltips
890935
*/
@@ -1100,6 +1145,8 @@ export class Digitizing {
11001145

11011146
if(loadedGeom){
11021147
const loadedFeature = new Feature(loadedGeom);
1148+
// init measure tooltip
1149+
this._initMeasureTooltipOnLoadedFeatures(loadedFeature.getGeometry());
11031150
loadedFeature.set('color', feature.color);
11041151
loadedFeatures.push(loadedFeature);
11051152
}
@@ -1114,6 +1161,8 @@ export class Digitizing {
11141161
console.log(loadedFeatures.length+' features read from WKT!');
11151162
// set color
11161163
for(const loadedFeature of loadedFeatures){
1164+
// init measure tooltip
1165+
this._initMeasureTooltipOnLoadedFeatures(loadedFeature.getGeometry());
11171166
loadedFeature.set('color', this._drawColor);
11181167
}
11191168
// No features read from localStorage so remove the data

tests/end2end/playwright/draw.spec.js

+27
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,26 @@ test.describe('Draw', () => {
281281
expect(await page.evaluate(() => lizMap.mainLizmap.digitizing.featureDrawn)).toBeNull();
282282
});
283283

284+
test('Circular geometry measure', async ({ page }) => {
285+
await page.locator('#draw button.dropdown-toggle:nth-child(2)').click();
286+
await page.locator('.digitizing-circle > svg').click();
287+
await page.locator('#newOlMap').click({
288+
position: {
289+
x: 450,
290+
y: 75
291+
}
292+
});
293+
await page.locator('#newOlMap').click({
294+
position: {
295+
x: 480,
296+
y: 115
297+
}
298+
});
299+
await page.locator('#draw button.digitizing-toggle-measure').click();
300+
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toBeVisible();
301+
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toHaveText('3.3 km34.27 km2');
302+
})
303+
284304
test('From local storage', async ({ page }) => {
285305
const the_json = '[{"type":"Polygon","color":"#000000","coords":[[[764321.0416656,6290805.935670358],[767628.3399468632,6290805.935670358],[767628.3399468632,6295105.423436],[764321.0416656,6295105.423436],[764321.0416656,6290805.935670358],[764321.0416656,6290805.935670358]]]}]';
286306
await page.evaluate(token => localStorage.setItem('testsrepository_draw_draw_drawLayer', token), the_json);
@@ -313,6 +333,13 @@ test.describe('Draw', () => {
313333
await expect(drawn[0][4]).toHaveLength(2);
314334
await expect(drawn[0][5]).toHaveLength(2);
315335

336+
// check measure initialization
337+
await page.locator('#draw button.digitizing-toggle-measure').click();
338+
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toBeVisible();
339+
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toHaveText('15.2 km14.19 km2');
340+
// hide measure
341+
await page.locator('#draw button.digitizing-toggle-measure').click();
342+
316343
// Hide all elements but #map, #newOlMap and their children
317344
await page.$eval("*", el => el.style.visibility = 'hidden');
318345
await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible');

0 commit comments

Comments
 (0)