@open-pioneer/measurement 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/Measurement.d.ts +31 -1
- package/Measurement.js +24 -12
- package/Measurement.js.map +1 -1
- package/MeasurementController.d.ts +25 -14
- package/MeasurementController.js +247 -107
- package/MeasurementController.js.map +1 -1
- package/README.md +38 -0
- package/index.d.ts +1 -1
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @open-pioneer/measurement
|
|
2
2
|
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b152428: Update trails dependencies
|
|
8
|
+
- 23b48ad: Add two new optional properties:
|
|
9
|
+
|
|
10
|
+
- `predefinedMeasurements`: an array of measurements that will be added to the map (without user interaction)
|
|
11
|
+
- `onMeasurementsChange`: an event listener that will be called when measurements are added or removed
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
const predefinedMeasurements = useMemo(
|
|
15
|
+
() => [
|
|
16
|
+
new LineString([
|
|
17
|
+
[398657.97, 5755696.26],
|
|
18
|
+
[402570.98, 5757547.78]
|
|
19
|
+
])
|
|
20
|
+
],
|
|
21
|
+
[]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
<Measurement
|
|
25
|
+
mapId={MAP_ID}
|
|
26
|
+
onMeasurementsChange={(e) => console.log(e.kind, e.geometry)}
|
|
27
|
+
predefinedMeasurements={predefinedMeasurements}
|
|
28
|
+
/>;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [b152428]
|
|
32
|
+
- Updated dependencies [291ccb6]
|
|
33
|
+
- @open-pioneer/map@0.6.1
|
|
34
|
+
|
|
35
|
+
## 0.4.3
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- 28e092a: Update dependencies
|
|
40
|
+
- 484ad86: Add tooltip role to tooltip divs (See https://github.com/open-pioneer/trails-openlayers-base-packages/issues/309).
|
|
41
|
+
- Updated dependencies [28e092a]
|
|
42
|
+
- Updated dependencies [0d51d2f]
|
|
43
|
+
- Updated dependencies [76f8863]
|
|
44
|
+
- @open-pioneer/map@0.6.0
|
|
45
|
+
|
|
3
46
|
## 0.4.2
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
package/Measurement.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { CommonComponentProps } from "@open-pioneer/react-utils";
|
|
2
2
|
import { StyleLike } from "ol/style/Style";
|
|
3
3
|
import { FC } from "react";
|
|
4
|
+
import LineString from "ol/geom/LineString";
|
|
5
|
+
import Polygon from "ol/geom/Polygon";
|
|
6
|
+
/** Emitted when a new measurement is being added to the map. */
|
|
7
|
+
export interface MeasurementsAddEvent {
|
|
8
|
+
kind: "add-measurement";
|
|
9
|
+
geometry: MeasurementGeometry;
|
|
10
|
+
}
|
|
11
|
+
/** Emitted when a measurement is being removed from the map. */
|
|
12
|
+
export interface MeasurementsRemoveEvent {
|
|
13
|
+
kind: "remove-measurement";
|
|
14
|
+
geometry: MeasurementGeometry;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A change event emitted by {@link Measurement} when measurements change.
|
|
18
|
+
*
|
|
19
|
+
* NOTE: Non-exhaustive. More event types may be added in a future version.
|
|
20
|
+
**/
|
|
21
|
+
export type MeasurementsChangeEvent = MeasurementsAddEvent | MeasurementsRemoveEvent;
|
|
22
|
+
/**
|
|
23
|
+
* Represents the geometry of a measurement.
|
|
24
|
+
*/
|
|
25
|
+
export type MeasurementGeometry = LineString | Polygon;
|
|
4
26
|
/**
|
|
5
27
|
* This is for special properties of the Measurement.
|
|
6
28
|
*/
|
|
@@ -17,8 +39,16 @@ export interface MeasurementProps extends CommonComponentProps {
|
|
|
17
39
|
* The style for the finished drawn feature's geometry.
|
|
18
40
|
*/
|
|
19
41
|
finishedFeatureStyle?: StyleLike;
|
|
42
|
+
/**
|
|
43
|
+
* List of measurements to be rendered when the component is initialized.
|
|
44
|
+
*/
|
|
45
|
+
predefinedMeasurements?: MeasurementGeometry[];
|
|
46
|
+
/**
|
|
47
|
+
* Event handler that is called whenever a measurement is added or removed.
|
|
48
|
+
*/
|
|
49
|
+
onMeasurementsChange?: (event: MeasurementsChangeEvent) => void;
|
|
20
50
|
}
|
|
21
51
|
/**
|
|
22
|
-
* The `Measurement` component can be used in an app to
|
|
52
|
+
* The `Measurement` component can be used in an app to measure geometries (areas or lines) on the map.
|
|
23
53
|
*/
|
|
24
54
|
export declare const Measurement: FC<MeasurementProps>;
|
package/Measurement.js
CHANGED
|
@@ -2,27 +2,19 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { Box, Text, FormControl, HStack, FormLabel, Select, Button } from '@open-pioneer/chakra-integration';
|
|
3
3
|
import { useMapModel } from '@open-pioneer/map';
|
|
4
4
|
import { useCommonComponentProps } from '@open-pioneer/react-utils';
|
|
5
|
-
import { Style, Stroke, Fill, Circle } from 'ol/style';
|
|
5
|
+
import { Style, Stroke, Fill, Circle } from 'ol/style.js';
|
|
6
6
|
import { useIntl } from './_virtual/_virtual-pioneer-module_react-hooks.js';
|
|
7
7
|
import { useState, useEffect } from 'react';
|
|
8
8
|
import { MeasurementController } from './MeasurementController.js';
|
|
9
9
|
|
|
10
10
|
const Measurement = (props) => {
|
|
11
11
|
const intl = useIntl();
|
|
12
|
-
const { mapId
|
|
12
|
+
const { mapId } = props;
|
|
13
13
|
const { containerProps } = useCommonComponentProps("measurement", props);
|
|
14
14
|
const [selectedMeasurement, setMeasurement] = useState("distance");
|
|
15
15
|
const label = (id) => intl.formatMessage({ id });
|
|
16
16
|
const mapState = useMapModel(mapId);
|
|
17
|
-
const controller = useController(mapState.map, intl);
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
controller?.setActiveFeatureStyle(activeFeatureStyle ?? getDefaultActiveFeatureStyle());
|
|
20
|
-
}, [controller, activeFeatureStyle]);
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
controller?.setFinishedFeatureStyle(
|
|
23
|
-
finishedFeatureStyle ?? getDefaultFinishedFeatureStyle()
|
|
24
|
-
);
|
|
25
|
-
}, [controller, finishedFeatureStyle]);
|
|
17
|
+
const controller = useController(mapState.map, props, intl);
|
|
26
18
|
useEffect(() => {
|
|
27
19
|
if (!controller) {
|
|
28
20
|
return;
|
|
@@ -71,7 +63,13 @@ const Measurement = (props) => {
|
|
|
71
63
|
)
|
|
72
64
|
] });
|
|
73
65
|
};
|
|
74
|
-
function useController(map, intl) {
|
|
66
|
+
function useController(map, props, intl) {
|
|
67
|
+
const {
|
|
68
|
+
activeFeatureStyle,
|
|
69
|
+
finishedFeatureStyle,
|
|
70
|
+
onMeasurementsChange,
|
|
71
|
+
predefinedMeasurements
|
|
72
|
+
} = props;
|
|
75
73
|
const [controller, setController] = useState(void 0);
|
|
76
74
|
useEffect(() => {
|
|
77
75
|
if (!map) {
|
|
@@ -96,6 +94,20 @@ function useController(map, intl) {
|
|
|
96
94
|
setController(void 0);
|
|
97
95
|
};
|
|
98
96
|
}, [map, intl]);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
controller?.setActiveFeatureStyle(activeFeatureStyle ?? getDefaultActiveFeatureStyle());
|
|
99
|
+
}, [controller, activeFeatureStyle]);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
controller?.setFinishedFeatureStyle(
|
|
102
|
+
finishedFeatureStyle ?? getDefaultFinishedFeatureStyle()
|
|
103
|
+
);
|
|
104
|
+
}, [controller, finishedFeatureStyle]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
controller?.setMeasurementSourceChangedHandler(onMeasurementsChange);
|
|
107
|
+
}, [controller, onMeasurementsChange]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
controller?.setPredefinedMeasurements(predefinedMeasurements ?? []);
|
|
110
|
+
}, [controller, predefinedMeasurements]);
|
|
99
111
|
return controller;
|
|
100
112
|
}
|
|
101
113
|
function getDefaultActiveFeatureStyle() {
|
package/Measurement.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Measurement.js","sources":["Measurement.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Box,\n Button,\n FormControl,\n FormLabel,\n HStack,\n Select,\n Text\n} from \"@open-pioneer/chakra-integration\";\nimport { MapModel, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { Circle as CircleStyle, Fill, Stroke, Style } from \"ol/style\";\nimport { StyleLike } from \"ol/style/Style\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, useEffect, useState } from \"react\";\nimport { MeasurementController, MeasurementType } from \"./MeasurementController\";\n\n/**\n * This is for special properties of the Measurement.\n */\nexport interface MeasurementProps extends CommonComponentProps {\n /**\n * The id of the map.\n */\n mapId: string;\n\n /**\n * The style for the active drawing feature's geometry.\n */\n activeFeatureStyle?: StyleLike;\n\n /**\n * The style for the finished drawn feature's geometry.\n */\n finishedFeatureStyle?: StyleLike;\n}\n\n/**\n * The `Measurement` component can be used in an app to switch between distance and area measurements and to delete all current measurements.\n */\nexport const Measurement: FC<MeasurementProps> = (props) => {\n const intl = useIntl();\n\n const { mapId, activeFeatureStyle, finishedFeatureStyle } = props;\n const { containerProps } = useCommonComponentProps(\"measurement\", props);\n const [selectedMeasurement, setMeasurement] = useState<MeasurementType>(\"distance\");\n const label = (id: string) => intl.formatMessage({ id: id });\n\n const mapState = useMapModel(mapId);\n const controller = useController(mapState.map, intl);\n\n // Synchronize styles with controller\n useEffect(() => {\n controller?.setActiveFeatureStyle(activeFeatureStyle ?? getDefaultActiveFeatureStyle());\n }, [controller, activeFeatureStyle]);\n useEffect(() => {\n controller?.setFinishedFeatureStyle(\n finishedFeatureStyle ?? getDefaultFinishedFeatureStyle()\n );\n }, [controller, finishedFeatureStyle]);\n\n // Start / Stop measurement on selection change\n useEffect(() => {\n if (!controller) {\n return;\n }\n\n controller.startMeasurement(selectedMeasurement);\n return () => {\n controller.stopMeasurement();\n };\n }, [controller, selectedMeasurement]);\n\n function changeMeasurement(measurementType: string) {\n if (measurementType === \"distance\" || measurementType === \"area\") {\n setMeasurement(measurementType);\n } else {\n throw new Error(`Unexpected measurement type: '${measurementType}'.`);\n }\n }\n\n function removeMeasurements() {\n controller?.clearMeasurements();\n }\n\n return (\n <Box {...containerProps}>\n <Text mb={3}>{intl.formatMessage({ id: \"measurementInfoText\" })}</Text>\n <FormControl mb={4} alignItems=\"center\">\n <HStack mb={2}>\n <FormLabel mb={1}>{label(\"measurementLabel\")}</FormLabel>\n <Select\n value={selectedMeasurement}\n onChange={(e) => changeMeasurement(e.target.value)}\n className=\"measurement-select\"\n >\n <option value={\"distance\"}>{label(\"distance\")}</option>\n <option value={\"area\"}>{label(\"area\")}</option>\n </Select>\n </HStack>\n </FormControl>\n <Button\n padding={2}\n className=\"measurement-delete-button\"\n onClick={removeMeasurements}\n width=\"100%\"\n >\n {label(\"deleteMeasurementLabel\")}\n </Button>\n </Box>\n );\n};\n\n/** Creates a MeasurementController instance for the given map. */\nfunction useController(map: MapModel | undefined, intl: PackageIntl) {\n const [controller, setController] = useState<MeasurementController | undefined>(undefined);\n useEffect(() => {\n if (!map) {\n return;\n }\n\n const controller = new MeasurementController(map.olMap, {\n getContinueMessage() {\n return intl.formatMessage({ id: \"tooltips.continue\" });\n },\n getHelpMessage() {\n return intl.formatMessage({ id: \"tooltips.help\" });\n },\n formatNumber(value) {\n return intl.formatNumber(value, {\n maximumFractionDigits: 2\n });\n }\n });\n setController(controller);\n return () => {\n controller.destroy();\n setController(undefined);\n };\n }, [map, intl]);\n return controller;\n}\n\nfunction getDefaultActiveFeatureStyle() {\n return [\n new Style({\n stroke: new Stroke({\n color: \"#fff\",\n lineDash: [10, 10],\n width: 5\n })\n }),\n new Style({\n fill: new Fill({\n color: \"rgba(0,0,0,0.15)\"\n }),\n stroke: new Stroke({\n color: \"rgba(0, 0, 0, 0.7)\",\n lineDash: [10, 10],\n width: 3\n }),\n image: new CircleStyle({\n radius: 5,\n stroke: new Stroke({\n color: \"rgba(0, 0, 0, 0.7)\",\n width: 2\n }),\n fill: new Fill({\n color: \"rgba(255, 255, 255, 0.2)\"\n })\n })\n })\n ];\n}\n\nfunction getDefaultFinishedFeatureStyle() {\n return [\n new Style({\n stroke: new Stroke({\n color: \"#fff\",\n width: 5\n })\n }),\n new Style({\n stroke: new Stroke({\n color: \"#0b96fc\",\n width: 3\n }),\n fill: new Fill({\n color: \"rgba(11,150,252,0.15)\"\n })\n })\n ];\n}\n"],"names":["controller","CircleStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Measurement.js","sources":["Measurement.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport {\n Box,\n Button,\n FormControl,\n FormLabel,\n HStack,\n Select,\n Text\n} from \"@open-pioneer/chakra-integration\";\nimport { MapModel, useMapModel } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { Circle as CircleStyle, Fill, Stroke, Style } from \"ol/style\";\nimport { StyleLike } from \"ol/style/Style\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, useEffect, useState } from \"react\";\nimport { MeasurementController, MeasurementType } from \"./MeasurementController\";\nimport LineString from \"ol/geom/LineString\";\nimport Polygon from \"ol/geom/Polygon\";\n\n/** Emitted when a new measurement is being added to the map. */\nexport interface MeasurementsAddEvent {\n kind: \"add-measurement\";\n geometry: MeasurementGeometry;\n}\n\n/** Emitted when a measurement is being removed from the map. */\nexport interface MeasurementsRemoveEvent {\n kind: \"remove-measurement\";\n geometry: MeasurementGeometry;\n}\n\n/**\n * A change event emitted by {@link Measurement} when measurements change.\n *\n * NOTE: Non-exhaustive. More event types may be added in a future version.\n **/\nexport type MeasurementsChangeEvent = MeasurementsAddEvent | MeasurementsRemoveEvent;\n\n/**\n * Represents the geometry of a measurement.\n */\nexport type MeasurementGeometry = LineString | Polygon;\n\n/**\n * This is for special properties of the Measurement.\n */\nexport interface MeasurementProps extends CommonComponentProps {\n /**\n * The id of the map.\n */\n mapId: string;\n\n /**\n * The style for the active drawing feature's geometry.\n */\n activeFeatureStyle?: StyleLike;\n\n /**\n * The style for the finished drawn feature's geometry.\n */\n finishedFeatureStyle?: StyleLike;\n\n /**\n * List of measurements to be rendered when the component is initialized.\n */\n predefinedMeasurements?: MeasurementGeometry[];\n\n /**\n * Event handler that is called whenever a measurement is added or removed.\n */\n onMeasurementsChange?: (event: MeasurementsChangeEvent) => void;\n}\n\n/**\n * The `Measurement` component can be used in an app to measure geometries (areas or lines) on the map.\n */\nexport const Measurement: FC<MeasurementProps> = (props) => {\n const intl = useIntl();\n const { mapId } = props;\n const { containerProps } = useCommonComponentProps(\"measurement\", props);\n const [selectedMeasurement, setMeasurement] = useState<MeasurementType>(\"distance\");\n const label = (id: string) => intl.formatMessage({ id: id });\n const mapState = useMapModel(mapId);\n const controller = useController(mapState.map, props, intl);\n\n // Start / Stop measurement on selection change\n useEffect(() => {\n if (!controller) {\n return;\n }\n\n controller.startMeasurement(selectedMeasurement);\n return () => {\n controller.stopMeasurement();\n };\n }, [controller, selectedMeasurement]);\n\n function changeMeasurement(measurementType: string) {\n if (measurementType === \"distance\" || measurementType === \"area\") {\n setMeasurement(measurementType);\n } else {\n throw new Error(`Unexpected measurement type: '${measurementType}'.`);\n }\n }\n\n function removeMeasurements() {\n controller?.clearMeasurements();\n }\n\n return (\n <Box {...containerProps}>\n <Text mb={3}>{intl.formatMessage({ id: \"measurementInfoText\" })}</Text>\n <FormControl mb={4} alignItems=\"center\">\n <HStack mb={2}>\n <FormLabel mb={1}>{label(\"measurementLabel\")}</FormLabel>\n <Select\n value={selectedMeasurement}\n onChange={(e) => changeMeasurement(e.target.value)}\n className=\"measurement-select\"\n >\n <option value={\"distance\"}>{label(\"distance\")}</option>\n <option value={\"area\"}>{label(\"area\")}</option>\n </Select>\n </HStack>\n </FormControl>\n <Button\n padding={2}\n className=\"measurement-delete-button\"\n onClick={removeMeasurements}\n width=\"100%\"\n >\n {label(\"deleteMeasurementLabel\")}\n </Button>\n </Box>\n );\n};\n\n/** Creates a MeasurementController instance for the given map. */\nfunction useController(map: MapModel | undefined, props: MeasurementProps, intl: PackageIntl) {\n const {\n activeFeatureStyle,\n finishedFeatureStyle,\n onMeasurementsChange,\n predefinedMeasurements\n } = props;\n const [controller, setController] = useState<MeasurementController | undefined>(undefined);\n useEffect(() => {\n if (!map) {\n return;\n }\n const controller = new MeasurementController(map.olMap, {\n getContinueMessage() {\n return intl.formatMessage({ id: \"tooltips.continue\" });\n },\n getHelpMessage() {\n return intl.formatMessage({ id: \"tooltips.help\" });\n },\n formatNumber(value) {\n return intl.formatNumber(value, {\n maximumFractionDigits: 2\n });\n }\n });\n\n setController(controller);\n return () => {\n controller.destroy();\n setController(undefined);\n };\n }, [map, intl]);\n\n // Synchronize styles with controller\n useEffect(() => {\n controller?.setActiveFeatureStyle(activeFeatureStyle ?? getDefaultActiveFeatureStyle());\n }, [controller, activeFeatureStyle]);\n useEffect(() => {\n controller?.setFinishedFeatureStyle(\n finishedFeatureStyle ?? getDefaultFinishedFeatureStyle()\n );\n }, [controller, finishedFeatureStyle]);\n useEffect(() => {\n controller?.setMeasurementSourceChangedHandler(onMeasurementsChange);\n }, [controller, onMeasurementsChange]);\n\n useEffect(() => {\n controller?.setPredefinedMeasurements(predefinedMeasurements ?? []);\n }, [controller, predefinedMeasurements]);\n return controller;\n}\n\nfunction getDefaultActiveFeatureStyle() {\n return [\n new Style({\n stroke: new Stroke({\n color: \"#fff\",\n lineDash: [10, 10],\n width: 5\n })\n }),\n new Style({\n fill: new Fill({\n color: \"rgba(0,0,0,0.15)\"\n }),\n stroke: new Stroke({\n color: \"rgba(0, 0, 0, 0.7)\",\n lineDash: [10, 10],\n width: 3\n }),\n image: new CircleStyle({\n radius: 5,\n stroke: new Stroke({\n color: \"rgba(0, 0, 0, 0.7)\",\n width: 2\n }),\n fill: new Fill({\n color: \"rgba(255, 255, 255, 0.2)\"\n })\n })\n })\n ];\n}\n\nfunction getDefaultFinishedFeatureStyle() {\n return [\n new Style({\n stroke: new Stroke({\n color: \"#fff\",\n width: 5\n })\n }),\n new Style({\n stroke: new Stroke({\n color: \"#0b96fc\",\n width: 3\n }),\n fill: new Fill({\n color: \"rgba(11,150,252,0.15)\"\n })\n })\n ];\n}\n"],"names":["controller","CircleStyle"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Feature from "ol/Feature";
|
|
2
2
|
import OlMap from "ol/Map";
|
|
3
3
|
import { Vector as VectorLayer } from "ol/layer";
|
|
4
|
-
import { Vector as VectorSource } from "ol/source";
|
|
5
4
|
import { StyleLike } from "ol/style/Style";
|
|
5
|
+
import type { MeasurementGeometry, MeasurementProps } from "./Measurement";
|
|
6
|
+
type MeasurementsChangeHandler = NonNullable<MeasurementProps["onMeasurementsChange"]>;
|
|
6
7
|
export type MeasurementType = "area" | "distance";
|
|
7
8
|
export interface Messages {
|
|
8
9
|
getContinueMessage(): string;
|
|
@@ -10,8 +11,8 @@ export interface Messages {
|
|
|
10
11
|
formatNumber(value: number): string;
|
|
11
12
|
}
|
|
12
13
|
export declare class MeasurementController {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
readonly olMap: OlMap;
|
|
15
|
+
readonly messages: Messages;
|
|
15
16
|
private activeFeatureStyle;
|
|
16
17
|
/**
|
|
17
18
|
* The layer rendering the measurement "features".
|
|
@@ -26,31 +27,40 @@ export declare class MeasurementController {
|
|
|
26
27
|
*/
|
|
27
28
|
private draw;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* The active measurement manipulated by the `draw` interaction.
|
|
30
31
|
*/
|
|
31
|
-
private
|
|
32
|
+
private activeMeasurement;
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
+
* Map that is used to track all predefined measurements currently added to the source.
|
|
35
|
+
* It associates the measurement geometry (key) with the corresponding measurement instance.
|
|
36
|
+
*
|
|
37
|
+
* The measurement instances here must also be contained in `finishedMeasurements`.
|
|
34
38
|
*/
|
|
35
|
-
private
|
|
39
|
+
private predefinedMeasurements;
|
|
36
40
|
/**
|
|
37
|
-
*
|
|
41
|
+
* Measurement instances that were finished.
|
|
38
42
|
*/
|
|
39
|
-
private
|
|
43
|
+
private finishedMeasurements;
|
|
40
44
|
/**
|
|
41
|
-
*
|
|
45
|
+
* The help tooltip element.
|
|
42
46
|
*/
|
|
43
|
-
private
|
|
47
|
+
private helpTooltip;
|
|
44
48
|
/**
|
|
45
49
|
* Keeps track of registered event handlers.
|
|
46
50
|
*/
|
|
47
51
|
private resources;
|
|
52
|
+
/**
|
|
53
|
+
* Called when a measurement is added to or removed from the source.
|
|
54
|
+
*/
|
|
55
|
+
private measurementChangedHandler;
|
|
48
56
|
constructor(olMap: OlMap, messages: Messages);
|
|
49
57
|
destroy(): void;
|
|
50
58
|
/** Returns the vector layer used for finished features. */
|
|
51
|
-
getVectorLayer(): VectorLayer<
|
|
59
|
+
getVectorLayer(): VectorLayer<Feature<import("ol/geom").Geometry>>;
|
|
52
60
|
/** Updates the style used for finished features. */
|
|
53
61
|
setFinishedFeatureStyle(style: StyleLike): void;
|
|
62
|
+
setMeasurementSourceChangedHandler(handler: MeasurementsChangeHandler | undefined): void;
|
|
63
|
+
setPredefinedMeasurements(geometries: MeasurementGeometry[]): void;
|
|
54
64
|
/** Updates the style used for active measurements. */
|
|
55
65
|
setActiveFeatureStyle(style: StyleLike): void;
|
|
56
66
|
/** Removes all finished measurements. */
|
|
@@ -59,7 +69,8 @@ export declare class MeasurementController {
|
|
|
59
69
|
startMeasurement(type: MeasurementType): void;
|
|
60
70
|
/** Stops the current measuring started by `startMeasurement`. */
|
|
61
71
|
stopMeasurement(): void;
|
|
62
|
-
private createMeasureTooltip;
|
|
63
|
-
private createHelpTooltip;
|
|
64
72
|
private handlePointerMove;
|
|
73
|
+
private updatePredefinedMeasurements;
|
|
74
|
+
private raiseMeasurementsChangeEvent;
|
|
65
75
|
}
|
|
76
|
+
export {};
|
package/MeasurementController.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Overlay from 'ol/Overlay';
|
|
3
|
-
import { Polygon, LineString } from 'ol/geom';
|
|
4
|
-
import Draw from 'ol/interaction/Draw';
|
|
5
|
-
import { Vector as Vector$1 } from 'ol/layer';
|
|
6
|
-
import { Vector } from 'ol/source';
|
|
7
|
-
import { getArea, getLength } from 'ol/sphere';
|
|
8
|
-
import { toFunction } from 'ol/style/Style';
|
|
1
|
+
import { destroyResource } from '@open-pioneer/core';
|
|
9
2
|
import { TOPMOST_LAYER_Z } from '@open-pioneer/map';
|
|
3
|
+
import Feature from 'ol/Feature.js';
|
|
4
|
+
import { unByKey } from 'ol/Observable.js';
|
|
5
|
+
import Overlay from 'ol/Overlay.js';
|
|
6
|
+
import { Polygon, LineString } from 'ol/geom.js';
|
|
7
|
+
import Draw from 'ol/interaction/Draw.js';
|
|
8
|
+
import { Vector as Vector$1 } from 'ol/layer.js';
|
|
9
|
+
import { Vector } from 'ol/source.js';
|
|
10
|
+
import { getArea, getLength } from 'ol/sphere.js';
|
|
11
|
+
import { toFunction } from 'ol/style/Style.js';
|
|
10
12
|
|
|
11
13
|
class MeasurementController {
|
|
12
14
|
olMap;
|
|
@@ -25,33 +27,43 @@ class MeasurementController {
|
|
|
25
27
|
*/
|
|
26
28
|
draw = void 0;
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
30
|
+
* The active measurement manipulated by the `draw` interaction.
|
|
29
31
|
*/
|
|
30
|
-
|
|
32
|
+
activeMeasurement;
|
|
31
33
|
/**
|
|
32
|
-
*
|
|
34
|
+
* Map that is used to track all predefined measurements currently added to the source.
|
|
35
|
+
* It associates the measurement geometry (key) with the corresponding measurement instance.
|
|
36
|
+
*
|
|
37
|
+
* The measurement instances here must also be contained in `finishedMeasurements`.
|
|
33
38
|
*/
|
|
34
|
-
|
|
39
|
+
predefinedMeasurements = /* @__PURE__ */ new Map();
|
|
35
40
|
/**
|
|
36
|
-
*
|
|
41
|
+
* Measurement instances that were finished.
|
|
37
42
|
*/
|
|
38
|
-
|
|
43
|
+
finishedMeasurements = /* @__PURE__ */ new Set();
|
|
39
44
|
/**
|
|
40
|
-
*
|
|
45
|
+
* The help tooltip element.
|
|
41
46
|
*/
|
|
42
|
-
|
|
47
|
+
helpTooltip;
|
|
43
48
|
/**
|
|
44
49
|
* Keeps track of registered event handlers.
|
|
45
50
|
*/
|
|
46
51
|
resources = [];
|
|
52
|
+
/**
|
|
53
|
+
* Called when a measurement is added to or removed from the source.
|
|
54
|
+
*/
|
|
55
|
+
measurementChangedHandler;
|
|
47
56
|
constructor(olMap, messages) {
|
|
48
57
|
this.olMap = olMap;
|
|
49
58
|
this.messages = messages;
|
|
50
59
|
const source = this.source = new Vector();
|
|
51
60
|
this.layer = new Vector$1({
|
|
52
|
-
source
|
|
61
|
+
source,
|
|
62
|
+
zIndex: TOPMOST_LAYER_Z,
|
|
63
|
+
properties: {
|
|
64
|
+
name: "measurement-layer"
|
|
65
|
+
}
|
|
53
66
|
});
|
|
54
|
-
this.layer.setZIndex(TOPMOST_LAYER_Z);
|
|
55
67
|
olMap.addLayer(this.layer);
|
|
56
68
|
const pointerMoveKey = olMap.on("pointermove", this.handlePointerMove.bind(this));
|
|
57
69
|
this.resources.push({
|
|
@@ -68,7 +80,7 @@ class MeasurementController {
|
|
|
68
80
|
olMap.getViewport().removeEventListener("mouseout", mouseOutHandler);
|
|
69
81
|
}
|
|
70
82
|
});
|
|
71
|
-
this.helpTooltip = this.
|
|
83
|
+
this.helpTooltip = createHelpTooltip(this.olMap);
|
|
72
84
|
}
|
|
73
85
|
destroy() {
|
|
74
86
|
this.stopMeasurement();
|
|
@@ -76,15 +88,17 @@ class MeasurementController {
|
|
|
76
88
|
resource.destroy();
|
|
77
89
|
}
|
|
78
90
|
this.resources = [];
|
|
79
|
-
this.
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
tooltip.destroy();
|
|
91
|
+
this.activeMeasurement = destroyResource(this.activeMeasurement);
|
|
92
|
+
for (const measurement of this.finishedMeasurements) {
|
|
93
|
+
measurement.destroy();
|
|
83
94
|
}
|
|
84
|
-
this.
|
|
95
|
+
this.finishedMeasurements.clear();
|
|
96
|
+
this.helpTooltip.destroy();
|
|
85
97
|
this.olMap.removeLayer(this.layer);
|
|
86
98
|
this.layer.dispose();
|
|
87
99
|
this.source.dispose();
|
|
100
|
+
this.measurementChangedHandler = void 0;
|
|
101
|
+
this.predefinedMeasurements.clear();
|
|
88
102
|
}
|
|
89
103
|
/** Returns the vector layer used for finished features. */
|
|
90
104
|
getVectorLayer() {
|
|
@@ -94,6 +108,12 @@ class MeasurementController {
|
|
|
94
108
|
setFinishedFeatureStyle(style) {
|
|
95
109
|
this.layer.setStyle(style);
|
|
96
110
|
}
|
|
111
|
+
setMeasurementSourceChangedHandler(handler) {
|
|
112
|
+
this.measurementChangedHandler = handler;
|
|
113
|
+
}
|
|
114
|
+
setPredefinedMeasurements(geometries) {
|
|
115
|
+
this.updatePredefinedMeasurements(geometries);
|
|
116
|
+
}
|
|
97
117
|
/** Updates the style used for active measurements. */
|
|
98
118
|
setActiveFeatureStyle(style) {
|
|
99
119
|
const styleFunction = toFunction(style);
|
|
@@ -107,11 +127,16 @@ class MeasurementController {
|
|
|
107
127
|
}
|
|
108
128
|
/** Removes all finished measurements. */
|
|
109
129
|
clearMeasurements() {
|
|
130
|
+
const currentFeatures = this.source.getFeatures();
|
|
110
131
|
this.source.clear();
|
|
111
|
-
|
|
112
|
-
|
|
132
|
+
currentFeatures.forEach((feature) => {
|
|
133
|
+
this.raiseMeasurementsChangeEvent("remove-measurement", feature);
|
|
134
|
+
});
|
|
135
|
+
this.predefinedMeasurements.clear();
|
|
136
|
+
for (const measurement of this.finishedMeasurements) {
|
|
137
|
+
measurement.destroy();
|
|
113
138
|
}
|
|
114
|
-
this.
|
|
139
|
+
this.finishedMeasurements.clear();
|
|
115
140
|
}
|
|
116
141
|
/** Starts measuring using the provided type. */
|
|
117
142
|
startMeasurement(type) {
|
|
@@ -125,55 +150,40 @@ class MeasurementController {
|
|
|
125
150
|
style: this.activeFeatureStyle
|
|
126
151
|
});
|
|
127
152
|
this.olMap.addInteraction(draw);
|
|
128
|
-
let
|
|
153
|
+
let measurement;
|
|
129
154
|
let changeListenerKey = void 0;
|
|
130
155
|
draw.on("drawstart", (evt) => {
|
|
131
|
-
|
|
132
|
-
const sketch = this.sketch = evt.feature;
|
|
156
|
+
const sketch = evt.feature;
|
|
133
157
|
if (!sketch) {
|
|
134
158
|
return;
|
|
135
159
|
}
|
|
136
|
-
|
|
137
|
-
changeListenerKey = sketch.getGeometry()?.on("change", (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
let output = "";
|
|
141
|
-
if (geom instanceof Polygon) {
|
|
142
|
-
output = formatArea(geom, projection, this.messages);
|
|
143
|
-
tooltipCoord = geom.getInteriorPoint().getCoordinates() || null;
|
|
144
|
-
} else if (geom instanceof LineString) {
|
|
145
|
-
output = formatLength(geom, projection, this.messages);
|
|
146
|
-
tooltipCoord = geom.getLastCoordinate() || null;
|
|
147
|
-
}
|
|
148
|
-
if (measureTooltip) {
|
|
149
|
-
measureTooltip.element.innerHTML = output;
|
|
150
|
-
if (tooltipCoord) {
|
|
151
|
-
measureTooltip?.overlay.setPosition(tooltipCoord);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
160
|
+
measurement = this.activeMeasurement = new MeasurementInstance("active", sketch, this);
|
|
161
|
+
changeListenerKey = sketch.getGeometry()?.on("change", () => {
|
|
162
|
+
measurement?.updateTooltipContent();
|
|
163
|
+
measurement?.updateTooltipPosition();
|
|
154
164
|
});
|
|
155
165
|
});
|
|
156
166
|
draw.on("drawend", () => {
|
|
157
|
-
if (
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
this.overlayTooltips.push(measureTooltip);
|
|
164
|
-
this.measureTooltip = measureTooltip = void 0;
|
|
167
|
+
if (measurement && measurement === this.activeMeasurement) {
|
|
168
|
+
const newMeasurement = measurement;
|
|
169
|
+
newMeasurement.updateState("finished");
|
|
170
|
+
this.finishedMeasurements.add(newMeasurement);
|
|
171
|
+
this.raiseMeasurementsChangeEvent("add-measurement", newMeasurement.feature);
|
|
172
|
+
this.activeMeasurement = measurement = void 0;
|
|
165
173
|
}
|
|
166
|
-
|
|
174
|
+
measurement = void 0;
|
|
167
175
|
if (changeListenerKey) {
|
|
168
176
|
unByKey(changeListenerKey);
|
|
169
177
|
}
|
|
170
178
|
});
|
|
171
179
|
draw.on("drawabort", () => {
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
180
|
+
if (measurement) {
|
|
181
|
+
measurement.destroy();
|
|
182
|
+
if (measurement === this.activeMeasurement) {
|
|
183
|
+
this.activeMeasurement = void 0;
|
|
184
|
+
}
|
|
185
|
+
measurement = void 0;
|
|
175
186
|
}
|
|
176
|
-
this.sketch = void 0;
|
|
177
187
|
if (changeListenerKey) {
|
|
178
188
|
unByKey(changeListenerKey);
|
|
179
189
|
}
|
|
@@ -187,62 +197,192 @@ class MeasurementController {
|
|
|
187
197
|
this.draw.dispose();
|
|
188
198
|
this.draw = void 0;
|
|
189
199
|
}
|
|
190
|
-
this.
|
|
191
|
-
this.measureTooltip?.destroy();
|
|
192
|
-
this.measureTooltip = void 0;
|
|
193
|
-
}
|
|
194
|
-
createMeasureTooltip() {
|
|
195
|
-
const element = document.createElement("div");
|
|
196
|
-
element.className = "measurement-tooltip measurement-active-tooltip printing-hide";
|
|
197
|
-
const overlay = new Overlay({
|
|
198
|
-
element,
|
|
199
|
-
offset: [0, -15],
|
|
200
|
-
positioning: "bottom-center",
|
|
201
|
-
stopEvent: false,
|
|
202
|
-
insertFirst: false
|
|
203
|
-
});
|
|
204
|
-
const olMap = this.olMap;
|
|
205
|
-
olMap.addOverlay(overlay);
|
|
206
|
-
return {
|
|
207
|
-
overlay,
|
|
208
|
-
element,
|
|
209
|
-
destroy() {
|
|
210
|
-
olMap.removeOverlay(overlay);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
createHelpTooltip() {
|
|
215
|
-
const element = document.createElement("div");
|
|
216
|
-
element.className = "measurement-tooltip printing-hide hidden";
|
|
217
|
-
const overlay = new Overlay({
|
|
218
|
-
element,
|
|
219
|
-
offset: [15, 0],
|
|
220
|
-
positioning: "center-left"
|
|
221
|
-
});
|
|
222
|
-
const olMap = this.olMap;
|
|
223
|
-
olMap.addOverlay(overlay);
|
|
224
|
-
return {
|
|
225
|
-
overlay,
|
|
226
|
-
element,
|
|
227
|
-
destroy() {
|
|
228
|
-
olMap.removeOverlay(overlay);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
200
|
+
this.activeMeasurement = destroyResource(this.activeMeasurement);
|
|
231
201
|
}
|
|
232
202
|
handlePointerMove(evt) {
|
|
233
203
|
if (evt.dragging) {
|
|
234
204
|
return;
|
|
235
205
|
}
|
|
236
206
|
const tooltip = this.helpTooltip;
|
|
237
|
-
const helpMessage = getHelpMessage(this.messages, this.
|
|
238
|
-
tooltip.
|
|
207
|
+
const helpMessage = getHelpMessage(this.messages, this.activeMeasurement);
|
|
208
|
+
tooltip.setText(helpMessage);
|
|
239
209
|
tooltip.overlay.setPosition(evt.coordinate);
|
|
240
210
|
tooltip.element.classList.remove("hidden");
|
|
241
211
|
}
|
|
212
|
+
updatePredefinedMeasurements(geometries) {
|
|
213
|
+
const addedMeasurements = geometries.filter(
|
|
214
|
+
(geom) => !this.predefinedMeasurements.has(geom)
|
|
215
|
+
);
|
|
216
|
+
const removedMeasurements = [];
|
|
217
|
+
for (const geom of this.predefinedMeasurements.keys()) {
|
|
218
|
+
if (!geometries.includes(geom)) {
|
|
219
|
+
removedMeasurements.push(geom);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
addedMeasurements.forEach((geom) => {
|
|
223
|
+
const measurementFeature = new Feature(geom);
|
|
224
|
+
this.source.addFeature(measurementFeature);
|
|
225
|
+
const measurement = new MeasurementInstance("finished", measurementFeature, this);
|
|
226
|
+
this.finishedMeasurements.add(measurement);
|
|
227
|
+
this.predefinedMeasurements.set(geom, measurement);
|
|
228
|
+
this.raiseMeasurementsChangeEvent("add-measurement", measurementFeature);
|
|
229
|
+
});
|
|
230
|
+
removedMeasurements.forEach((geom) => {
|
|
231
|
+
const measurement = this.predefinedMeasurements.get(geom);
|
|
232
|
+
if (measurement) {
|
|
233
|
+
this.source.removeFeature(measurement.feature);
|
|
234
|
+
this.finishedMeasurements.delete(measurement);
|
|
235
|
+
measurement.destroy();
|
|
236
|
+
this.raiseMeasurementsChangeEvent("remove-measurement", measurement.feature);
|
|
237
|
+
}
|
|
238
|
+
this.predefinedMeasurements.delete(geom);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
raiseMeasurementsChangeEvent(kind, measurementFeature) {
|
|
242
|
+
const measurementGeom = measurementFeature.getGeometry();
|
|
243
|
+
if (this.measurementChangedHandler && measurementGeom) {
|
|
244
|
+
this.measurementChangedHandler({
|
|
245
|
+
kind,
|
|
246
|
+
geometry: measurementGeom instanceof Polygon ? measurementGeom : measurementGeom
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
class MeasurementInstance {
|
|
252
|
+
controller;
|
|
253
|
+
feature;
|
|
254
|
+
_state;
|
|
255
|
+
tooltip;
|
|
256
|
+
constructor(state, feature, controller) {
|
|
257
|
+
this.controller = controller;
|
|
258
|
+
this._state = state;
|
|
259
|
+
this.feature = feature;
|
|
260
|
+
this.tooltip = createMeasureTooltip(this.olMap);
|
|
261
|
+
this.updateTooltipContent();
|
|
262
|
+
this.updateTooltipPosition();
|
|
263
|
+
this.tooltip.setActive(state === "active");
|
|
264
|
+
}
|
|
265
|
+
destroy() {
|
|
266
|
+
this.tooltip.destroy();
|
|
267
|
+
}
|
|
268
|
+
get state() {
|
|
269
|
+
return this._state;
|
|
270
|
+
}
|
|
271
|
+
updateState(state) {
|
|
272
|
+
if (this._state === state) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
this._state = state;
|
|
276
|
+
this.tooltip.setActive(state === "active");
|
|
277
|
+
}
|
|
278
|
+
// Updates the tooltip content based on the current state and the feature's geometry.
|
|
279
|
+
updateTooltipContent() {
|
|
280
|
+
const geometry = this.feature.getGeometry();
|
|
281
|
+
if (!geometry) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const projection = this.olMap.getView().getProjection();
|
|
285
|
+
let outputHtml;
|
|
286
|
+
if (geometry instanceof Polygon) {
|
|
287
|
+
outputHtml = formatArea(geometry, projection, this.messages);
|
|
288
|
+
} else if (geometry instanceof LineString) {
|
|
289
|
+
outputHtml = formatLength(geometry, projection, this.messages);
|
|
290
|
+
}
|
|
291
|
+
if (outputHtml) {
|
|
292
|
+
this.tooltip.setHtml(outputHtml);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Updates the tooltip's position.
|
|
296
|
+
updateTooltipPosition() {
|
|
297
|
+
const geometry = this.feature.getGeometry();
|
|
298
|
+
if (!geometry) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
let tooltipCoord;
|
|
302
|
+
if (geometry instanceof Polygon) {
|
|
303
|
+
tooltipCoord = geometry.getInteriorPoint().getCoordinates() || null;
|
|
304
|
+
} else if (geometry instanceof LineString) {
|
|
305
|
+
tooltipCoord = geometry.getLastCoordinate() || null;
|
|
306
|
+
} else {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
this.tooltip.overlay.setPosition(tooltipCoord);
|
|
310
|
+
}
|
|
311
|
+
get olMap() {
|
|
312
|
+
return this.controller.olMap;
|
|
313
|
+
}
|
|
314
|
+
get messages() {
|
|
315
|
+
return this.controller.messages;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const DEFAULT_MEASUREMENT_OFFSET = [0, -15];
|
|
319
|
+
const FINISHED_MEASUREMENT_OFFSET = [0, -7];
|
|
320
|
+
function createHelpTooltip(olMap) {
|
|
321
|
+
const element = document.createElement("div");
|
|
322
|
+
element.className = "measurement-tooltip printing-hide hidden";
|
|
323
|
+
element.role = "tooltip";
|
|
324
|
+
const content = document.createElement("span");
|
|
325
|
+
element.appendChild(content);
|
|
326
|
+
const overlay = new Overlay({
|
|
327
|
+
element,
|
|
328
|
+
offset: [15, 0],
|
|
329
|
+
positioning: "center-left"
|
|
330
|
+
});
|
|
331
|
+
olMap.addOverlay(overlay);
|
|
332
|
+
return {
|
|
333
|
+
overlay,
|
|
334
|
+
element,
|
|
335
|
+
destroy() {
|
|
336
|
+
olMap.removeOverlay(overlay);
|
|
337
|
+
},
|
|
338
|
+
setText(value) {
|
|
339
|
+
content.textContent = value;
|
|
340
|
+
},
|
|
341
|
+
setHtml(value) {
|
|
342
|
+
content.innerHTML = value;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function createMeasureTooltip(olMap) {
|
|
347
|
+
const element = document.createElement("div");
|
|
348
|
+
element.role = "tooltip";
|
|
349
|
+
element.className = "measurement-tooltip measurement-active-tooltip printing-hide";
|
|
350
|
+
const content = document.createElement("span");
|
|
351
|
+
element.appendChild(content);
|
|
352
|
+
const overlay = new Overlay({
|
|
353
|
+
element,
|
|
354
|
+
offset: DEFAULT_MEASUREMENT_OFFSET,
|
|
355
|
+
positioning: "bottom-center",
|
|
356
|
+
stopEvent: false,
|
|
357
|
+
insertFirst: false
|
|
358
|
+
});
|
|
359
|
+
olMap.addOverlay(overlay);
|
|
360
|
+
return {
|
|
361
|
+
overlay,
|
|
362
|
+
element,
|
|
363
|
+
destroy() {
|
|
364
|
+
olMap.removeOverlay(overlay);
|
|
365
|
+
},
|
|
366
|
+
setActive(active) {
|
|
367
|
+
if (active) {
|
|
368
|
+
element.className = "measurement-tooltip measurement-active-tooltip printing-hide";
|
|
369
|
+
overlay.setOffset(DEFAULT_MEASUREMENT_OFFSET);
|
|
370
|
+
} else {
|
|
371
|
+
element.className = "measurement-tooltip measurement-finished-tooltip";
|
|
372
|
+
overlay.setOffset(FINISHED_MEASUREMENT_OFFSET);
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
setText(value) {
|
|
376
|
+
content.textContent = value;
|
|
377
|
+
},
|
|
378
|
+
setHtml(value) {
|
|
379
|
+
content.innerHTML = value;
|
|
380
|
+
}
|
|
381
|
+
};
|
|
242
382
|
}
|
|
243
|
-
function getHelpMessage(messages,
|
|
244
|
-
if (
|
|
245
|
-
const geom =
|
|
383
|
+
function getHelpMessage(messages, activeMeasurement) {
|
|
384
|
+
if (activeMeasurement) {
|
|
385
|
+
const geom = activeMeasurement.feature.getGeometry();
|
|
246
386
|
if (geom instanceof Polygon || geom instanceof LineString) {
|
|
247
387
|
return messages.getContinueMessage();
|
|
248
388
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeasurementController.js","sources":["MeasurementController.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Resource } from \"@open-pioneer/core\";\nimport Feature from \"ol/Feature\";\nimport OlMap from \"ol/Map\";\nimport MapBrowserEvent from \"ol/MapBrowserEvent\";\nimport { unByKey } from \"ol/Observable\";\nimport Overlay from \"ol/Overlay\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { LineString, Polygon } from \"ol/geom\";\nimport Draw from \"ol/interaction/Draw\";\nimport { Vector as VectorLayer } from \"ol/layer\";\nimport { Vector as VectorSource } from \"ol/source\";\nimport { getArea, getLength } from \"ol/sphere\";\nimport { Projection } from \"ol/proj\";\nimport { StyleFunction, StyleLike, toFunction as toStyleFunction } from \"ol/style/Style\";\nimport { TOPMOST_LAYER_Z } from \"@open-pioneer/map\";\n\nexport type MeasurementType = \"area\" | \"distance\";\n\nexport interface Messages {\n getContinueMessage(): string;\n getHelpMessage(): string;\n formatNumber(value: number): string;\n}\n\nexport class MeasurementController {\n private olMap: OlMap;\n private messages: Messages;\n private activeFeatureStyle: StyleFunction | undefined;\n\n /**\n * The layer rendering the measurement \"features\".\n */\n private layer: VectorLayer<VectorSource>;\n\n /**\n * Source of {@link layer}.\n */\n private source: VectorSource;\n\n /**\n * Stores the current `Draw` interaction.\n */\n private draw: Draw | undefined = undefined;\n\n /**\n * Currently drawn feature.\n */\n private sketch: Feature | undefined = undefined;\n\n /**\n * The help tooltip element.\n */\n private helpTooltip: Tooltip;\n\n /**\n * The current measurement tooltip (if any).\n */\n private measureTooltip: Tooltip | undefined;\n\n /**\n * Overlays/Tooltip containing the tooltip for finished drawings.\n */\n private overlayTooltips: Tooltip[] = [];\n\n /**\n * Keeps track of registered event handlers.\n */\n private resources: Resource[] = [];\n\n constructor(olMap: OlMap, messages: Messages) {\n this.olMap = olMap;\n this.messages = messages;\n const source = (this.source = new VectorSource());\n this.layer = new VectorLayer({\n source\n });\n this.layer.setZIndex(TOPMOST_LAYER_Z);\n olMap.addLayer(this.layer);\n\n const pointerMoveKey = olMap.on(\"pointermove\", this.handlePointerMove.bind(this));\n this.resources.push({\n destroy() {\n unByKey(pointerMoveKey);\n }\n });\n\n const mouseOutHandler = () => {\n this.helpTooltip.element.classList.add(\"hidden\");\n };\n olMap.getViewport().addEventListener(\"mouseout\", mouseOutHandler);\n this.resources.push({\n destroy() {\n olMap.getViewport().removeEventListener(\"mouseout\", mouseOutHandler);\n }\n });\n\n this.helpTooltip = this.createHelpTooltip();\n }\n\n destroy() {\n this.stopMeasurement();\n\n // Cleanup registered event handlers etc.\n for (const resource of this.resources) {\n resource.destroy();\n }\n this.resources = [];\n\n // Cleanup tooltips\n this.helpTooltip.destroy();\n this.measureTooltip?.destroy();\n for (const tooltip of this.overlayTooltips) {\n tooltip.destroy();\n }\n this.overlayTooltips = [];\n\n // Cleanup layer\n this.olMap.removeLayer(this.layer);\n this.layer.dispose();\n this.source.dispose();\n }\n\n /** Returns the vector layer used for finished features. */\n getVectorLayer() {\n return this.layer;\n }\n\n /** Updates the style used for finished features. */\n setFinishedFeatureStyle(style: StyleLike) {\n this.layer.setStyle(style);\n }\n\n /** Updates the style used for active measurements. */\n setActiveFeatureStyle(style: StyleLike) {\n const styleFunction = toStyleFunction(style);\n this.activeFeatureStyle = (feature, ...args) => {\n const ft = feature?.getGeometry()?.getType();\n if (ft === \"Polygon\" || ft === \"LineString\" || ft === \"Point\") {\n return styleFunction(feature, ...args);\n }\n };\n // Update style on current draw instance (if any)\n this.draw?.getOverlay().setStyle(this.activeFeatureStyle);\n }\n\n /** Removes all finished measurements. */\n clearMeasurements() {\n this.source.clear();\n for (const tooltip of this.overlayTooltips) {\n tooltip.destroy();\n }\n this.overlayTooltips = [];\n }\n\n /** Starts measuring using the provided type. */\n startMeasurement(type: MeasurementType) {\n if (this.draw) {\n throw new Error(\"Internal error: another measurement interaction is still active.\");\n }\n\n const geometryType = type === \"area\" ? \"Polygon\" : \"LineString\";\n const draw = (this.draw = new Draw({\n source: this.source,\n type: geometryType,\n style: this.activeFeatureStyle\n }));\n this.olMap.addInteraction(draw);\n\n let measureTooltip: Tooltip | undefined;\n let changeListenerKey: EventsKey | undefined = undefined;\n draw.on(\"drawstart\", (evt) => {\n measureTooltip = this.measureTooltip = this.createMeasureTooltip();\n\n // set sketch\n const sketch = (this.sketch = evt.feature);\n if (!sketch) {\n return;\n }\n\n let tooltipCoord: Coordinate | undefined;\n changeListenerKey = sketch.getGeometry()?.on(\"change\", (evt) => {\n const geom = evt.target;\n const projection = this.olMap.getView().getProjection();\n\n let output = \"\";\n if (geom instanceof Polygon) {\n output = formatArea(geom, projection, this.messages);\n tooltipCoord = geom.getInteriorPoint().getCoordinates() || null;\n } else if (geom instanceof LineString) {\n output = formatLength(geom, projection, this.messages);\n tooltipCoord = geom.getLastCoordinate() || null;\n }\n\n if (measureTooltip) {\n measureTooltip.element.innerHTML = output;\n if (tooltipCoord) {\n measureTooltip?.overlay.setPosition(tooltipCoord);\n }\n }\n });\n });\n\n draw.on(\"drawend\", () => {\n if (measureTooltip) {\n // Make the tooltip (which was previously following the mouse)\n // static instead, next to the feature (last known overlay coordinate).\n const classes = measureTooltip.element.classList;\n classes.remove(\"measurement-active-tooltip\");\n classes.remove(\"printing-hide\");\n classes.add(\"measurement-finished-tooltip\");\n measureTooltip.overlay.setOffset([0, -7]);\n\n this.overlayTooltips.push(measureTooltip);\n this.measureTooltip = measureTooltip = undefined;\n }\n\n // unset sketch\n this.sketch = undefined;\n if (changeListenerKey) {\n unByKey(changeListenerKey);\n }\n });\n\n draw.on(\"drawabort\", () => {\n if (measureTooltip) {\n measureTooltip.destroy();\n this.measureTooltip = measureTooltip = undefined;\n }\n\n this.sketch = undefined;\n if (changeListenerKey) {\n unByKey(changeListenerKey);\n }\n });\n }\n\n /** Stops the current measuring started by `startMeasurement`. */\n stopMeasurement() {\n if (this.draw) {\n this.olMap.removeInteraction(this.draw);\n this.draw.abortDrawing();\n this.draw.dispose();\n this.draw = undefined;\n }\n\n this.sketch = undefined;\n this.measureTooltip?.destroy();\n this.measureTooltip = undefined;\n }\n\n private createMeasureTooltip(): Tooltip {\n const element = document.createElement(\"div\");\n element.className = \"measurement-tooltip measurement-active-tooltip printing-hide\";\n\n const overlay = new Overlay({\n element: element,\n offset: [0, -15],\n positioning: \"bottom-center\",\n stopEvent: false,\n insertFirst: false\n });\n\n const olMap = this.olMap;\n olMap.addOverlay(overlay);\n return {\n overlay,\n element,\n destroy() {\n olMap.removeOverlay(overlay);\n }\n };\n }\n\n private createHelpTooltip(): Tooltip {\n const element = document.createElement(\"div\");\n element.className = \"measurement-tooltip printing-hide hidden\";\n\n const overlay = new Overlay({\n element: element,\n offset: [15, 0],\n positioning: \"center-left\"\n });\n\n const olMap = this.olMap;\n olMap.addOverlay(overlay);\n return {\n overlay,\n element,\n destroy() {\n olMap.removeOverlay(overlay);\n }\n };\n }\n\n private handlePointerMove(evt: MapBrowserEvent<UIEvent>) {\n if (evt.dragging) {\n return;\n }\n\n const tooltip = this.helpTooltip;\n const helpMessage = getHelpMessage(this.messages, this.sketch);\n tooltip.element.textContent = helpMessage;\n tooltip.overlay.setPosition(evt.coordinate);\n tooltip.element.classList.remove(\"hidden\");\n }\n}\n\n/** Represents a tooltip rendered on the OpenLayers map. */\ninterface Tooltip extends Resource {\n overlay: Overlay;\n element: HTMLDivElement;\n}\n\nfunction getHelpMessage(messages: Messages, sketch: Feature | undefined) {\n if (sketch) {\n const geom = sketch.getGeometry();\n if (geom instanceof Polygon || geom instanceof LineString) {\n return messages.getContinueMessage();\n }\n }\n return messages.getHelpMessage();\n}\n\nfunction formatArea(polygon: Polygon, projection: Projection, messages: Messages) {\n const area = getArea(polygon, { projection });\n let output;\n if (area >= 1000000) {\n output = `${messages.formatNumber(area / 1000000)} km<sup>2</sup>`;\n } else {\n output = `${messages.formatNumber(area)} m<sup>2</sup>`;\n }\n return output;\n}\n\nfunction formatLength(line: LineString, projection: Projection, messages: Messages) {\n const length = getLength(line, { projection });\n let output;\n if (length >= 1000) {\n output = `${messages.formatNumber(length / 1000)} km`;\n } else {\n output = `${messages.formatNumber(length)} m`;\n }\n return output;\n}\n"],"names":["VectorSource","VectorLayer","toStyleFunction","evt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MeasurementController.js","sources":["MeasurementController.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { destroyResource, Resource } from \"@open-pioneer/core\";\nimport { TOPMOST_LAYER_Z } from \"@open-pioneer/map\";\nimport Feature from \"ol/Feature\";\nimport OlMap from \"ol/Map\";\nimport MapBrowserEvent from \"ol/MapBrowserEvent\";\nimport { unByKey } from \"ol/Observable\";\nimport Overlay from \"ol/Overlay\";\nimport { Coordinate } from \"ol/coordinate\";\nimport { EventsKey } from \"ol/events\";\nimport { LineString, Polygon } from \"ol/geom\";\nimport Draw from \"ol/interaction/Draw\";\nimport { Vector as VectorLayer } from \"ol/layer\";\nimport { Projection } from \"ol/proj\";\nimport { Vector as VectorSource } from \"ol/source\";\nimport { getArea, getLength } from \"ol/sphere\";\nimport { StyleFunction, StyleLike, toFunction as toStyleFunction } from \"ol/style/Style\";\nimport type { MeasurementsChangeEvent, MeasurementGeometry, MeasurementProps } from \"./Measurement\";\n\ntype MeasurementsChangeHandler = NonNullable<MeasurementProps[\"onMeasurementsChange\"]>;\n\nexport type MeasurementType = \"area\" | \"distance\";\n\nexport interface Messages {\n getContinueMessage(): string;\n getHelpMessage(): string;\n formatNumber(value: number): string;\n}\n\nexport class MeasurementController {\n readonly olMap: OlMap;\n readonly messages: Messages;\n\n private activeFeatureStyle: StyleFunction | undefined;\n /**\n * The layer rendering the measurement \"features\".\n */\n private layer: VectorLayer<Feature>;\n\n /**\n * Source of {@link layer}.\n */\n private source: VectorSource;\n\n /**\n * Stores the current `Draw` interaction.\n */\n private draw: Draw | undefined = undefined;\n\n /**\n * The active measurement manipulated by the `draw` interaction.\n */\n private activeMeasurement: MeasurementInstance | undefined;\n\n /**\n * Map that is used to track all predefined measurements currently added to the source.\n * It associates the measurement geometry (key) with the corresponding measurement instance.\n *\n * The measurement instances here must also be contained in `finishedMeasurements`.\n */\n private predefinedMeasurements = new Map<MeasurementGeometry, MeasurementInstance>();\n\n /**\n * Measurement instances that were finished.\n */\n private finishedMeasurements = new Set<MeasurementInstance>();\n\n /**\n * The help tooltip element.\n */\n private helpTooltip: Tooltip;\n\n /**\n * Keeps track of registered event handlers.\n */\n private resources: Resource[] = [];\n\n /**\n * Called when a measurement is added to or removed from the source.\n */\n private measurementChangedHandler: MeasurementsChangeHandler | undefined;\n\n constructor(olMap: OlMap, messages: Messages) {\n this.olMap = olMap;\n this.messages = messages;\n const source = (this.source = new VectorSource());\n this.layer = new VectorLayer({\n source: source,\n zIndex: TOPMOST_LAYER_Z,\n properties: {\n name: \"measurement-layer\"\n }\n });\n olMap.addLayer(this.layer);\n\n const pointerMoveKey = olMap.on(\"pointermove\", this.handlePointerMove.bind(this));\n this.resources.push({\n destroy() {\n unByKey(pointerMoveKey);\n }\n });\n\n const mouseOutHandler = () => {\n this.helpTooltip.element.classList.add(\"hidden\");\n };\n olMap.getViewport().addEventListener(\"mouseout\", mouseOutHandler);\n this.resources.push({\n destroy() {\n olMap.getViewport().removeEventListener(\"mouseout\", mouseOutHandler);\n }\n });\n\n this.helpTooltip = createHelpTooltip(this.olMap);\n }\n\n destroy() {\n this.stopMeasurement();\n\n // Cleanup registered event handlers etc.\n for (const resource of this.resources) {\n resource.destroy();\n }\n this.resources = [];\n\n // Cleanup measurements and tooltips.\n this.activeMeasurement = destroyResource(this.activeMeasurement);\n for (const measurement of this.finishedMeasurements) {\n measurement.destroy();\n }\n this.finishedMeasurements.clear();\n this.helpTooltip.destroy();\n\n // Cleanup layer\n this.olMap.removeLayer(this.layer);\n this.layer.dispose();\n this.source.dispose();\n\n this.measurementChangedHandler = undefined;\n this.predefinedMeasurements.clear();\n }\n\n /** Returns the vector layer used for finished features. */\n getVectorLayer() {\n return this.layer;\n }\n\n /** Updates the style used for finished features. */\n setFinishedFeatureStyle(style: StyleLike) {\n this.layer.setStyle(style);\n }\n\n setMeasurementSourceChangedHandler(handler: MeasurementsChangeHandler | undefined) {\n this.measurementChangedHandler = handler;\n }\n\n setPredefinedMeasurements(geometries: MeasurementGeometry[]) {\n this.updatePredefinedMeasurements(geometries);\n }\n\n /** Updates the style used for active measurements. */\n setActiveFeatureStyle(style: StyleLike) {\n const styleFunction = toStyleFunction(style);\n this.activeFeatureStyle = (feature, ...args) => {\n const ft = feature?.getGeometry()?.getType();\n if (ft === \"Polygon\" || ft === \"LineString\" || ft === \"Point\") {\n return styleFunction(feature, ...args);\n }\n };\n // Update style on current draw instance (if any)\n this.draw?.getOverlay().setStyle(this.activeFeatureStyle);\n }\n\n /** Removes all finished measurements. */\n clearMeasurements() {\n const currentFeatures = this.source.getFeatures(); //returns snapshot copy of the features on the source\n this.source.clear();\n currentFeatures.forEach((feature) => {\n //raise remove-measurement event for each measurement after the source was cleared\n this.raiseMeasurementsChangeEvent(\"remove-measurement\", feature);\n });\n this.predefinedMeasurements.clear();\n for (const measurement of this.finishedMeasurements) {\n measurement.destroy();\n }\n this.finishedMeasurements.clear();\n }\n\n /** Starts measuring using the provided type. */\n startMeasurement(type: MeasurementType) {\n if (this.draw) {\n throw new Error(\"Internal error: another measurement interaction is still active.\");\n }\n\n const geometryType = type === \"area\" ? \"Polygon\" : \"LineString\";\n const draw = (this.draw = new Draw({\n source: this.source,\n type: geometryType,\n style: this.activeFeatureStyle\n }));\n this.olMap.addInteraction(draw);\n\n let measurement: MeasurementInstance | undefined;\n let changeListenerKey: EventsKey | undefined = undefined;\n draw.on(\"drawstart\", (evt) => {\n // set sketch\n const sketch = evt.feature;\n if (!sketch) {\n return;\n }\n\n measurement = this.activeMeasurement = new MeasurementInstance(\"active\", sketch, this);\n changeListenerKey = sketch.getGeometry()?.on(\"change\", () => {\n measurement?.updateTooltipContent();\n measurement?.updateTooltipPosition();\n });\n });\n\n draw.on(\"drawend\", () => {\n if (measurement && measurement === this.activeMeasurement) {\n const newMeasurement = measurement;\n newMeasurement.updateState(\"finished\");\n this.finishedMeasurements.add(newMeasurement);\n this.raiseMeasurementsChangeEvent(\"add-measurement\", newMeasurement.feature);\n this.activeMeasurement = measurement = undefined;\n }\n\n measurement = undefined;\n if (changeListenerKey) {\n unByKey(changeListenerKey);\n }\n });\n\n draw.on(\"drawabort\", () => {\n if (measurement) {\n measurement.destroy();\n if (measurement === this.activeMeasurement) {\n this.activeMeasurement = undefined;\n }\n measurement = undefined;\n }\n if (changeListenerKey) {\n unByKey(changeListenerKey);\n }\n });\n }\n\n /** Stops the current measuring started by `startMeasurement`. */\n stopMeasurement() {\n if (this.draw) {\n this.olMap.removeInteraction(this.draw);\n this.draw.abortDrawing();\n this.draw.dispose();\n this.draw = undefined;\n }\n\n this.activeMeasurement = destroyResource(this.activeMeasurement);\n }\n\n private handlePointerMove(evt: MapBrowserEvent<UIEvent>) {\n if (evt.dragging) {\n return;\n }\n\n const tooltip = this.helpTooltip;\n const helpMessage = getHelpMessage(this.messages, this.activeMeasurement);\n tooltip.setText(helpMessage);\n tooltip.overlay.setPosition(evt.coordinate);\n tooltip.element.classList.remove(\"hidden\");\n }\n\n private updatePredefinedMeasurements(geometries: MeasurementGeometry[]) {\n const addedMeasurements = geometries.filter(\n (geom) => !this.predefinedMeasurements.has(geom)\n );\n const removedMeasurements: MeasurementGeometry[] = [];\n for (const geom of this.predefinedMeasurements.keys()) {\n if (!geometries.includes(geom)) {\n removedMeasurements.push(geom);\n }\n }\n\n addedMeasurements.forEach((geom) => {\n const measurementFeature = new Feature(geom);\n this.source.addFeature(measurementFeature);\n\n const measurement = new MeasurementInstance(\"finished\", measurementFeature, this);\n this.finishedMeasurements.add(measurement);\n this.predefinedMeasurements.set(geom, measurement);\n this.raiseMeasurementsChangeEvent(\"add-measurement\", measurementFeature);\n });\n\n removedMeasurements.forEach((geom) => {\n const measurement = this.predefinedMeasurements.get(geom);\n if (measurement) {\n //remove measurement feature from source and destroy associated tooltip\n this.source.removeFeature(measurement.feature);\n this.finishedMeasurements.delete(measurement);\n measurement.destroy();\n this.raiseMeasurementsChangeEvent(\"remove-measurement\", measurement.feature);\n }\n this.predefinedMeasurements.delete(geom);\n });\n }\n\n private raiseMeasurementsChangeEvent(\n kind: MeasurementsChangeEvent[\"kind\"],\n measurementFeature: Feature\n ) {\n const measurementGeom = measurementFeature.getGeometry();\n if (this.measurementChangedHandler && measurementGeom) {\n this.measurementChangedHandler({\n kind: kind,\n geometry:\n measurementGeom instanceof Polygon\n ? (measurementGeom as Polygon)\n : (measurementGeom as LineString)\n });\n }\n }\n}\n\n// Encapsulates the display state of a measurement.\n//\n// More ideas for further improvements:\n// - Resolve duplicate source of truths (feature source and map of measurements).\n// - Add and remove the feature here as well (instead of in the controller).\n// - Perhaps use reactivity API and watch for state consistency.\n// The current implementations relies on the update*() functions being called at the correct time.\nclass MeasurementInstance {\n readonly controller: MeasurementController;\n readonly feature: Feature;\n\n private _state: \"active\" | \"finished\";\n private readonly tooltip: ReturnType<typeof createMeasureTooltip>;\n\n constructor(state: \"active\" | \"finished\", feature: Feature, controller: MeasurementController) {\n this.controller = controller;\n this._state = state;\n this.feature = feature;\n this.tooltip = createMeasureTooltip(this.olMap);\n this.updateTooltipContent();\n this.updateTooltipPosition();\n this.tooltip.setActive(state === \"active\");\n }\n\n destroy() {\n this.tooltip.destroy();\n }\n\n get state(): \"active\" | \"finished\" {\n return this._state;\n }\n\n updateState(state: \"active\" | \"finished\") {\n if (this._state === state) {\n return;\n }\n\n this._state = state;\n this.tooltip.setActive(state === \"active\");\n }\n\n // Updates the tooltip content based on the current state and the feature's geometry.\n updateTooltipContent() {\n const geometry = this.feature.getGeometry();\n if (!geometry) {\n return;\n }\n\n const projection = this.olMap.getView().getProjection();\n let outputHtml;\n if (geometry instanceof Polygon) {\n outputHtml = formatArea(geometry, projection, this.messages);\n } else if (geometry instanceof LineString) {\n outputHtml = formatLength(geometry, projection, this.messages);\n }\n if (outputHtml) {\n this.tooltip.setHtml(outputHtml);\n }\n }\n\n // Updates the tooltip's position.\n updateTooltipPosition() {\n const geometry = this.feature.getGeometry();\n if (!geometry) {\n return;\n }\n\n let tooltipCoord: Coordinate;\n if (geometry instanceof Polygon) {\n tooltipCoord = geometry.getInteriorPoint().getCoordinates() || null;\n } else if (geometry instanceof LineString) {\n tooltipCoord = geometry.getLastCoordinate() || null;\n } else {\n return;\n }\n this.tooltip.overlay.setPosition(tooltipCoord);\n }\n\n private get olMap(): OlMap {\n return this.controller.olMap;\n }\n\n private get messages(): Messages {\n return this.controller.messages;\n }\n}\n\nconst DEFAULT_MEASUREMENT_OFFSET = [0, -15];\nconst FINISHED_MEASUREMENT_OFFSET = [0, -7];\n\n/** Represents a tooltip rendered on the OpenLayers map. */\ninterface Tooltip extends Resource {\n overlay: Overlay;\n element: HTMLDivElement;\n\n setText(value: string): void;\n setHtml(value: string): void;\n}\n\nfunction createHelpTooltip(olMap: OlMap): Tooltip {\n const element = document.createElement(\"div\");\n element.className = \"measurement-tooltip printing-hide hidden\";\n element.role = \"tooltip\";\n\n const content = document.createElement(\"span\");\n element.appendChild(content);\n\n const overlay = new Overlay({\n element: element,\n offset: [15, 0],\n positioning: \"center-left\"\n });\n\n olMap.addOverlay(overlay);\n return {\n overlay,\n element,\n destroy() {\n olMap.removeOverlay(overlay);\n },\n setText(value) {\n content.textContent = value;\n },\n setHtml(value) {\n content.innerHTML = value;\n }\n };\n}\n\nfunction createMeasureTooltip(olMap: OlMap): Tooltip & { setActive(active: boolean): void } {\n const element = document.createElement(\"div\");\n element.role = \"tooltip\";\n element.className = \"measurement-tooltip measurement-active-tooltip printing-hide\";\n\n const content = document.createElement(\"span\");\n element.appendChild(content);\n\n const overlay = new Overlay({\n element: element,\n offset: DEFAULT_MEASUREMENT_OFFSET,\n positioning: \"bottom-center\",\n stopEvent: false,\n insertFirst: false\n });\n\n olMap.addOverlay(overlay);\n return {\n overlay,\n element,\n destroy() {\n olMap.removeOverlay(overlay);\n },\n setActive(active) {\n if (active) {\n element.className = \"measurement-tooltip measurement-active-tooltip printing-hide\";\n overlay.setOffset(DEFAULT_MEASUREMENT_OFFSET);\n } else {\n element.className = \"measurement-tooltip measurement-finished-tooltip\";\n overlay.setOffset(FINISHED_MEASUREMENT_OFFSET);\n }\n },\n setText(value) {\n content.textContent = value;\n },\n setHtml(value) {\n content.innerHTML = value;\n }\n };\n}\n\nfunction getHelpMessage(messages: Messages, activeMeasurement: MeasurementInstance | undefined) {\n if (activeMeasurement) {\n const geom = activeMeasurement.feature.getGeometry();\n if (geom instanceof Polygon || geom instanceof LineString) {\n return messages.getContinueMessage();\n }\n }\n return messages.getHelpMessage();\n}\n\nfunction formatArea(polygon: Polygon, projection: Projection, messages: Messages) {\n const area = getArea(polygon, { projection });\n let output;\n if (area >= 1000000) {\n output = `${messages.formatNumber(area / 1000000)} km<sup>2</sup>`;\n } else {\n output = `${messages.formatNumber(area)} m<sup>2</sup>`;\n }\n return output;\n}\n\nfunction formatLength(line: LineString, projection: Projection, messages: Messages) {\n const length = getLength(line, { projection });\n let output;\n if (length >= 1000) {\n output = `${messages.formatNumber(length / 1000)} km`;\n } else {\n output = `${messages.formatNumber(length)} m`;\n }\n return output;\n}\n"],"names":["VectorSource","VectorLayer","toStyleFunction"],"mappings":";;;;;;;;;;;;AA8BO,MAAM,qBAAsB,CAAA;AAAA,EACtB,KAAA,CAAA;AAAA,EACA,QAAA,CAAA;AAAA,EAED,kBAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAIA,KAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAyB,GAAA,KAAA,CAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKzB,iBAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAA,uBAA6B,GAA8C,EAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAK3E,oBAAA,uBAA2B,GAAyB,EAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKpD,WAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAwB,EAAC,CAAA;AAAA;AAAA;AAAA;AAAA,EAKzB,yBAAA,CAAA;AAAA,EAER,WAAA,CAAY,OAAc,QAAoB,EAAA;AAC1C,IAAA,IAAA,CAAK,KAAQ,GAAA,KAAA,CAAA;AACb,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA,CAAA;AAChB,IAAA,MAAM,MAAU,GAAA,IAAA,CAAK,MAAS,GAAA,IAAIA,MAAa,EAAA,CAAA;AAC/C,IAAK,IAAA,CAAA,KAAA,GAAQ,IAAIC,QAAY,CAAA;AAAA,MACzB,MAAA;AAAA,MACA,MAAQ,EAAA,eAAA;AAAA,MACR,UAAY,EAAA;AAAA,QACR,IAAM,EAAA,mBAAA;AAAA,OACV;AAAA,KACH,CAAA,CAAA;AACD,IAAM,KAAA,CAAA,QAAA,CAAS,KAAK,KAAK,CAAA,CAAA;AAEzB,IAAM,MAAA,cAAA,GAAiB,MAAM,EAAG,CAAA,aAAA,EAAe,KAAK,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAChF,IAAA,IAAA,CAAK,UAAU,IAAK,CAAA;AAAA,MAChB,OAAU,GAAA;AACN,QAAA,OAAA,CAAQ,cAAc,CAAA,CAAA;AAAA,OAC1B;AAAA,KACH,CAAA,CAAA;AAED,IAAA,MAAM,kBAAkB,MAAM;AAC1B,MAAA,IAAA,CAAK,WAAY,CAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,QAAQ,CAAA,CAAA;AAAA,KACnD,CAAA;AACA,IAAA,KAAA,CAAM,WAAY,EAAA,CAAE,gBAAiB,CAAA,UAAA,EAAY,eAAe,CAAA,CAAA;AAChE,IAAA,IAAA,CAAK,UAAU,IAAK,CAAA;AAAA,MAChB,OAAU,GAAA;AACN,QAAA,KAAA,CAAM,WAAY,EAAA,CAAE,mBAAoB,CAAA,UAAA,EAAY,eAAe,CAAA,CAAA;AAAA,OACvE;AAAA,KACH,CAAA,CAAA;AAED,IAAK,IAAA,CAAA,WAAA,GAAc,iBAAkB,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAAA,GACnD;AAAA,EAEA,OAAU,GAAA;AACN,IAAA,IAAA,CAAK,eAAgB,EAAA,CAAA;AAGrB,IAAW,KAAA,MAAA,QAAA,IAAY,KAAK,SAAW,EAAA;AACnC,MAAA,QAAA,CAAS,OAAQ,EAAA,CAAA;AAAA,KACrB;AACA,IAAA,IAAA,CAAK,YAAY,EAAC,CAAA;AAGlB,IAAK,IAAA,CAAA,iBAAA,GAAoB,eAAgB,CAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AAC/D,IAAW,KAAA,MAAA,WAAA,IAAe,KAAK,oBAAsB,EAAA;AACjD,MAAA,WAAA,CAAY,OAAQ,EAAA,CAAA;AAAA,KACxB;AACA,IAAA,IAAA,CAAK,qBAAqB,KAAM,EAAA,CAAA;AAChC,IAAA,IAAA,CAAK,YAAY,OAAQ,EAAA,CAAA;AAGzB,IAAK,IAAA,CAAA,KAAA,CAAM,WAAY,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AACjC,IAAA,IAAA,CAAK,MAAM,OAAQ,EAAA,CAAA;AACnB,IAAA,IAAA,CAAK,OAAO,OAAQ,EAAA,CAAA;AAEpB,IAAA,IAAA,CAAK,yBAA4B,GAAA,KAAA,CAAA,CAAA;AACjC,IAAA,IAAA,CAAK,uBAAuB,KAAM,EAAA,CAAA;AAAA,GACtC;AAAA;AAAA,EAGA,cAAiB,GAAA;AACb,IAAA,OAAO,IAAK,CAAA,KAAA,CAAA;AAAA,GAChB;AAAA;AAAA,EAGA,wBAAwB,KAAkB,EAAA;AACtC,IAAK,IAAA,CAAA,KAAA,CAAM,SAAS,KAAK,CAAA,CAAA;AAAA,GAC7B;AAAA,EAEA,mCAAmC,OAAgD,EAAA;AAC/E,IAAA,IAAA,CAAK,yBAA4B,GAAA,OAAA,CAAA;AAAA,GACrC;AAAA,EAEA,0BAA0B,UAAmC,EAAA;AACzD,IAAA,IAAA,CAAK,6BAA6B,UAAU,CAAA,CAAA;AAAA,GAChD;AAAA;AAAA,EAGA,sBAAsB,KAAkB,EAAA;AACpC,IAAM,MAAA,aAAA,GAAgBC,WAAgB,KAAK,CAAA,CAAA;AAC3C,IAAK,IAAA,CAAA,kBAAA,GAAqB,CAAC,OAAA,EAAA,GAAY,IAAS,KAAA;AAC5C,MAAA,MAAM,EAAK,GAAA,OAAA,EAAS,WAAY,EAAA,EAAG,OAAQ,EAAA,CAAA;AAC3C,MAAA,IAAI,EAAO,KAAA,SAAA,IAAa,EAAO,KAAA,YAAA,IAAgB,OAAO,OAAS,EAAA;AAC3D,QAAO,OAAA,aAAA,CAAc,OAAS,EAAA,GAAG,IAAI,CAAA,CAAA;AAAA,OACzC;AAAA,KACJ,CAAA;AAEA,IAAA,IAAA,CAAK,IAAM,EAAA,UAAA,EAAa,CAAA,QAAA,CAAS,KAAK,kBAAkB,CAAA,CAAA;AAAA,GAC5D;AAAA;AAAA,EAGA,iBAAoB,GAAA;AAChB,IAAM,MAAA,eAAA,GAAkB,IAAK,CAAA,MAAA,CAAO,WAAY,EAAA,CAAA;AAChD,IAAA,IAAA,CAAK,OAAO,KAAM,EAAA,CAAA;AAClB,IAAgB,eAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AAEjC,MAAK,IAAA,CAAA,4BAAA,CAA6B,sBAAsB,OAAO,CAAA,CAAA;AAAA,KAClE,CAAA,CAAA;AACD,IAAA,IAAA,CAAK,uBAAuB,KAAM,EAAA,CAAA;AAClC,IAAW,KAAA,MAAA,WAAA,IAAe,KAAK,oBAAsB,EAAA;AACjD,MAAA,WAAA,CAAY,OAAQ,EAAA,CAAA;AAAA,KACxB;AACA,IAAA,IAAA,CAAK,qBAAqB,KAAM,EAAA,CAAA;AAAA,GACpC;AAAA;AAAA,EAGA,iBAAiB,IAAuB,EAAA;AACpC,IAAA,IAAI,KAAK,IAAM,EAAA;AACX,MAAM,MAAA,IAAI,MAAM,kEAAkE,CAAA,CAAA;AAAA,KACtF;AAEA,IAAM,MAAA,YAAA,GAAe,IAAS,KAAA,MAAA,GAAS,SAAY,GAAA,YAAA,CAAA;AACnD,IAAA,MAAM,IAAQ,GAAA,IAAA,CAAK,IAAO,GAAA,IAAI,IAAK,CAAA;AAAA,MAC/B,QAAQ,IAAK,CAAA,MAAA;AAAA,MACb,IAAM,EAAA,YAAA;AAAA,MACN,OAAO,IAAK,CAAA,kBAAA;AAAA,KACf,CAAA,CAAA;AACD,IAAK,IAAA,CAAA,KAAA,CAAM,eAAe,IAAI,CAAA,CAAA;AAE9B,IAAI,IAAA,WAAA,CAAA;AACJ,IAAA,IAAI,iBAA2C,GAAA,KAAA,CAAA,CAAA;AAC/C,IAAK,IAAA,CAAA,EAAA,CAAG,WAAa,EAAA,CAAC,GAAQ,KAAA;AAE1B,MAAA,MAAM,SAAS,GAAI,CAAA,OAAA,CAAA;AACnB,MAAA,IAAI,CAAC,MAAQ,EAAA;AACT,QAAA,OAAA;AAAA,OACJ;AAEA,MAAA,WAAA,GAAc,KAAK,iBAAoB,GAAA,IAAI,mBAAoB,CAAA,QAAA,EAAU,QAAQ,IAAI,CAAA,CAAA;AACrF,MAAA,iBAAA,GAAoB,MAAO,CAAA,WAAA,EAAe,EAAA,EAAA,CAAG,UAAU,MAAM;AACzD,QAAA,WAAA,EAAa,oBAAqB,EAAA,CAAA;AAClC,QAAA,WAAA,EAAa,qBAAsB,EAAA,CAAA;AAAA,OACtC,CAAA,CAAA;AAAA,KACJ,CAAA,CAAA;AAED,IAAK,IAAA,CAAA,EAAA,CAAG,WAAW,MAAM;AACrB,MAAI,IAAA,WAAA,IAAe,WAAgB,KAAA,IAAA,CAAK,iBAAmB,EAAA;AACvD,QAAA,MAAM,cAAiB,GAAA,WAAA,CAAA;AACvB,QAAA,cAAA,CAAe,YAAY,UAAU,CAAA,CAAA;AACrC,QAAK,IAAA,CAAA,oBAAA,CAAqB,IAAI,cAAc,CAAA,CAAA;AAC5C,QAAK,IAAA,CAAA,4BAAA,CAA6B,iBAAmB,EAAA,cAAA,CAAe,OAAO,CAAA,CAAA;AAC3E,QAAA,IAAA,CAAK,oBAAoB,WAAc,GAAA,KAAA,CAAA,CAAA;AAAA,OAC3C;AAEA,MAAc,WAAA,GAAA,KAAA,CAAA,CAAA;AACd,MAAA,IAAI,iBAAmB,EAAA;AACnB,QAAA,OAAA,CAAQ,iBAAiB,CAAA,CAAA;AAAA,OAC7B;AAAA,KACH,CAAA,CAAA;AAED,IAAK,IAAA,CAAA,EAAA,CAAG,aAAa,MAAM;AACvB,MAAA,IAAI,WAAa,EAAA;AACb,QAAA,WAAA,CAAY,OAAQ,EAAA,CAAA;AACpB,QAAI,IAAA,WAAA,KAAgB,KAAK,iBAAmB,EAAA;AACxC,UAAA,IAAA,CAAK,iBAAoB,GAAA,KAAA,CAAA,CAAA;AAAA,SAC7B;AACA,QAAc,WAAA,GAAA,KAAA,CAAA,CAAA;AAAA,OAClB;AACA,MAAA,IAAI,iBAAmB,EAAA;AACnB,QAAA,OAAA,CAAQ,iBAAiB,CAAA,CAAA;AAAA,OAC7B;AAAA,KACH,CAAA,CAAA;AAAA,GACL;AAAA;AAAA,EAGA,eAAkB,GAAA;AACd,IAAA,IAAI,KAAK,IAAM,EAAA;AACX,MAAK,IAAA,CAAA,KAAA,CAAM,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACtC,MAAA,IAAA,CAAK,KAAK,YAAa,EAAA,CAAA;AACvB,MAAA,IAAA,CAAK,KAAK,OAAQ,EAAA,CAAA;AAClB,MAAA,IAAA,CAAK,IAAO,GAAA,KAAA,CAAA,CAAA;AAAA,KAChB;AAEA,IAAK,IAAA,CAAA,iBAAA,GAAoB,eAAgB,CAAA,IAAA,CAAK,iBAAiB,CAAA,CAAA;AAAA,GACnE;AAAA,EAEQ,kBAAkB,GAA+B,EAAA;AACrD,IAAA,IAAI,IAAI,QAAU,EAAA;AACd,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,MAAM,UAAU,IAAK,CAAA,WAAA,CAAA;AACrB,IAAA,MAAM,WAAc,GAAA,cAAA,CAAe,IAAK,CAAA,QAAA,EAAU,KAAK,iBAAiB,CAAA,CAAA;AACxE,IAAA,OAAA,CAAQ,QAAQ,WAAW,CAAA,CAAA;AAC3B,IAAQ,OAAA,CAAA,OAAA,CAAQ,WAAY,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAC1C,IAAQ,OAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,GAC7C;AAAA,EAEQ,6BAA6B,UAAmC,EAAA;AACpE,IAAA,MAAM,oBAAoB,UAAW,CAAA,MAAA;AAAA,MACjC,CAAC,IAAS,KAAA,CAAC,IAAK,CAAA,sBAAA,CAAuB,IAAI,IAAI,CAAA;AAAA,KACnD,CAAA;AACA,IAAA,MAAM,sBAA6C,EAAC,CAAA;AACpD,IAAA,KAAA,MAAW,IAAQ,IAAA,IAAA,CAAK,sBAAuB,CAAA,IAAA,EAAQ,EAAA;AACnD,MAAA,IAAI,CAAC,UAAA,CAAW,QAAS,CAAA,IAAI,CAAG,EAAA;AAC5B,QAAA,mBAAA,CAAoB,KAAK,IAAI,CAAA,CAAA;AAAA,OACjC;AAAA,KACJ;AAEA,IAAkB,iBAAA,CAAA,OAAA,CAAQ,CAAC,IAAS,KAAA;AAChC,MAAM,MAAA,kBAAA,GAAqB,IAAI,OAAA,CAAQ,IAAI,CAAA,CAAA;AAC3C,MAAK,IAAA,CAAA,MAAA,CAAO,WAAW,kBAAkB,CAAA,CAAA;AAEzC,MAAA,MAAM,WAAc,GAAA,IAAI,mBAAoB,CAAA,UAAA,EAAY,oBAAoB,IAAI,CAAA,CAAA;AAChF,MAAK,IAAA,CAAA,oBAAA,CAAqB,IAAI,WAAW,CAAA,CAAA;AACzC,MAAK,IAAA,CAAA,sBAAA,CAAuB,GAAI,CAAA,IAAA,EAAM,WAAW,CAAA,CAAA;AACjD,MAAK,IAAA,CAAA,4BAAA,CAA6B,mBAAmB,kBAAkB,CAAA,CAAA;AAAA,KAC1E,CAAA,CAAA;AAED,IAAoB,mBAAA,CAAA,OAAA,CAAQ,CAAC,IAAS,KAAA;AAClC,MAAA,MAAM,WAAc,GAAA,IAAA,CAAK,sBAAuB,CAAA,GAAA,CAAI,IAAI,CAAA,CAAA;AACxD,MAAA,IAAI,WAAa,EAAA;AAEb,QAAK,IAAA,CAAA,MAAA,CAAO,aAAc,CAAA,WAAA,CAAY,OAAO,CAAA,CAAA;AAC7C,QAAK,IAAA,CAAA,oBAAA,CAAqB,OAAO,WAAW,CAAA,CAAA;AAC5C,QAAA,WAAA,CAAY,OAAQ,EAAA,CAAA;AACpB,QAAK,IAAA,CAAA,4BAAA,CAA6B,oBAAsB,EAAA,WAAA,CAAY,OAAO,CAAA,CAAA;AAAA,OAC/E;AACA,MAAK,IAAA,CAAA,sBAAA,CAAuB,OAAO,IAAI,CAAA,CAAA;AAAA,KAC1C,CAAA,CAAA;AAAA,GACL;AAAA,EAEQ,4BAAA,CACJ,MACA,kBACF,EAAA;AACE,IAAM,MAAA,eAAA,GAAkB,mBAAmB,WAAY,EAAA,CAAA;AACvD,IAAI,IAAA,IAAA,CAAK,6BAA6B,eAAiB,EAAA;AACnD,MAAA,IAAA,CAAK,yBAA0B,CAAA;AAAA,QAC3B,IAAA;AAAA,QACA,QAAA,EACI,eAA2B,YAAA,OAAA,GACpB,eACA,GAAA,eAAA;AAAA,OACd,CAAA,CAAA;AAAA,KACL;AAAA,GACJ;AACJ,CAAA;AASA,MAAM,mBAAoB,CAAA;AAAA,EACb,UAAA,CAAA;AAAA,EACA,OAAA,CAAA;AAAA,EAED,MAAA,CAAA;AAAA,EACS,OAAA,CAAA;AAAA,EAEjB,WAAA,CAAY,KAA8B,EAAA,OAAA,EAAkB,UAAmC,EAAA;AAC3F,IAAA,IAAA,CAAK,UAAa,GAAA,UAAA,CAAA;AAClB,IAAA,IAAA,CAAK,MAAS,GAAA,KAAA,CAAA;AACd,IAAA,IAAA,CAAK,OAAU,GAAA,OAAA,CAAA;AACf,IAAK,IAAA,CAAA,OAAA,GAAU,oBAAqB,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAC9C,IAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAC1B,IAAA,IAAA,CAAK,qBAAsB,EAAA,CAAA;AAC3B,IAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,KAAA,KAAU,QAAQ,CAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,OAAU,GAAA;AACN,IAAA,IAAA,CAAK,QAAQ,OAAQ,EAAA,CAAA;AAAA,GACzB;AAAA,EAEA,IAAI,KAA+B,GAAA;AAC/B,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GAChB;AAAA,EAEA,YAAY,KAA8B,EAAA;AACtC,IAAI,IAAA,IAAA,CAAK,WAAW,KAAO,EAAA;AACvB,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,IAAA,CAAK,MAAS,GAAA,KAAA,CAAA;AACd,IAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,KAAA,KAAU,QAAQ,CAAA,CAAA;AAAA,GAC7C;AAAA;AAAA,EAGA,oBAAuB,GAAA;AACnB,IAAM,MAAA,QAAA,GAAW,IAAK,CAAA,OAAA,CAAQ,WAAY,EAAA,CAAA;AAC1C,IAAA,IAAI,CAAC,QAAU,EAAA;AACX,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,MAAM,UAAa,GAAA,IAAA,CAAK,KAAM,CAAA,OAAA,GAAU,aAAc,EAAA,CAAA;AACtD,IAAI,IAAA,UAAA,CAAA;AACJ,IAAA,IAAI,oBAAoB,OAAS,EAAA;AAC7B,MAAA,UAAA,GAAa,UAAW,CAAA,QAAA,EAAU,UAAY,EAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,KAC/D,MAAA,IAAW,oBAAoB,UAAY,EAAA;AACvC,MAAA,UAAA,GAAa,YAAa,CAAA,QAAA,EAAU,UAAY,EAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,KACjE;AACA,IAAA,IAAI,UAAY,EAAA;AACZ,MAAK,IAAA,CAAA,OAAA,CAAQ,QAAQ,UAAU,CAAA,CAAA;AAAA,KACnC;AAAA,GACJ;AAAA;AAAA,EAGA,qBAAwB,GAAA;AACpB,IAAM,MAAA,QAAA,GAAW,IAAK,CAAA,OAAA,CAAQ,WAAY,EAAA,CAAA;AAC1C,IAAA,IAAI,CAAC,QAAU,EAAA;AACX,MAAA,OAAA;AAAA,KACJ;AAEA,IAAI,IAAA,YAAA,CAAA;AACJ,IAAA,IAAI,oBAAoB,OAAS,EAAA;AAC7B,MAAA,YAAA,GAAe,QAAS,CAAA,gBAAA,EAAmB,CAAA,cAAA,EAAoB,IAAA,IAAA,CAAA;AAAA,KACnE,MAAA,IAAW,oBAAoB,UAAY,EAAA;AACvC,MAAe,YAAA,GAAA,QAAA,CAAS,mBAAuB,IAAA,IAAA,CAAA;AAAA,KAC5C,MAAA;AACH,MAAA,OAAA;AAAA,KACJ;AACA,IAAK,IAAA,CAAA,OAAA,CAAQ,OAAQ,CAAA,WAAA,CAAY,YAAY,CAAA,CAAA;AAAA,GACjD;AAAA,EAEA,IAAY,KAAe,GAAA;AACvB,IAAA,OAAO,KAAK,UAAW,CAAA,KAAA,CAAA;AAAA,GAC3B;AAAA,EAEA,IAAY,QAAqB,GAAA;AAC7B,IAAA,OAAO,KAAK,UAAW,CAAA,QAAA,CAAA;AAAA,GAC3B;AACJ,CAAA;AAEA,MAAM,0BAAA,GAA6B,CAAC,CAAA,EAAG,CAAG,EAAA,CAAA,CAAA;AAC1C,MAAM,2BAAA,GAA8B,CAAC,CAAA,EAAG,CAAE,CAAA,CAAA,CAAA;AAW1C,SAAS,kBAAkB,KAAuB,EAAA;AAC9C,EAAM,MAAA,OAAA,GAAU,QAAS,CAAA,aAAA,CAAc,KAAK,CAAA,CAAA;AAC5C,EAAA,OAAA,CAAQ,SAAY,GAAA,0CAAA,CAAA;AACpB,EAAA,OAAA,CAAQ,IAAO,GAAA,SAAA,CAAA;AAEf,EAAM,MAAA,OAAA,GAAU,QAAS,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AAC7C,EAAA,OAAA,CAAQ,YAAY,OAAO,CAAA,CAAA;AAE3B,EAAM,MAAA,OAAA,GAAU,IAAI,OAAQ,CAAA;AAAA,IACxB,OAAA;AAAA,IACA,MAAA,EAAQ,CAAC,EAAA,EAAI,CAAC,CAAA;AAAA,IACd,WAAa,EAAA,aAAA;AAAA,GAChB,CAAA,CAAA;AAED,EAAA,KAAA,CAAM,WAAW,OAAO,CAAA,CAAA;AACxB,EAAO,OAAA;AAAA,IACH,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAU,GAAA;AACN,MAAA,KAAA,CAAM,cAAc,OAAO,CAAA,CAAA;AAAA,KAC/B;AAAA,IACA,QAAQ,KAAO,EAAA;AACX,MAAA,OAAA,CAAQ,WAAc,GAAA,KAAA,CAAA;AAAA,KAC1B;AAAA,IACA,QAAQ,KAAO,EAAA;AACX,MAAA,OAAA,CAAQ,SAAY,GAAA,KAAA,CAAA;AAAA,KACxB;AAAA,GACJ,CAAA;AACJ,CAAA;AAEA,SAAS,qBAAqB,KAA8D,EAAA;AACxF,EAAM,MAAA,OAAA,GAAU,QAAS,CAAA,aAAA,CAAc,KAAK,CAAA,CAAA;AAC5C,EAAA,OAAA,CAAQ,IAAO,GAAA,SAAA,CAAA;AACf,EAAA,OAAA,CAAQ,SAAY,GAAA,8DAAA,CAAA;AAEpB,EAAM,MAAA,OAAA,GAAU,QAAS,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AAC7C,EAAA,OAAA,CAAQ,YAAY,OAAO,CAAA,CAAA;AAE3B,EAAM,MAAA,OAAA,GAAU,IAAI,OAAQ,CAAA;AAAA,IACxB,OAAA;AAAA,IACA,MAAQ,EAAA,0BAAA;AAAA,IACR,WAAa,EAAA,eAAA;AAAA,IACb,SAAW,EAAA,KAAA;AAAA,IACX,WAAa,EAAA,KAAA;AAAA,GAChB,CAAA,CAAA;AAED,EAAA,KAAA,CAAM,WAAW,OAAO,CAAA,CAAA;AACxB,EAAO,OAAA;AAAA,IACH,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAU,GAAA;AACN,MAAA,KAAA,CAAM,cAAc,OAAO,CAAA,CAAA;AAAA,KAC/B;AAAA,IACA,UAAU,MAAQ,EAAA;AACd,MAAA,IAAI,MAAQ,EAAA;AACR,QAAA,OAAA,CAAQ,SAAY,GAAA,8DAAA,CAAA;AACpB,QAAA,OAAA,CAAQ,UAAU,0BAA0B,CAAA,CAAA;AAAA,OACzC,MAAA;AACH,QAAA,OAAA,CAAQ,SAAY,GAAA,kDAAA,CAAA;AACpB,QAAA,OAAA,CAAQ,UAAU,2BAA2B,CAAA,CAAA;AAAA,OACjD;AAAA,KACJ;AAAA,IACA,QAAQ,KAAO,EAAA;AACX,MAAA,OAAA,CAAQ,WAAc,GAAA,KAAA,CAAA;AAAA,KAC1B;AAAA,IACA,QAAQ,KAAO,EAAA;AACX,MAAA,OAAA,CAAQ,SAAY,GAAA,KAAA,CAAA;AAAA,KACxB;AAAA,GACJ,CAAA;AACJ,CAAA;AAEA,SAAS,cAAA,CAAe,UAAoB,iBAAoD,EAAA;AAC5F,EAAA,IAAI,iBAAmB,EAAA;AACnB,IAAM,MAAA,IAAA,GAAO,iBAAkB,CAAA,OAAA,CAAQ,WAAY,EAAA,CAAA;AACnD,IAAI,IAAA,IAAA,YAAgB,OAAW,IAAA,IAAA,YAAgB,UAAY,EAAA;AACvD,MAAA,OAAO,SAAS,kBAAmB,EAAA,CAAA;AAAA,KACvC;AAAA,GACJ;AACA,EAAA,OAAO,SAAS,cAAe,EAAA,CAAA;AACnC,CAAA;AAEA,SAAS,UAAA,CAAW,OAAkB,EAAA,UAAA,EAAwB,QAAoB,EAAA;AAC9E,EAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,OAAS,EAAA,EAAE,YAAY,CAAA,CAAA;AAC5C,EAAI,IAAA,MAAA,CAAA;AACJ,EAAA,IAAI,QAAQ,GAAS,EAAA;AACjB,IAAA,MAAA,GAAS,CAAG,EAAA,QAAA,CAAS,YAAa,CAAA,IAAA,GAAO,GAAO,CAAC,CAAA,eAAA,CAAA,CAAA;AAAA,GAC9C,MAAA;AACH,IAAA,MAAA,GAAS,CAAG,EAAA,QAAA,CAAS,YAAa,CAAA,IAAI,CAAC,CAAA,cAAA,CAAA,CAAA;AAAA,GAC3C;AACA,EAAO,OAAA,MAAA,CAAA;AACX,CAAA;AAEA,SAAS,YAAA,CAAa,IAAkB,EAAA,UAAA,EAAwB,QAAoB,EAAA;AAChF,EAAA,MAAM,MAAS,GAAA,SAAA,CAAU,IAAM,EAAA,EAAE,YAAY,CAAA,CAAA;AAC7C,EAAI,IAAA,MAAA,CAAA;AACJ,EAAA,IAAI,UAAU,GAAM,EAAA;AAChB,IAAA,MAAA,GAAS,CAAG,EAAA,QAAA,CAAS,YAAa,CAAA,MAAA,GAAS,GAAI,CAAC,CAAA,GAAA,CAAA,CAAA;AAAA,GAC7C,MAAA;AACH,IAAA,MAAA,GAAS,CAAG,EAAA,QAAA,CAAS,YAAa,CAAA,MAAM,CAAC,CAAA,EAAA,CAAA,CAAA;AAAA,GAC7C;AACA,EAAO,OAAA,MAAA,CAAA;AACX;;;;"}
|
package/README.md
CHANGED
|
@@ -60,6 +60,44 @@ function AppUI() {
|
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### Adding predefined measurements
|
|
64
|
+
|
|
65
|
+
The optional property `predefinedMeasurements` can be used to add predefined measurement geometries (line strings and polygons).
|
|
66
|
+
The predefined measurements will have the same style and tooltip as measurements created by a user.
|
|
67
|
+
|
|
68
|
+
Note that predefined measurements are re-applied when the array changes.
|
|
69
|
+
To prevent accidental updates, wrap the array in a `useMemo` hook or store it somewhere outside the render function.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import LineString from "ol/geom/LineString";
|
|
73
|
+
import { MeasurementGeometry } from "@open-pioneer/measurement/MeasurementController";
|
|
74
|
+
|
|
75
|
+
const measurements = useMemo(
|
|
76
|
+
() => [
|
|
77
|
+
new LineString([
|
|
78
|
+
[398657.97, 5755696.26],
|
|
79
|
+
[402570.98, 5757547.78]
|
|
80
|
+
])
|
|
81
|
+
],
|
|
82
|
+
[]
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
<Measurement predefinedMeasurements={measurements} />;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Listen for changes
|
|
89
|
+
|
|
90
|
+
The optional property `onMeasurementsChange` can be used to register an event handler function.
|
|
91
|
+
This function is called whenever the set of measurements changes (i.e. add or remove actions).
|
|
92
|
+
|
|
93
|
+
Changes include both user actions or updates triggered by `predefinedMeasurements`.
|
|
94
|
+
Unmounting the component will not trigger a change event.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// outputs either add-measurement or remove-measurement and the measurement geometry
|
|
98
|
+
<Measurement onMeasurementsChange={(e) => console.log(e.kind, e.geometry)} />
|
|
99
|
+
```
|
|
100
|
+
|
|
63
101
|
## License
|
|
64
102
|
|
|
65
103
|
Apache-2.0 (see `LICENSE` file)
|
package/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Measurement, type MeasurementProps } from "./Measurement";
|
|
1
|
+
export { Measurement, type MeasurementProps, type MeasurementsAddEvent, type MeasurementsRemoveEvent, type MeasurementsChangeEvent, type MeasurementGeometry } from "./Measurement";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@open-pioneer/measurement",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"description": "This package provides a UI component that allows the user to perform area and distance measurements on the map.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"open-pioneer-trails"
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
"directory": "src/packages/measurement"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@open-pioneer/chakra-integration": "^1.1.
|
|
18
|
-
"@open-pioneer/
|
|
19
|
-
"
|
|
20
|
-
"
|
|
17
|
+
"@open-pioneer/chakra-integration": "^1.1.4",
|
|
18
|
+
"@open-pioneer/core": "^1.3.0",
|
|
19
|
+
"@open-pioneer/react-utils": "^1.0.1",
|
|
20
|
+
"@open-pioneer/runtime": "^2.1.7",
|
|
21
21
|
"classnames": "^2.3.2",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
22
|
+
"ol": "^9.2.4",
|
|
23
|
+
"react": "^18.3.1",
|
|
24
|
+
"@open-pioneer/map": "^0.6.1"
|
|
24
25
|
},
|
|
25
26
|
"exports": {
|
|
26
27
|
"./package.json": "./package.json",
|