Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: distance measurement for line strings #1308

Draft
wants to merge 35 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b33c0b0
chore: implement very simple area measurement in drawstart handler
spectrachrome Oct 9, 2024
7c4f058
wip: try calculating circumference
spectrachrome Oct 9, 2024
d4d87dd
wip: use getLength method to calculate distances
spectrachrome Oct 10, 2024
24c44df
feat: properly implement area measurement with correct distances
spectrachrome Oct 14, 2024
d12d50e
fix: make sure overlays are cleaned up properly
spectrachrome Oct 21, 2024
8290727
feat: simplify calculation and provide area for polygons
spectrachrome Oct 21, 2024
66356ba
Merge branch 'main' into map/feature/area-measurements
spectrachrome Oct 21, 2024
c4eb290
fix: merge conflict
spectrachrome Oct 21, 2024
ed16f3f
chore: remove unnecessary method
spectrachrome Oct 21, 2024
241c41c
fix: only clear map overlays if applicable
spectrachrome Oct 21, 2024
b8932b9
chore: formatting
spectrachrome Oct 21, 2024
555a0c4
chore: add a `measure` attribute to map
spectrachrome Oct 30, 2024
e5b4ede
fix: a number of display issues, migrate to line string only
spectrachrome Oct 30, 2024
1bc5e09
feat: create a story for distance measurements
spectrachrome Oct 30, 2024
a4f5268
fix: linter errors
spectrachrome Oct 30, 2024
b44ea98
Merge branch 'main' into map/feature/area-measurements
spectrachrome Oct 30, 2024
5b6efad
chore: run prettier
spectrachrome Oct 30, 2024
51ca165
Merge branch 'map/feature/area-measurements' of github.com:EOX-A/EOxE…
spectrachrome Oct 30, 2024
0614d89
doc: update comments
spectrachrome Oct 30, 2024
389ebff
feat: define measure attribute on draw tools
spectrachrome Nov 11, 2024
90407ad
chore: move measuring from map into draw tools
spectrachrome Nov 11, 2024
a1acaa5
chore: remove old imports
spectrachrome Nov 11, 2024
cf617ad
chore: run prettier
spectrachrome Nov 11, 2024
43555b4
fix: merge conflicts
spectrachrome Nov 11, 2024
615589d
fix: linter issues, add more doc comments
spectrachrome Nov 11, 2024
ba9a55f
chore: provide single default export in measure helper
spectrachrome Nov 11, 2024
a3580d7
chore: cleanup
spectrachrome Nov 11, 2024
18a71eb
chore: run prettier (again?)
spectrachrome Nov 11, 2024
658516f
chore: replace mock-map reference
spectrachrome Nov 15, 2024
9c1c014
temp: work on tests
spectrachrome Nov 18, 2024
f9bc7fe
chore: add play function to fail e2e test deliberately
spectrachrome Nov 28, 2024
68014bc
chore: remove cypress file in favor of play fn test
spectrachrome Nov 28, 2024
ceae29c
Merge branch 'main' into map/feature/area-measurements
spectrachrome Nov 28, 2024
651442a
fix: linter errors and format
spectrachrome Nov 28, 2024
58ca335
chore: remove play function
spectrachrome Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions elements/drawtools/src/helpers/measure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { getLength } from "ol/sphere";
import Overlay from "ol/Overlay";

/**
* Render the tooltip overlay on the map near the last point of the drawn line.
*
* @param {Object} evt The triggering draw event.
* @param {import("../main").EOxDrawTools} EoxDrawTool
*/
function measure(evt, EoxDrawTool) {
let { measureTooltip, measureTooltipElement } = createTooltip();
let tooltipCoord = evt.coordinate;

let geometry = evt.feature.getGeometry();

EoxDrawTool.eoxMap.map.addOverlay(measureTooltip);

if (geometry.getType() === "LineString") {
measureTooltipElement.style.visibility = "visible";
measureTooltipElement.style.pointerEvents = "inherit";

evt.feature.getGeometry().on("change", function (_evt) {
tooltipCoord = geometry.getLastCoordinate();
measureTooltipElement.innerHTML = formatLength(geometry);
measureTooltip.setPosition(tooltipCoord);
});
}
}

