@mapcomponents/react-maplibre 0.1.12 → 0.1.16
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/.github/workflows/storybook.yml +4 -2
- package/CHANGELOG.md +33 -0
- package/README.md +22 -6
- package/coverage/clover.xml +893 -760
- package/coverage/coverage-final.json +22 -17
- package/coverage/lcov-report/index.html +183 -123
- package/coverage/lcov-report/{components → src/components}/MapLibreMap/MapLibreMap.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MapLibreMap/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/MlCreatePdfButton.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/MlFeatureEditor.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlFollowGps/MlFollowGps.js.html +148 -136
- package/coverage/lcov-report/{components → src/components}/MlFollowGps/index.html +24 -24
- package/coverage/lcov-report/{components → src/components}/MlGPXViewer/MlGPXViewer.js.html +66 -60
- package/coverage/lcov-report/{components → src/components}/MlGPXViewer/gpxConverter.js.html +49 -70
- package/coverage/lcov-report/{components → src/components}/MlGPXViewer/index.html +25 -25
- package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/MlGeoJsonLayer.js.html +155 -47
- package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/index.html +28 -28
- package/coverage/lcov-report/{components/MlLayer/MlLayer.js.html → src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html} +88 -121
- package/coverage/lcov-report/{components → src/components}/MlImageMarkerLayer/index.html +28 -28
- package/coverage/lcov-report/{components/MlImageMarkerLayer/MlImageMarkerLayer.js.html → src/components/MlLayer/MlLayer.js.html} +116 -125
- package/coverage/lcov-report/src/components/MlLayer/index.html +117 -0
- package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/MlLayerMagnify.js.html +41 -41
- package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/index.html +24 -24
- package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/MlLayerSwipe.js.html +38 -41
- package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/index.html +24 -24
- package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +755 -0
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +380 -0
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +117 -0
- package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +117 -0
- package/coverage/lcov-report/{components → src/components}/MlMarker/MlMarker.js.html +11 -11
- package/coverage/lcov-report/{components → src/components}/MlMarker/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/MlNavigationCompass.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlNavigationTools/MlNavigationTools.js.html +50 -41
- package/coverage/lcov-report/{components → src/components}/MlNavigationTools/index.html +18 -18
- package/coverage/lcov-report/{components → src/components}/MlOsmLayer/MlOsmLayer.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlOsmLayer/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlScaleReference/MlScaleReference.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlScaleReference/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlShareMapState/MlShareMapState.js.html +217 -25
- package/coverage/lcov-report/{components → src/components}/MlShareMapState/index.html +18 -18
- package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/MlThreeJsLayer.js.html +30 -54
- package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/index.html +24 -24
- package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/MlUseMapDebugger.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/MlVectorTileLayer.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/index.html +10 -10
- package/coverage/lcov-report/{components → src/components}/MlWmsLayer/MlWmsLayer.js.html +13 -13
- package/coverage/lcov-report/{components → src/components}/MlWmsLayer/index.html +14 -14
- package/coverage/lcov-report/{components → src/components}/MlWmsLoader/MlWmsLoader.js.html +31 -19
- package/coverage/lcov-report/{components → src/components}/MlWmsLoader/index.html +16 -16
- package/coverage/lcov-report/src/hooks/index.html +147 -0
- package/coverage/lcov-report/src/hooks/useMap.js.html +296 -0
- package/coverage/lcov-report/{hooks → src/hooks}/useMapState.js.html +91 -91
- package/coverage/lcov-report/{hooks → src/hooks}/useWms.js.html +18 -18
- package/coverage/lcov-report/src/i18n.js.html +167 -0
- package/coverage/lcov-report/src/index.html +117 -0
- package/coverage/lcov-report/src/translations/english.js.html +95 -0
- package/coverage/lcov-report/src/translations/german.js.html +95 -0
- package/coverage/lcov-report/src/translations/index.html +132 -0
- package/coverage/lcov.info +1610 -1314
- package/dist/b556faa3bc6829d2.png +0 -0
- package/dist/index.esm.js +934 -668
- package/dist/index.esm.js.map +1 -1
- package/package.json +3 -1
- package/public/assets/dop.png +0 -0
- package/public/assets/historic.png +0 -0
- package/public/assets/osm.png +0 -0
- package/public/thumbnails/MlFollowGps.png +0 -0
- package/public/thumbnails/MlThreeJsLayer.png +0 -0
- package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +53 -67
- package/src/components/MlComponentTemplate/MlComponentTemplate.js +6 -31
- package/src/components/MlFeatureEditor/MlFeatureEditor.meta.json +2 -2
- package/src/components/MlFollowGps/MlFollowGps.js +92 -88
- package/src/components/MlFollowGps/MlFollowGps.meta.json +2 -2
- package/src/components/MlFollowGps/MlFollowGps.test.js +3 -5
- package/src/components/MlFollowGps/assets/marker.png +0 -0
- package/src/components/MlGPXViewer/MlGPXViewer.js +45 -43
- package/src/components/MlGPXViewer/gpxConverter.js +22 -29
- package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +45 -9
- package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +21 -57
- package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.test.js +6 -7
- package/src/components/MlLayer/MlLayer.js +28 -6
- package/src/components/MlLayer/MlLayer.test.js +12 -10
- package/src/components/MlLayerMagnify/MlLayerMagnify.js +3 -3
- package/src/components/MlLayerSwipe/MlLayerSwipe.js +4 -5
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.css +17 -0
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.doc.de.md +3 -0
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +223 -0
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.meta_.json +15 -0
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.stories.js +106 -0
- package/src/components/MlLayerSwitcher/assets/sample_1.json +26 -0
- package/src/components/MlLayerSwitcher/assets/sample_2.json +22 -0
- package/src/components/MlLayerSwitcher/components/LayerBox.js +98 -0
- package/src/components/MlMarker/MlMarker.js +1 -1
- package/src/components/MlNavigationTools/MlNavigationTools.js +29 -26
- package/src/components/MlScaleReference/MlScaleReference.meta.json +1 -1
- package/src/components/MlScaleReference/MlScaleReference.stories.js +25 -21
- package/src/components/MlShareMapState/MlShareMapState.js +73 -9
- package/src/components/MlShareMapState/MlShareMapState.stories.js +24 -1
- package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.js +12 -6
- package/src/components/MlThreeJsLayer/MlThreeJsLayer.js +8 -15
- package/src/components/MlWmsLayer/MlWmsLayer.js +1 -1
- package/src/components/MlWmsLoader/MlWmsLoader.js +8 -4
- package/src/components/MlWmsLoader/MlWmsLoader.meta.json +1 -1
- package/src/components/MlWmsLoader/MlWmsLoader.stories.js +5 -4
- package/src/decorators/EmptyMapContextDecorator.js +11 -6
- package/src/decorators/MapContext3DDecorator.js +25 -20
- package/src/decorators/MapContextDashboardDecorator.js +7 -2
- package/src/decorators/MapContextDecorator.js +7 -3
- package/src/decorators/MapContextKlokantechBasicDecorator.js +8 -4
- package/src/decorators/MultiMapContextDecorator.js +2 -1
- package/src/hooks/useMap.js +33 -62
- package/src/hooks/useMapState.js +3 -3
- package/src/hooks/useWms.js +7 -6
- package/src/i18n.js +28 -0
- package/src/index.js +3 -0
- package/src/translations/english.js +4 -0
- package/src/translations/german.js +4 -0
- package/src/ui_components/ImageLoader.js +73 -0
- package/src/ui_components/Sidebar.js +75 -20
- package/src/ui_components/TopToolbar.js +18 -18
- package/coverage/lcov-report/components/MlLayer/index.html +0 -117
- package/coverage/lcov-report/hooks/index.html +0 -147
- package/coverage/lcov-report/hooks/useMap.js.html +0 -383
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mapcomponents/react-maplibre",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"@emotion/css": "^11.1.3",
|
|
10
10
|
"@emotion/react": "^11.4.1",
|
|
11
11
|
"@emotion/styled": "^11.3.0",
|
|
12
|
+
"@fontsource/roboto": "^4.5.1",
|
|
12
13
|
"@mapbox/mapbox-gl-draw": "^1.2.0",
|
|
13
14
|
"@mapbox/mapbox-gl-sync-move": "^0.3.0",
|
|
14
15
|
"@mapcomponents/react-core": "^0.1.1",
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
"@turf/turf": "^6.5.0",
|
|
19
20
|
"jspdf": "^2.3.0",
|
|
20
21
|
"maplibre-gl": "^1.13.0-rc.5",
|
|
22
|
+
"react-i18next": "^11.14.3",
|
|
21
23
|
"three": "^0.126.1",
|
|
22
24
|
"uuid": "^8.3.2",
|
|
23
25
|
"wms-capabilities": "^0.5.1",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-ignore: TS export Problem to be fixed upstream
|
|
1
2
|
import maplibregl from "maplibre-gl/dist/maplibre-gl";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -41,7 +42,7 @@ const MapLibreGlWrapper = function (props) {
|
|
|
41
42
|
on: (eventName, handler, options, componentId) => {
|
|
42
43
|
if (!self.eventHandlers[eventName]) return;
|
|
43
44
|
|
|
44
|
-
if(typeof options ===
|
|
45
|
+
if (typeof options === "string") {
|
|
45
46
|
componentId = options;
|
|
46
47
|
options = {};
|
|
47
48
|
}
|
|
@@ -91,7 +92,7 @@ const MapLibreGlWrapper = function (props) {
|
|
|
91
92
|
/**
|
|
92
93
|
* Array containing an object for each layer in the MapLibre instance providing information on visibility, loading state, order, paint & layout properties
|
|
93
94
|
*/
|
|
94
|
-
layerState:
|
|
95
|
+
layerState: [],
|
|
95
96
|
/**
|
|
96
97
|
* Maps layerIds to layerState in JSON string form for quick deep comparisons
|
|
97
98
|
*/
|
|
@@ -108,38 +109,38 @@ const MapLibreGlWrapper = function (props) {
|
|
|
108
109
|
*/
|
|
109
110
|
buildLayerObject: (layer) => {
|
|
110
111
|
//if (self.baseLayers.indexOf(layer.id) === -1) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
112
|
+
let paint = {};
|
|
113
|
+
let values = layer.paint?._values;
|
|
114
|
+
Object.keys(values || {}).map((propName) => {
|
|
115
|
+
paint[propName] =
|
|
116
|
+
typeof values[propName].value !== "undefined"
|
|
117
|
+
? values[propName].value.value
|
|
118
|
+
: values[propName];
|
|
119
|
+
});
|
|
120
|
+
let layout = {};
|
|
121
|
+
values = layer.layout?._values;
|
|
122
|
+
Object.keys(values || {}).map((propName) => {
|
|
123
|
+
layout[propName] =
|
|
124
|
+
typeof values[propName].value !== "undefined"
|
|
125
|
+
? values[propName].value.value
|
|
126
|
+
: values[propName];
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
id: layer.id,
|
|
130
|
+
type: layer.type,
|
|
131
|
+
visible: layer.visibility === "none" ? false : true,
|
|
132
|
+
baseLayer: self.baseLayers.indexOf(layer.id) !== -1,
|
|
133
|
+
paint,
|
|
134
|
+
layout,
|
|
135
|
+
//filter: layers[layerId].filter,
|
|
136
|
+
//layout: layers[layerId].layout,
|
|
137
|
+
//maxzoom: layers[layerId].maxzoom,
|
|
138
|
+
//metadata: layers[layerId].metadata,
|
|
139
|
+
//minzoom: layers[layerId].minzoom,
|
|
140
|
+
//paint: layers[layerId].paint.get(),
|
|
141
|
+
//source: layers[layerId].source,
|
|
142
|
+
//sourceLayer: layers[layerId].sourceLayer,
|
|
143
|
+
};
|
|
143
144
|
//}
|
|
144
145
|
},
|
|
145
146
|
/**
|
|
@@ -159,7 +160,7 @@ const MapLibreGlWrapper = function (props) {
|
|
|
159
160
|
*/
|
|
160
161
|
refreshLayerState: () => {
|
|
161
162
|
self.wrapper.layerState = self.wrapper.buildLayerObjects();
|
|
162
|
-
self.wrapper.layerStateStrings = self.wrapper.layerState.map(el => JSON.stringify(el));
|
|
163
|
+
self.wrapper.layerStateStrings = self.wrapper.layerState.map((el) => JSON.stringify(el));
|
|
163
164
|
},
|
|
164
165
|
/**
|
|
165
166
|
* Object containing information on the current viewport state
|
|
@@ -173,29 +174,17 @@ const MapLibreGlWrapper = function (props) {
|
|
|
173
174
|
* Previous version of viewportStateString
|
|
174
175
|
*/
|
|
175
176
|
oldViewportStateString: "{}",
|
|
176
|
-
getViewport: () =>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
viewportRefreshWaiting: false,
|
|
184
|
-
refreshViewport: (force) => {
|
|
185
|
-
if (self.wrapper.viewportRefreshEnabled || force) {
|
|
186
|
-
self.wrapper.viewportRefreshEnabled = false;
|
|
187
|
-
self.wrapper.viewportState = self.wrapper.getViewport();
|
|
188
|
-
self.wrapper.viewportStateString = JSON.stringify(self.wrapper.viewportState);
|
|
189
|
-
setTimeout(() => {
|
|
190
|
-
self.wrapper.viewportRefreshEnabled = true;
|
|
191
|
-
if (self.wrapper.viewportRefreshWaiting) {
|
|
192
|
-
self.wrapper.viewportRefreshWaiting = false;
|
|
193
|
-
self.wrapper.refreshViewport();
|
|
177
|
+
getViewport: () =>
|
|
178
|
+
typeof self.map.getCenter === "function"
|
|
179
|
+
? {
|
|
180
|
+
center: (({ lng, lat, ...rest }) => ({ lng, lat }))(self.map.getCenter()),
|
|
181
|
+
zoom: self.map.getZoom(),
|
|
182
|
+
bearing: self.map.getBearing(),
|
|
183
|
+
pitch: self.map.getPitch(),
|
|
194
184
|
}
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
185
|
+
: {},
|
|
186
|
+
refreshViewport: () => {
|
|
187
|
+
self.wrapper.viewportState = self.wrapper.getViewport();
|
|
199
188
|
},
|
|
200
189
|
};
|
|
201
190
|
|
|
@@ -484,10 +473,10 @@ const MapLibreGlWrapper = function (props) {
|
|
|
484
473
|
) {
|
|
485
474
|
await fetch(props.mapOptions.style)
|
|
486
475
|
.then((response) => {
|
|
487
|
-
if(response.ok){
|
|
488
|
-
return response.json()
|
|
489
|
-
}else{
|
|
490
|
-
throw new Error(
|
|
476
|
+
if (response.ok) {
|
|
477
|
+
return response.json();
|
|
478
|
+
} else {
|
|
479
|
+
throw new Error("error loading map style.json");
|
|
491
480
|
}
|
|
492
481
|
})
|
|
493
482
|
.then((styleJson) => {
|
|
@@ -508,15 +497,12 @@ const MapLibreGlWrapper = function (props) {
|
|
|
508
497
|
self.map = new maplibregl.Map(props.mapOptions);
|
|
509
498
|
|
|
510
499
|
self.addNativeMaplibreFunctionsAndProps();
|
|
511
|
-
self.wrapper.refreshViewport(
|
|
500
|
+
self.wrapper.refreshViewport();
|
|
512
501
|
self.wrapper.fire("viewportchange");
|
|
513
502
|
|
|
514
503
|
self.map.on("move", () => {
|
|
515
|
-
self.wrapper.
|
|
516
|
-
|
|
517
|
-
self.wrapper.oldViewportStateString = self.wrapper.viewportStateString;
|
|
518
|
-
self.wrapper.fire("viewportchange");
|
|
519
|
-
}
|
|
504
|
+
self.wrapper.viewportState = self.wrapper.getViewport();
|
|
505
|
+
self.wrapper.fire("viewportchange");
|
|
520
506
|
});
|
|
521
507
|
self.map.on("data", () => {
|
|
522
508
|
self.wrapper.refreshLayerState();
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React, { useRef, useEffect, useContext } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
-
|
|
4
|
-
import { MapContext } from "@mapcomponents/react-core";
|
|
5
|
-
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import useMap from "../../hooks/useMap";
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* TODO: Add short & useful description
|
|
@@ -13,40 +11,17 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
13
11
|
* @component
|
|
14
12
|
*/
|
|
15
13
|
const MlComponentTemplate = (props) => {
|
|
16
|
-
|
|
17
|
-
const mapContext = useContext(MapContext);
|
|
18
|
-
|
|
14
|
+
const mapHook = useMap({mapId: props.mapId, waitForLayer: props.insertBeforeLayer});
|
|
19
15
|
const initializedRef = useRef(false);
|
|
20
|
-
const mapRef = useRef(undefined);
|
|
21
|
-
const componentId = useRef((props.idPrefix ? props.idPrefix : "MlComponentTemplate-") + uuidv4());
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
let _componentId = componentId.current;
|
|
25
|
-
|
|
26
|
-
return () => {
|
|
27
|
-
// This is the cleanup function, it is called when this react component is removed from react-dom
|
|
28
|
-
// try to remove anything this component has added to the MapLibre-gl instance
|
|
29
|
-
// e.g.: remove the layer
|
|
30
|
-
// mapContext.getMap(props.mapId).removeLayer(layerRef.current);
|
|
31
|
-
// check for the existence of map.style before calling getLayer or getSource
|
|
32
|
-
|
|
33
|
-
if (mapRef.current) {
|
|
34
|
-
mapRef.current.cleanup(_componentId);
|
|
35
|
-
mapRef.current = undefined;
|
|
36
|
-
}
|
|
37
|
-
initializedRef.current = false;
|
|
38
|
-
};
|
|
39
|
-
}, []);
|
|
40
16
|
|
|
41
17
|
useEffect(() => {
|
|
42
|
-
if (!
|
|
43
|
-
// the MapLibre-gl instance (
|
|
18
|
+
if (!mapHook.mapIsReady || initializedRef.current) return;
|
|
19
|
+
// the MapLibre-gl instance (mapHook.map) is accessible here
|
|
44
20
|
// initialize the layer and add it to the MapLibre-gl instance or do something else with it
|
|
45
21
|
initializedRef.current = true;
|
|
46
|
-
mapRef.current = mapContext.getMap(props.mapId);
|
|
47
22
|
|
|
48
|
-
|
|
49
|
-
}, [
|
|
23
|
+
mapHook.map.setCenter([7.132122000552613, 50.716405378037706]);
|
|
24
|
+
}, [mapHook.map, props.mapId]);
|
|
50
25
|
|
|
51
26
|
return <></>;
|
|
52
27
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "MlFeatureEditor",
|
|
3
|
-
"title": "Sketch
|
|
3
|
+
"title": "Sketch tools",
|
|
4
4
|
"description": "Enables the editing of Point, Linestring and Polygon GeoJSON Files.",
|
|
5
5
|
"i18n": {
|
|
6
6
|
"de": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"description": "Ermöglicht das Bearbeiten von Punkt, Linestring und Polygon GeoJSON Daten."
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"tags": [
|
|
11
|
+
"tags": ["Map add-on"],
|
|
12
12
|
"category": "add-ons",
|
|
13
13
|
"type": "component",
|
|
14
14
|
"price": 0
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import React, {useRef, useEffect,
|
|
1
|
+
import React, { useRef, useEffect, useState, useCallback } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
+
import useMap from "../../hooks/useMap";
|
|
3
4
|
|
|
4
|
-
import {MapContext} from "@mapcomponents/react-core";
|
|
5
|
-
import {v4 as uuidv4} from "uuid";
|
|
6
5
|
import Button from "@mui/material/Button";
|
|
7
6
|
import RoomIcon from "@mui/icons-material/Room";
|
|
8
|
-
import {point} from "@turf/turf"
|
|
7
|
+
import { point, circle } from "@turf/turf";
|
|
9
8
|
import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
|
|
10
9
|
import MlImageMarkerLayer from "../MlImageMarkerLayer/MlImageMarkerLayer";
|
|
11
10
|
|
|
11
|
+
import marker from "./assets/marker.png";
|
|
12
|
+
|
|
12
13
|
/**
|
|
13
14
|
* Adds a button that makes the map follow the users GPS position using
|
|
14
15
|
* navigator.geolocation.watchPosition if activated
|
|
@@ -19,121 +20,97 @@ import MlImageMarkerLayer from "../MlImageMarkerLayer/MlImageMarkerLayer";
|
|
|
19
20
|
* @component
|
|
20
21
|
*/
|
|
21
22
|
const MlFollowGps = (props) => {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
|
|
24
|
+
|
|
24
25
|
const [isFollowed, setIsFollowed] = useState(false);
|
|
25
26
|
const [geoJson, setGeoJson] = useState(undefined);
|
|
26
27
|
const watchIdRef = useRef(undefined);
|
|
27
28
|
const [locationAccessDenied, setLocationAccessDenied] = useState(false);
|
|
28
29
|
|
|
29
|
-
const
|
|
30
|
-
const mapRef = useRef(undefined);
|
|
31
|
-
const componentId = useRef((props.idPrefix ? props.idPrefix : "MlFollowGps-") + uuidv4());
|
|
32
|
-
const [accuracyRadius, setAccuracyRadius] = useState(30);
|
|
30
|
+
const [accuracyGeoJson, setAccuracyGeoJson] = useState();
|
|
33
31
|
|
|
34
32
|
useEffect(() => {
|
|
35
|
-
let _componentId = componentId.current;
|
|
36
|
-
|
|
37
|
-
|
|
38
33
|
return () => {
|
|
39
|
-
// This is the cleanup function, it is called when this react component is removed from react-dom
|
|
40
|
-
// try to remove anything this component has added to the MapLibre-gl instance
|
|
41
|
-
// e.g.: remove the layer
|
|
42
|
-
// mapContext.getMap(props.mapId).removeLayer(layerRef.current);
|
|
43
|
-
// check for the existence of map.style before calling getLayer or getSource
|
|
44
|
-
|
|
45
|
-
if (mapRef.current) {
|
|
46
|
-
mapRef.current.cleanup(_componentId);
|
|
47
|
-
mapRef.current = undefined;
|
|
48
|
-
}
|
|
49
34
|
if (watchIdRef.current) {
|
|
50
|
-
initializedRef.current = false;
|
|
51
35
|
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
52
36
|
watchIdRef.current = undefined;
|
|
53
37
|
}
|
|
54
38
|
};
|
|
55
39
|
}, []);
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!mapRef.current) return;
|
|
69
|
-
mapRef.current.setCenter([pos.coords.longitude, pos.coords.latitude]);
|
|
70
|
-
setAccuracyRadius(pos.coords.accuracy)
|
|
71
|
-
setGeoJson(point([pos.coords.longitude, pos.coords.latitude]));
|
|
72
|
-
};
|
|
41
|
+
const getLocationSuccess = useCallback(
|
|
42
|
+
(pos) => {
|
|
43
|
+
if (!mapHook.map) return;
|
|
44
|
+
|
|
45
|
+
mapHook.map.setCenter([pos.coords.longitude, pos.coords.latitude]);
|
|
46
|
+
const geoJsonPoint = point([pos.coords.longitude, pos.coords.latitude]);
|
|
47
|
+
setGeoJson(geoJsonPoint);
|
|
48
|
+
setAccuracyGeoJson(circle(geoJsonPoint, pos.coords.accuracy / 1000));
|
|
49
|
+
},
|
|
50
|
+
[mapHook.map]
|
|
51
|
+
);
|
|
73
52
|
|
|
74
53
|
const getLocationError = (err) => {
|
|
75
54
|
console.log("Access of user location denied");
|
|
76
55
|
setLocationAccessDenied(true);
|
|
77
56
|
};
|
|
78
57
|
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!mapHook.map) return;
|
|
60
|
+
|
|
61
|
+
if (isFollowed) {
|
|
62
|
+
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
63
|
+
getLocationSuccess,
|
|
64
|
+
getLocationError
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
68
|
+
}
|
|
69
|
+
}, [isFollowed, getLocationSuccess]);
|
|
70
|
+
|
|
79
71
|
return (
|
|
80
72
|
<>
|
|
81
|
-
{isFollowed && geoJson &&
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"icon-offset": [0, -340]
|
|
113
|
-
},
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
imgSrc={"/assets/marker.png"}
|
|
117
|
-
/>
|
|
118
|
-
}
|
|
73
|
+
{isFollowed && geoJson && (
|
|
74
|
+
<MlGeoJsonLayer
|
|
75
|
+
geojson={accuracyGeoJson}
|
|
76
|
+
type={"fill"}
|
|
77
|
+
paint={{
|
|
78
|
+
"fill-color": "#ee7700",
|
|
79
|
+
"fill-opacity": 0.5,
|
|
80
|
+
...props.accuracyPaint,
|
|
81
|
+
}}
|
|
82
|
+
insertBeforeLayer={"MlFollowGpsMarker"}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{isFollowed && geoJson && (
|
|
87
|
+
<MlImageMarkerLayer
|
|
88
|
+
layerId={"MlFollowGpsMarker"}
|
|
89
|
+
options={{
|
|
90
|
+
type: "symbol",
|
|
91
|
+
source: {
|
|
92
|
+
type: "geojson",
|
|
93
|
+
data: geoJson,
|
|
94
|
+
},
|
|
95
|
+
layout: {
|
|
96
|
+
"icon-size": 0.1,
|
|
97
|
+
"icon-offset": [0, -340],
|
|
98
|
+
...props.markerLayout,
|
|
99
|
+
},
|
|
100
|
+
}}
|
|
101
|
+
imgSrc={props.markerImage || marker}
|
|
102
|
+
/>
|
|
103
|
+
)}
|
|
119
104
|
|
|
120
105
|
<Button
|
|
121
|
-
sx={{zIndex: 1002, color: isFollowed ?
|
|
106
|
+
sx={{ zIndex: 1002, color: isFollowed ? props.onColor : props.offColor, ...props.style }}
|
|
122
107
|
disabled={locationAccessDenied}
|
|
123
108
|
onClick={() => {
|
|
124
|
-
if (isFollowed) {
|
|
125
|
-
navigator.geolocation.clearWatch(watchIdRef.current);
|
|
126
|
-
} else {
|
|
127
|
-
watchIdRef.current = navigator.geolocation.watchPosition(
|
|
128
|
-
getLocationSuccess,
|
|
129
|
-
getLocationError
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
109
|
setIsFollowed(!isFollowed);
|
|
133
110
|
}}
|
|
134
111
|
>
|
|
135
112
|
{" "}
|
|
136
|
-
<RoomIcon sx={{}}/>{" "}
|
|
113
|
+
<RoomIcon sx={{ fontSize: props.style.fontSize }} />{" "}
|
|
137
114
|
</Button>
|
|
138
115
|
</>
|
|
139
116
|
);
|
|
@@ -149,11 +126,14 @@ MlFollowGps.defaultProps = {
|
|
|
149
126
|
backgroundColor: "#414141",
|
|
150
127
|
borderRadius: "23%",
|
|
151
128
|
margin: 0.15,
|
|
129
|
+
fontSize: "1.3em",
|
|
152
130
|
":hover": {
|
|
153
131
|
backgroundColor: "#515151",
|
|
154
132
|
color: "#ececec",
|
|
155
133
|
},
|
|
156
134
|
},
|
|
135
|
+
onColor: "#ececec",
|
|
136
|
+
offColor: "#666",
|
|
157
137
|
};
|
|
158
138
|
|
|
159
139
|
MlFollowGps.propTypes = {
|
|
@@ -165,5 +145,29 @@ MlFollowGps.propTypes = {
|
|
|
165
145
|
* CSS style object that is applied to the button component
|
|
166
146
|
*/
|
|
167
147
|
style: PropTypes.object,
|
|
148
|
+
/**
|
|
149
|
+
* Active button font color
|
|
150
|
+
*/
|
|
151
|
+
onColor: PropTypes.string,
|
|
152
|
+
/**
|
|
153
|
+
* Inactive button font color
|
|
154
|
+
*/
|
|
155
|
+
offColor: PropTypes.string,
|
|
156
|
+
/**
|
|
157
|
+
* Accuracy paint property object, that is passed to the MlGeoJsonLayer responsible for drawing the accuracy circle.
|
|
158
|
+
* Use any available paint prop from layer type "fill".
|
|
159
|
+
* https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#fill
|
|
160
|
+
*/
|
|
161
|
+
accuracyPaint: PropTypes.object,
|
|
162
|
+
/**
|
|
163
|
+
* Marker layout property object, that is passed to the MlImageMarkerLayer responsible for drawing the position marker.
|
|
164
|
+
* Use any available layout property from layer type "symbol".
|
|
165
|
+
* https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#symbol
|
|
166
|
+
*/
|
|
167
|
+
markerLayout: PropTypes.object,
|
|
168
|
+
/**
|
|
169
|
+
* Replace the default marker image with a custom one.
|
|
170
|
+
*/
|
|
171
|
+
markerImage: PropTypes.string,
|
|
168
172
|
};
|
|
169
173
|
export default MlFollowGps;
|
|
@@ -6,14 +6,12 @@ import MlFollowGps from "./MlFollowGps";
|
|
|
6
6
|
import MapLibreMap from "./../MapLibreMap/MapLibreMap";
|
|
7
7
|
|
|
8
8
|
const mockGeolocation = {
|
|
9
|
-
watchPosition: jest.fn(),
|
|
9
|
+
watchPosition: jest.fn(() => 1),
|
|
10
10
|
clearWatch: jest.fn(),
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
|
|
13
13
|
global.navigator.geolocation = mockGeolocation;
|
|
14
14
|
|
|
15
|
-
global.navigator.geolocation.watchPosition.mockReturnValue(1);
|
|
16
|
-
|
|
17
15
|
const MlFollowGPSTestComponent = (props) => {
|
|
18
16
|
const [componentVisible, setComponentVisible] = useState(true);
|
|
19
17
|
|
|
@@ -60,6 +58,6 @@ describe("<MlFollowGps>", () => {
|
|
|
60
58
|
wrapper.find("MlFollowGps button").simulate("click");
|
|
61
59
|
//wrapper.find(".toggle_layer_visible").simulate("click");
|
|
62
60
|
|
|
63
|
-
await waitFor(() => expect(mockGeolocation.clearWatch).toHaveBeenCalledTimes(
|
|
61
|
+
await waitFor(() => expect(mockGeolocation.clearWatch).toHaveBeenCalledTimes(2));
|
|
64
62
|
});
|
|
65
63
|
});
|
|
Binary file
|