@mapcomponents/react-maplibre 0.1.20 → 0.1.24
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 +13 -0
- package/coverage/clover.xml +195 -198
- package/coverage/coverage-final.json +6 -6
- package/coverage/lcov-report/index.html +31 -31
- package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.js.html +1 -1
- package/coverage/lcov-report/src/components/MapLibreMap/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.js.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.js.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.js.html +1 -1
- package/coverage/lcov-report/src/components/MlFollowGps/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js.html +4 -4
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/MlLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/MlMarker.js.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.js.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.js.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/index.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +1 -1
- package/coverage/lcov-report/src/components/MlScaleReference/index.html +1 -1
- package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +261 -111
- package/coverage/lcov-report/src/components/MlShareMapState/index.html +9 -9
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +1 -1
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
- package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.js.html +94 -124
- package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +17 -17
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.js.html +35 -89
- package/coverage/lcov-report/src/components/MlWmsLayer/index.html +17 -17
- package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.js.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLoader/index.html +1 -1
- package/coverage/lcov-report/src/hooks/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useMap.js.html +23 -23
- package/coverage/lcov-report/src/hooks/useMapState.js.html +34 -34
- package/coverage/lcov-report/src/hooks/useWms.js.html +1 -1
- package/coverage/lcov-report/src/i18n.js.html +1 -1
- package/coverage/lcov-report/src/index.html +1 -1
- package/coverage/lcov-report/src/translations/english.js.html +1 -1
- package/coverage/lcov-report/src/translations/german.js.html +1 -1
- package/coverage/lcov-report/src/translations/index.html +1 -1
- package/coverage/lcov.info +334 -329
- package/dist/index.esm.js +86 -106
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/scripts/build-catalogue-markdown-docs.js +5 -3
- package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +26 -21
- package/src/components/MapLibreMap/lib/MapLibreGlWrapper.test.js +3 -3
- package/src/components/MlCreatePdfButton/MlCreatePdfButton.doc.de.md +2 -2
- package/src/components/MlCreatePdfButton/MlCreatePdfButton.doc.en.md +3 -0
- package/src/components/MlFeatureEditor/MlFeatureEditor.test.js +2 -2
- package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +3 -3
- package/src/components/MlNavigationCompass/MlNavigationCompass.test.js +2 -2
- package/src/components/MlShareMapState/MlShareMapState.js +138 -88
- package/src/components/MlShareMapState/MlShareMapState.stories.js +79 -29
- package/src/components/MlVectorTileLayer/MlVectorTileLayer.js +65 -75
- package/src/components/MlVectorTileLayer/MlVectorTileLayer.test.js +6 -6
- package/src/components/MlWmsLayer/MlWmsLayer.js +16 -34
- package/src/hooks/useMap.js +1 -1
package/package.json
CHANGED
|
@@ -7,19 +7,21 @@ let options = {};
|
|
|
7
7
|
function getComponentNameFromPath(path) {
|
|
8
8
|
let tmp = path.split("/");
|
|
9
9
|
tmp = tmp[tmp.length - 1];
|
|
10
|
-
|
|
10
|
+
tmp = tmp.split(".doc");
|
|
11
|
+
return tmp[0];
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const converter = new showdown.Converter();
|
|
14
15
|
|
|
15
|
-
glob("src/components/**/*.doc
|
|
16
|
+
glob("src/components/**/*.doc.*.md", options, function (er, files) {
|
|
16
17
|
console.log(files);
|
|
17
18
|
|
|
18
19
|
for (var i = 0, len = files.length; i < len; i++) {
|
|
20
|
+
let language = files[i].slice(-5, -3);
|
|
19
21
|
let rawdata = fs.readFileSync(files[i]);
|
|
20
22
|
let html = converter.makeHtml(rawdata + "");
|
|
21
23
|
fs.writeFileSync(
|
|
22
|
-
"public/catalogue/" + getComponentNameFromPath(files[i]) + ".
|
|
24
|
+
"public/catalogue/" + getComponentNameFromPath(files[i]) + "." + language + ".html",
|
|
23
25
|
html
|
|
24
26
|
);
|
|
25
27
|
}
|
|
@@ -97,7 +97,7 @@ const MapLibreGlWrapper = function (props) {
|
|
|
97
97
|
/**
|
|
98
98
|
* Maps layerIds to layerState in JSON string form for quick deep comparisons
|
|
99
99
|
*/
|
|
100
|
-
|
|
100
|
+
layerStateString: "",
|
|
101
101
|
/**
|
|
102
102
|
* Previous Version of layerStateString
|
|
103
103
|
*/
|
|
@@ -110,29 +110,29 @@ const MapLibreGlWrapper = function (props) {
|
|
|
110
110
|
*/
|
|
111
111
|
buildLayerObject: (layer) => {
|
|
112
112
|
//if (self.baseLayers.indexOf(layer.id) === -1) {
|
|
113
|
-
let paint = {};
|
|
114
|
-
let values = layer.paint?._values;
|
|
115
|
-
Object.keys(values || {}).
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
});
|
|
121
|
-
let layout = {};
|
|
122
|
-
values = layer.layout?._values;
|
|
123
|
-
Object.keys(values || {}).
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
});
|
|
113
|
+
//let paint = {};
|
|
114
|
+
//let values = layer.paint?._values;
|
|
115
|
+
//Object.keys(values || {}).map((propName) => {
|
|
116
|
+
// paint[propName] =
|
|
117
|
+
// typeof values[propName].value !== "undefined"
|
|
118
|
+
// ? values[propName].value.value
|
|
119
|
+
// : values[propName];
|
|
120
|
+
//});
|
|
121
|
+
//let layout = {};
|
|
122
|
+
//values = layer.layout?._values;
|
|
123
|
+
//Object.keys(values || {}).map((propName) => {
|
|
124
|
+
// layout[propName] =
|
|
125
|
+
// typeof values[propName].value !== "undefined"
|
|
126
|
+
// ? values[propName].value.value
|
|
127
|
+
// : values[propName];
|
|
128
|
+
//});
|
|
129
129
|
return {
|
|
130
130
|
id: layer.id,
|
|
131
131
|
type: layer.type,
|
|
132
132
|
visible: layer.visibility === "none" ? false : true,
|
|
133
133
|
baseLayer: self.baseLayers.indexOf(layer.id) !== -1,
|
|
134
|
-
paint,
|
|
135
|
-
layout,
|
|
134
|
+
//paint,
|
|
135
|
+
//layout,
|
|
136
136
|
//filter: layers[layerId].filter,
|
|
137
137
|
//layout: layers[layerId].layout,
|
|
138
138
|
//maxzoom: layers[layerId].maxzoom,
|
|
@@ -161,7 +161,10 @@ const MapLibreGlWrapper = function (props) {
|
|
|
161
161
|
*/
|
|
162
162
|
refreshLayerState: () => {
|
|
163
163
|
self.wrapper.layerState = self.wrapper.buildLayerObjects();
|
|
164
|
-
self.wrapper.
|
|
164
|
+
if (JSON.stringify(self.wrapper.layerState) !== self.wrapper.layerStateString) {
|
|
165
|
+
self.wrapper.fire("layerchange");
|
|
166
|
+
self.wrapper.layerStateString = JSON.stringify(self.wrapper.layerState);
|
|
167
|
+
}
|
|
165
168
|
},
|
|
166
169
|
/**
|
|
167
170
|
* Object containing information on the current viewport state
|
|
@@ -505,9 +508,11 @@ const MapLibreGlWrapper = function (props) {
|
|
|
505
508
|
self.wrapper.viewportState = self.wrapper.getViewport();
|
|
506
509
|
self.wrapper.fire("viewportchange");
|
|
507
510
|
});
|
|
511
|
+
self.map.on("idle", () => {
|
|
512
|
+
self.wrapper.refreshLayerState();
|
|
513
|
+
});
|
|
508
514
|
self.map.on("data", () => {
|
|
509
515
|
self.wrapper.refreshLayerState();
|
|
510
|
-
self.wrapper.fire("layerchange");
|
|
511
516
|
});
|
|
512
517
|
if (typeof props.onReady === "function") {
|
|
513
518
|
props.onReady(self.map, self);
|
|
@@ -297,7 +297,7 @@ describe("MapLibreGlWrapper - event tests", () => {
|
|
|
297
297
|
);
|
|
298
298
|
|
|
299
299
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
300
|
-
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
300
|
+
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4);
|
|
301
301
|
});
|
|
302
302
|
|
|
303
303
|
it("should remove an event using off from MapLibreGl using MapLibreGlWrapper.cleanup(componentId)", async () => {
|
|
@@ -310,7 +310,7 @@ describe("MapLibreGlWrapper - event tests", () => {
|
|
|
310
310
|
);
|
|
311
311
|
|
|
312
312
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
313
|
-
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
313
|
+
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4);
|
|
314
314
|
|
|
315
315
|
wrapper.find(".toggle_children_are_visible").simulate("click");
|
|
316
316
|
|
|
@@ -327,7 +327,7 @@ describe("MapLibreGlWrapper - event tests", () => {
|
|
|
327
327
|
);
|
|
328
328
|
|
|
329
329
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
330
|
-
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
330
|
+
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(6);
|
|
331
331
|
|
|
332
332
|
wrapper.find(".toggle_children_are_visible").simulate("click");
|
|
333
333
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Beschreibung
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Export auf Knopfdruck ein PDF des aktuellen Kartenausschnitts.
|
|
@@ -82,7 +82,7 @@ describe("<MlFeatureEditor>", () => {
|
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
85
|
-
await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
85
|
+
await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(5));
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
it("should deregister 2 event listeners to the maplibre instance", async () => {
|
|
@@ -93,7 +93,7 @@ describe("<MlFeatureEditor>", () => {
|
|
|
93
93
|
);
|
|
94
94
|
|
|
95
95
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
96
|
-
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
96
|
+
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(5);
|
|
97
97
|
|
|
98
98
|
wrapper.find(".toggle_layer_visible").simulate("click");
|
|
99
99
|
|
|
@@ -139,15 +139,15 @@ const MlGeoJsonLayer = (props) => {
|
|
|
139
139
|
);
|
|
140
140
|
|
|
141
141
|
if (typeof props.onHover !== "undefined") {
|
|
142
|
-
mapHook.map.on("mousemove",
|
|
142
|
+
mapHook.map.on("mousemove", layerId.current, props.onHover, mapHook.componentId);
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
if (typeof props.onClick !== "undefined") {
|
|
146
|
-
mapHook.map.on("click",
|
|
146
|
+
mapHook.map.on("click", layerId.current, props.onClick, mapHook.componentId);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
if (typeof props.onLeave !== "undefined") {
|
|
150
|
-
mapHook.map.on("mouseleave",
|
|
150
|
+
mapHook.map.on("mouseleave", layerId.current, props.onLeave, mapHook.componentId);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
if (
|
|
@@ -48,7 +48,7 @@ describe("<MlNavigationCompass>", () => {
|
|
|
48
48
|
);
|
|
49
49
|
|
|
50
50
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
51
|
-
await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
51
|
+
await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4));
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it("should deregister 1 event listener to the maplibre instance", async () => {
|
|
@@ -59,7 +59,7 @@ describe("<MlNavigationCompass>", () => {
|
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
// MapLibreGlWrapper now subscribes to "data", "move" events on its own
|
|
62
|
-
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(
|
|
62
|
+
expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4);
|
|
63
63
|
|
|
64
64
|
wrapper.find(".toggle_layer_visible").simulate("click");
|
|
65
65
|
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
import React, {useRef, useEffect, useContext, useState} from "react";
|
|
1
|
+
import React, { useRef, useEffect, useContext, useState, useCallback } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
|
|
4
|
-
import {MapContext} from "@mapcomponents/react-core";
|
|
5
|
-
import {v4 as uuidv4} from "uuid";
|
|
4
|
+
import { MapContext } from "@mapcomponents/react-core";
|
|
5
|
+
import { v4 as uuidv4 } from "uuid";
|
|
6
6
|
import useMapState from "../../hooks/useMapState";
|
|
7
7
|
|
|
8
|
+
const getCurrentUrlParameters = () => {
|
|
9
|
+
let currentParams = Object.fromEntries(new URLSearchParams(window.location.search));
|
|
10
|
+
currentParams.layers = JSON.parse(currentParams?.layers ? currentParams.layers : "[]");
|
|
11
|
+
|
|
12
|
+
return currentParams;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const initialUrlParams = getCurrentUrlParameters();
|
|
16
|
+
|
|
8
17
|
/**
|
|
9
18
|
* TODO: Add short & useful description
|
|
10
19
|
*
|
|
@@ -19,24 +28,73 @@ const MlShareMapState = (props) => {
|
|
|
19
28
|
const initializedRef = useRef(false);
|
|
20
29
|
const mapRef = useRef(undefined);
|
|
21
30
|
const [map, setMap] = useState(undefined);
|
|
31
|
+
const layersFromUrlParamsRef = useRef({});
|
|
22
32
|
const componentId = useRef((props.idPrefix ? props.idPrefix : "MlShareMapState-") + uuidv4());
|
|
23
|
-
const [isInitialState, setIsInitialState] = useState(true);
|
|
24
33
|
const mapState = useMapState({
|
|
25
34
|
watch: {
|
|
26
35
|
viewport: false,
|
|
27
36
|
layers: true,
|
|
28
|
-
sources: false
|
|
37
|
+
sources: false,
|
|
29
38
|
},
|
|
30
39
|
filter: {
|
|
31
|
-
includeBaseLayers: false
|
|
32
|
-
}
|
|
33
|
-
})
|
|
40
|
+
includeBaseLayers: false,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const allStatesRestoredRef = useRef(false);
|
|
45
|
+
const layerStatesRestored = useRef(undefined);
|
|
46
|
+
const restoredStatesRef = useRef({
|
|
47
|
+
viewport: {
|
|
48
|
+
center: false,
|
|
49
|
+
bearing: false,
|
|
50
|
+
pitch: false,
|
|
51
|
+
zoom: false,
|
|
52
|
+
},
|
|
53
|
+
layers: {
|
|
54
|
+
...layersFromUrlParamsRef,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
34
57
|
|
|
58
|
+
// initial URL-Params
|
|
35
59
|
const mapStateRef = useRef({});
|
|
36
60
|
|
|
61
|
+
const refreshUrlParameters = useCallback(() => {
|
|
62
|
+
if (!props.active) return;
|
|
63
|
+
|
|
64
|
+
let mapLayers = [];
|
|
65
|
+
for (let x in mapState.layers) {
|
|
66
|
+
mapLayers.push({
|
|
67
|
+
id: mapState.layers[x].id,
|
|
68
|
+
type: mapState.layers[x].type,
|
|
69
|
+
visible: mapState.layers[x].visible,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
refreshMapState();
|
|
73
|
+
let urlParams = new URLSearchParams({
|
|
74
|
+
...getCurrentUrlParameters(),
|
|
75
|
+
...mapStateRef.current,
|
|
76
|
+
layers: JSON.stringify(mapLayers),
|
|
77
|
+
});
|
|
78
|
+
JSON.parse(Object.fromEntries(urlParams).layers).forEach((el) => {
|
|
79
|
+
layersFromUrlParamsRef.current[el.id] = false;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
let currentParams = new URLSearchParams(window.location.search);
|
|
83
|
+
checkRestorationStates(mapState.layers);
|
|
84
|
+
if (urlParams.toString() !== currentParams.toString()) {
|
|
85
|
+
window.history.pushState(
|
|
86
|
+
{ ...mapStateRef.current },
|
|
87
|
+
document.title,
|
|
88
|
+
"?" + urlParams.toString()
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}, [mapState.layers, props.active]);
|
|
92
|
+
|
|
37
93
|
useEffect(() => {
|
|
38
94
|
let _componentId = componentId.current;
|
|
39
95
|
|
|
96
|
+
mapStateRef.current = getCurrentUrlParameters();
|
|
97
|
+
|
|
40
98
|
return () => {
|
|
41
99
|
// This is the cleanup function, it is called when this react component is removed from react-dom
|
|
42
100
|
// try to remove anything this component has added to the MapLibre-gl instance
|
|
@@ -52,6 +110,24 @@ const MlShareMapState = (props) => {
|
|
|
52
110
|
};
|
|
53
111
|
}, []);
|
|
54
112
|
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (!mapRef.current) return;
|
|
115
|
+
|
|
116
|
+
refreshUrlParameters();
|
|
117
|
+
}, [refreshUrlParameters]);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!mapRef.current) return;
|
|
121
|
+
|
|
122
|
+
let _refreshUrlParameters = refreshUrlParameters;
|
|
123
|
+
|
|
124
|
+
mapRef.current.on("moveend", _refreshUrlParameters, componentId.current);
|
|
125
|
+
|
|
126
|
+
return () => {
|
|
127
|
+
mapRef.current?.off("moveend", _refreshUrlParameters);
|
|
128
|
+
};
|
|
129
|
+
}, [refreshUrlParameters, map]);
|
|
130
|
+
|
|
55
131
|
useEffect(() => {
|
|
56
132
|
if (!mapContext.mapExists(props.mapId) || initializedRef.current) return;
|
|
57
133
|
// the MapLibre-gl instance (mapContext.getMap(props.mapId)) is accessible here
|
|
@@ -59,111 +135,85 @@ const MlShareMapState = (props) => {
|
|
|
59
135
|
initializedRef.current = true;
|
|
60
136
|
mapRef.current = mapContext.getMap(props.mapId);
|
|
61
137
|
setMap(mapRef.current);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (currentUrlParams.lat && currentUrlParams.lng) {
|
|
65
|
-
mapStateRef.current.lat = currentUrlParams.lat;
|
|
66
|
-
mapStateRef.current.lng = currentUrlParams.lng;
|
|
67
|
-
mapStateRef.current.zoom = currentUrlParams.zoom;
|
|
68
|
-
mapRef.current.setZoom(mapStateRef.current.zoom);
|
|
138
|
+
if (mapStateRef.current.lat && mapStateRef.current.lng) {
|
|
139
|
+
restoreViewportState();
|
|
69
140
|
}
|
|
70
141
|
}, [mapContext.mapIds, mapContext, props.mapId, props.active]);
|
|
71
142
|
|
|
72
143
|
useEffect(() => {
|
|
73
|
-
if (!
|
|
74
|
-
if(!mapState.layers) return;
|
|
75
|
-
if(!isInitialState) return;
|
|
144
|
+
if (!mapState?.layers?.length) return;
|
|
76
145
|
|
|
77
|
-
|
|
146
|
+
if (typeof layerStatesRestored.current === "undefined") {
|
|
147
|
+
layerStatesRestored.current = {};
|
|
148
|
+
initialUrlParams?.layers.forEach((layer) => {
|
|
149
|
+
layerStatesRestored.current[layer.id] = false;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
78
152
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
153
|
+
for (let key in layerStatesRestored.current) {
|
|
154
|
+
let _allDone = true;
|
|
155
|
+
if (layerStatesRestored.current[key] === false) {
|
|
156
|
+
_allDone = false;
|
|
157
|
+
}
|
|
158
|
+
if (_allDone) {
|
|
159
|
+
return;
|
|
83
160
|
}
|
|
84
161
|
}
|
|
85
162
|
|
|
86
|
-
|
|
163
|
+
if (initialUrlParams.layers) {
|
|
164
|
+
initialUrlParams.layers.forEach((layer) => {
|
|
165
|
+
if (mapRef.current?.getLayer(layer.id) && layerStatesRestored.current[layer.id] === false) {
|
|
166
|
+
layerStatesRestored.current[layer.id] = true;
|
|
167
|
+
mapRef.current
|
|
168
|
+
?.getLayer(layer.id)
|
|
169
|
+
?.setLayoutProperty("visibility", layer.visible ? "visible" : "none");
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}, [mapState.layers, props.mapId, props.active]);
|
|
87
174
|
|
|
88
175
|
useEffect(() => {
|
|
89
176
|
if (!map) return;
|
|
90
177
|
if (!mapState.layers) return;
|
|
91
178
|
|
|
92
|
-
if (props.active) {
|
|
93
|
-
setIsInitialState(false)
|
|
94
|
-
map.on(
|
|
95
|
-
"moveend",
|
|
96
|
-
() => {
|
|
97
|
-
let mapLayers = []
|
|
98
|
-
for (let x in mapState.layers) {
|
|
99
|
-
mapLayers.push(new URLSearchParams({
|
|
100
|
-
id: mapState.layers[x].id,
|
|
101
|
-
type: mapState.layers[x].type,
|
|
102
|
-
visible: mapState.layers[x].visible
|
|
103
|
-
}))
|
|
104
|
-
}
|
|
105
|
-
refreshMapState();
|
|
106
|
-
let urlParams = new URLSearchParams({
|
|
107
|
-
...getCurrentUrlParameters(),
|
|
108
|
-
...mapStateRef.current,
|
|
109
|
-
layers : mapLayers
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
let currentParams = new URLSearchParams(window.location.search);
|
|
113
|
-
if (urlParams.toString() !== currentParams.toString()) {
|
|
114
|
-
window.history.pushState(
|
|
115
|
-
{...mapStateRef.current},
|
|
116
|
-
document.title,
|
|
117
|
-
"?" + urlParams.toString()
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
componentId.current
|
|
122
|
-
);
|
|
123
|
-
} else {
|
|
179
|
+
if (!props.active) {
|
|
124
180
|
map.cleanup(componentId.current);
|
|
125
181
|
}
|
|
126
|
-
}, [props.active, map]);
|
|
127
|
-
|
|
128
|
-
const getCurrentUrlParameters = () => {
|
|
129
|
-
let parameterObject = Object.fromEntries(new URLSearchParams(window.location.search))
|
|
130
|
-
|
|
131
|
-
if(window.location.search.indexOf("layers")!==-1) {
|
|
132
|
-
let layerParamString = window.location.search.substring(window.location.search.indexOf("layers"))
|
|
133
|
-
layerParamString = layerParamString.substring(0, (layerParamString.indexOf("&")!==-1) ? layerParamString.indexOf("&") : layerParamString.length)
|
|
134
|
-
parameterObject = Object.fromEntries(new URLSearchParams(window.location.search.replace(layerParamString, "")))
|
|
135
|
-
let layerParams = layerParamString.substring(7)
|
|
136
|
-
layerParams = layerParams.replaceAll("%3D", "=")
|
|
137
|
-
layerParams = layerParams.replaceAll("%26", "&")
|
|
138
|
-
layerParams = layerParams.replaceAll("%2C", ",")
|
|
139
|
-
|
|
140
|
-
if (layerParams.indexOf(",")) {
|
|
141
|
-
layerParams = layerParams.split(",")
|
|
142
|
-
} else {
|
|
143
|
-
layerParams = [layerParams]
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
for (let x in layerParams) {
|
|
147
|
-
let layerState = layerParams[x].split("&")
|
|
148
|
-
layerParams[x] = {}
|
|
149
|
-
for (let y in layerState) {
|
|
150
|
-
layerParams[x][layerState[y].split("=")[0]] = layerState[y].split("=")[1]
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
parameterObject["layers"] = layerParams
|
|
154
|
-
}
|
|
155
|
-
return parameterObject
|
|
156
|
-
};
|
|
182
|
+
}, [props.active, map, mapState.layers]);
|
|
157
183
|
|
|
158
184
|
const refreshMapState = () => {
|
|
159
185
|
mapStateRef.current.lat = mapRef.current.getCenter().lat;
|
|
160
186
|
mapStateRef.current.lng = mapRef.current.getCenter().lng;
|
|
161
187
|
mapStateRef.current.zoom = mapRef.current.getZoom();
|
|
188
|
+
mapStateRef.current.bearing = mapRef.current.getBearing();
|
|
189
|
+
mapStateRef.current.pitch = mapRef.current.getPitch();
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const checkRestorationStates = (stateArray) => {
|
|
193
|
+
let tempArray = {};
|
|
194
|
+
stateArray.forEach((el, i, arr) => {
|
|
195
|
+
if (!arr[el.key]) tempArray[el.key] = true;
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const restoreViewportState = () => {
|
|
200
|
+
if (!restoredStatesRef.current.viewport.center) {
|
|
201
|
+
restoredStatesRef.current.viewport.center = true;
|
|
202
|
+
mapRef.current.setCenter([mapStateRef.current.lng, mapStateRef.current.lat]);
|
|
203
|
+
mapRef.current.setZoom(mapStateRef.current.zoom);
|
|
204
|
+
mapRef.current.setBearing(mapStateRef.current.bearing);
|
|
205
|
+
mapRef.current.setPitch(mapStateRef.current.pitch);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
allStatesRestoredRef.current = true;
|
|
162
209
|
};
|
|
163
210
|
|
|
164
211
|
window.onpopstate = (event) => {
|
|
165
212
|
if (event.state && event.state.lng && event.state.lat && event.state.zoom) {
|
|
166
|
-
mapRef.current.easeTo({
|
|
213
|
+
mapRef.current.easeTo({
|
|
214
|
+
zoom: event.state.zoom,
|
|
215
|
+
center: [event.state.lng, event.state.lat],
|
|
216
|
+
});
|
|
167
217
|
}
|
|
168
218
|
};
|
|
169
219
|
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
-
import React, { useState} from "react";
|
|
1
|
+
import React, { useState } from "react";
|
|
2
2
|
|
|
3
3
|
import MlShareMapState from "./MlShareMapState";
|
|
4
4
|
import mapContextDecorator from "../../decorators/MapContextDecorator";
|
|
5
|
-
import
|
|
5
|
+
import useMapState from "../../hooks/useMapState";
|
|
6
|
+
import useMap from "../../hooks/useMap";
|
|
7
|
+
import Sidebar from "../../ui_components/Sidebar";
|
|
8
|
+
import ListItem from "@mui/material/ListItem";
|
|
9
|
+
import IconButton from "@mui/material/IconButton";
|
|
10
|
+
import VisibilityIcon from "@mui/icons-material/Visibility";
|
|
11
|
+
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
|
12
|
+
import ListItemText from "@mui/material/ListItemText";
|
|
13
|
+
import sample_geojson_1 from "../MlGeoJsonLayer/assets/sample_1.json";
|
|
14
|
+
import sample_geojson_2 from "../MlGeoJsonLayer/assets/sample_2.json";
|
|
15
|
+
import List from "@mui/material/List";
|
|
16
|
+
import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
|
|
17
|
+
import { ToggleButton } from "@mui/material";
|
|
18
|
+
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
|
|
19
|
+
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
|
|
6
20
|
|
|
7
21
|
const storyoptions = {
|
|
8
22
|
title: "MapComponents/MlShareMapState",
|
|
@@ -12,37 +26,73 @@ const storyoptions = {
|
|
|
12
26
|
};
|
|
13
27
|
export default storyoptions;
|
|
14
28
|
|
|
15
|
-
const Template = (
|
|
16
|
-
const [
|
|
17
|
-
const [
|
|
29
|
+
const Template = () => {
|
|
30
|
+
const geoJsonArray = [sample_geojson_1, sample_geojson_2];
|
|
31
|
+
const [watchState, setWatchState] = useState(true);
|
|
32
|
+
const mapHook = useMap({ mapId: "map_1" });
|
|
33
|
+
const mapState = useMapState({
|
|
34
|
+
mapId: "map_1",
|
|
35
|
+
watch: {
|
|
36
|
+
viewport: false,
|
|
37
|
+
layers: true,
|
|
38
|
+
sources: false,
|
|
39
|
+
},
|
|
40
|
+
filter: {
|
|
41
|
+
includeBaseLayers: false,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
18
44
|
|
|
19
45
|
return (
|
|
20
46
|
<>
|
|
21
|
-
<button
|
|
22
|
-
style={{ zIndex: "1000", position: "absolute" }}
|
|
23
|
-
onClick={() => setWatchState(!watchState)}
|
|
24
|
-
>
|
|
25
|
-
watch map state {watchState ? 1 : 0}
|
|
26
|
-
</button>
|
|
27
|
-
<button
|
|
28
|
-
style={{ zIndex: "1000", position: "absolute" }}
|
|
29
|
-
onClick={() => setTestLayerVisible(!testLayerVisible)}
|
|
30
|
-
>
|
|
31
|
-
visibility {testLayerVisible ? 1 : 0}
|
|
32
|
-
</button>
|
|
33
47
|
<MlShareMapState active={watchState} />
|
|
34
|
-
|
|
35
|
-
layerId={"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
{geoJsonArray.map((el, i) => (
|
|
49
|
+
<MlGeoJsonLayer layerId={"GeoJson_" + i} type="line" geojson={el} key={"GeoJson_" + i} />
|
|
50
|
+
))}
|
|
51
|
+
<Sidebar sx={{ wordBreak: "break-word" }}>
|
|
52
|
+
<ToggleButton
|
|
53
|
+
size="small"
|
|
54
|
+
selected={watchState}
|
|
55
|
+
value={watchState}
|
|
56
|
+
onChange={() => {
|
|
57
|
+
setWatchState(!watchState);
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{watchState ? <CheckCircleOutlineIcon /> : <ErrorOutlineIcon />}
|
|
61
|
+
|
|
62
|
+
{watchState ? "active" : "inactive"}
|
|
63
|
+
</ToggleButton>
|
|
64
|
+
<List dense key="layers">
|
|
65
|
+
{mapState.layers?.map((el) => (
|
|
66
|
+
<ListItem
|
|
67
|
+
key={el.id}
|
|
68
|
+
secondaryAction={
|
|
69
|
+
<IconButton
|
|
70
|
+
edge="end"
|
|
71
|
+
aria-label="toggle visibility"
|
|
72
|
+
onClick={() => {
|
|
73
|
+
let currentVisibility = mapHook.map
|
|
74
|
+
?.getLayer?.(el.id)
|
|
75
|
+
?.getLayoutProperty("visibility");
|
|
76
|
+
mapHook.map
|
|
77
|
+
?.getLayer?.(el.id)
|
|
78
|
+
?.setLayoutProperty(
|
|
79
|
+
"visibility",
|
|
80
|
+
currentVisibility === "none" ? "visible" : "none"
|
|
81
|
+
);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
mapHook.map._render();
|
|
84
|
+
}, 100);
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{el.visible ? <VisibilityIcon /> : <VisibilityOffIcon />}
|
|
88
|
+
</IconButton>
|
|
89
|
+
}
|
|
90
|
+
>
|
|
91
|
+
<ListItemText primary={el.id} secondary={""} />
|
|
92
|
+
</ListItem>
|
|
93
|
+
))}
|
|
94
|
+
</List>
|
|
95
|
+
</Sidebar>
|
|
46
96
|
</>
|
|
47
97
|
);
|
|
48
98
|
};
|