/**
* Create an OpenLayers overlay with the measuring tooltip.
*
* @return {Object} An object with the overlay and its element.
*/
function createTooltip() {
let measureTooltipElement = document.createElement("div");

const measureTooltip = new Overlay({
element: measureTooltipElement,
offset: [16, 0],
positioning: "center-left",
stopEvent: false,
insertFirst: false,
});

measureTooltipElement.className = "ol-tooltip ol-tooltip-measure";
measureTooltipElement.style.padding = "3px 7px";
measureTooltipElement.style.borderRadius = "4px";
measureTooltipElement.style.backdropFilter = "blur(20px)";
measureTooltipElement.style.background = "#004180AA";
measureTooltipElement.style.fontFamily = "monospace, sans-serif";
measureTooltipElement.style.color = "#FFF";
measureTooltipElement.style.visibility = "visible";
measureTooltipElement.style.display = "block";
measureTooltipElement.style.pointerEvents = "none";

return { measureTooltip, measureTooltipElement };
}

/**
* Calculate real distance on the map and format the output.
*
* @param {Polygon} line The line string to calculate the distance for.
* @return {string} Formatted length.
*/
const formatLength = function (line) {
const length = getLength(line);
let output;
if (length > 100) {
output = Math.round((length / 1000) * 100) / 100 + " " + "km";
} else {
output = Math.round(length * 100) / 100 + " " + "m";
}
return output;
};

export default measure;
1 change: 1 addition & 0 deletions elements/drawtools/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class EOxDrawTools extends LitElement {
format: { type: String },
type: { type: String },
unstyled: { type: Boolean },
measure: { type: Boolean },
};
}

Expand Down
6 changes: 6 additions & 0 deletions elements/drawtools/src/methods/draw/discard-drawing.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ const discardDrawingMethod = (EoxDrawTool) => {
EoxDrawTool.drawLayer.getSource().clear();
//@ts-expect-error TODO
EoxDrawTool.geoJSON = null;

// Clear map overlays, if available
const map = EoxDrawTool.eoxMap.map;
if (map && map.getOverlays !== undefined) {
EoxDrawTool.eoxMap.map.getOverlays().clear();
}
};

// Function to trigger updates after discarding drawing
Expand Down
9 changes: 9 additions & 0 deletions elements/drawtools/src/methods/draw/start-drawing.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import measure from "../../helpers/measure.js";

/**
* Initiates the drawing process by initializing the draw layer,
* activating drawing, and updating the drawing status.
Expand All @@ -11,6 +13,13 @@ const startDrawingMethod = (EoxDrawTool) => {
EoxDrawTool.draw.setActive(true);
// Add selection
EoxDrawTool.selectionEvents.addSelectionEvent();

// Set up measurements, if desired
if (EoxDrawTool.measure) {
EoxDrawTool.draw.on("drawstart", (evt) => {
measure(evt, EoxDrawTool);
});
}
};

// Function to update the drawing status and request an update
Expand Down
25 changes: 25 additions & 0 deletions elements/drawtools/stories/distance-measurement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { html } from "lit";

import { STORIES_MAP_STYLE, STORIES_LAYERS_ARRAY } from "../src/enums";

/**
* Component demonstrating how EOxMap and the draw tools can be used to measure distances on a map.
*/
export const DistanceMeasurement = {
render: () => html`
<eox-map
id="line-measurement"
style=${STORIES_MAP_STYLE}
.layers=${STORIES_LAYERS_ARRAY}
/>
<eox-drawtools
for="eox-map#line-measurement"
type="LineString"
multiple-features
allow-modify
measure
/>
`,
};

export default DistanceMeasurement;
7 changes: 7 additions & 0 deletions elements/drawtools/stories/drawtools.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MultiFeaturesSelectStory,
FeaturesProjectionStory,
FormatStory,
DistanceMeasurementStory,
} from "./index";

export default {
Expand Down Expand Up @@ -89,3 +90,9 @@ export const CSSVariableOverride = CSSVariableOverrideStory;
* By setting the `unstyled` attribute or property, the element has no styling applied.
*/
export const Unstyled = UnstyledStory;

/**
* Setting the `measure` attribute on the map and drawing with `LineString`s will cause
* a tooltip to be displayed showing the distance of the line being drawn.
*/
export const DistanceMeasurement = DistanceMeasurementStory;
1 change: 1 addition & 0 deletions elements/drawtools/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export { default as MultiFeaturesSelectStory } from "./multi-feature-select"; //
export { default as FeaturesProjectionStory } from "./features-projection"; // Story showcasing emitting drawn features in different projections
export { default as FormatStory } from "./formats"; // Story showcasing emitting drawn features in different formats
export { default as CSSVariableOverrideStory } from "./css-variable-override"; // Story demonstrating css override
export { default as DistanceMeasurementStory } from "./distance-measurement"; // Story demonstrating distance measurements.
export { default as UnstyledStory } from "./unstyled"; // Story demonstrating unstyled variant of element.
1 change: 1 addition & 0 deletions elements/drawtools/test/cases/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as loadDrawToolsTest } from "./load-drawtool"; // Test for load
export { default as copyGeoJsonEditorTest } from "./copy-geo-json-editor"; // Test to check whether a valid geo-json present in the clipboard
export { default as setLayerId } from "./set-layer-id"; // Test to set the layer id and check if the draw button icon changes
export { default as setDifferentFormats } from "./set-different-formats"; // Test if the drawn features are emitted in different formats
export { default as measureTooltipTest } from "./shows-measure-tooltip"; // Test to check if the measure tooltip is displayed
2 changes: 1 addition & 1 deletion elements/drawtools/test/cases/set-layer-id.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { drawTools, drawBtn } = TEST_SELECTORS;
*/
const setLayerId = () => {
const layerId = "regions";
cy.get("mock-map").then(($el) => {
cy.get("eox-map").then(($el) => {
cy.log($el[0]);
$el[0].layers = STORIES_VECTOR_LAYERS;
});
Expand Down
30 changes: 30 additions & 0 deletions elements/drawtools/test/cases/shows-measure-tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { TEST_SELECTORS } from "../../src/enums";

// Destructure TEST_SELECTORS object
const { drawTools, controller, drawBtn } = TEST_SELECTORS;

/**
* Clicks the draw button and verifies the 'drawing' state.
*/
const measureTooltipTest = () => {
// Start drawing mode so that we get the measure tooltip later
cy.get(drawTools)
.shadow()
.within(() => {
cy.get(controller).within(() => {
cy.get(drawBtn).click();
});
});

// Click into the center of the map, move and click again to create a line.
cy.get("eox-map").click(15, 40);
cy.get("eox-map").click("center");

cy.get("eox-map")
.shadow()
.within(() => {
cy.get(".ol-tooltip-measure").should("exist");
});
};

export default measureTooltipTest;
14 changes: 11 additions & 3 deletions elements/drawtools/test/general.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import {
loadDrawToolsTest,
setDifferentFormats,
setLayerId,
measureTooltipTest,
} from "./cases";

import { TEST_SELECTORS } from "../src/enums";
import "../../map/src/main";

// Destructuring TEST_SELECTORS object
const { drawTools } = TEST_SELECTORS;
Expand All @@ -19,10 +21,14 @@ const { drawTools } = TEST_SELECTORS;
describe("Drawtools", () => {
// Setting up the environment before each test
beforeEach(() => {
// Mounting mock-map and eox-drawtools elements
cy.mount("<mock-map></mock-map>").as("mock-map");
cy.mount(
`<eox-drawtools show-editor import-features for="mock-map"></eox-drawtools>`,
'<eox-map center="[15,48]" layers="[{"type":"Tile","source":{"type":"OSM"}}]" zoom="7" style="width: 100%; height: 300px;"></eox-map>',
).as("eox-map");

//cy.mount("<mock-map></mock-map>").as("mock-map");

cy.mount(
`<eox-drawtools show-editor import-features measure type="LineString" for="eox-map"></eox-drawtools>`,
).as(drawTools);
});

Expand All @@ -44,4 +50,6 @@ describe("Drawtools", () => {

// Test case to check if the drawn features are emitted in different formats
it("emits drawn features in different formats", () => setDifferentFormats());

it("renders the measurement tooltip correctly", () => measureTooltipTest());
});
Loading