@mapcomponents/react-maplibre 0.1.14 → 0.1.15

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.
Files changed (81) hide show
  1. package/.github/workflows/storybook.yml +4 -2
  2. package/coverage/clover.xml +325 -297
  3. package/coverage/coverage-final.json +8 -8
  4. package/coverage/lcov-report/index.html +63 -63
  5. package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.js.html +1 -1
  6. package/coverage/lcov-report/src/components/MapLibreMap/index.html +1 -1
  7. package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.js.html +1 -1
  8. package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +1 -1
  9. package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.js.html +1 -1
  10. package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +1 -1
  11. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +1 -1
  12. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +1 -1
  13. package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.js.html +37 -34
  14. package/coverage/lcov-report/src/components/MlFollowGps/index.html +11 -11
  15. package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.js.html +1 -1
  16. package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +1 -1
  17. package/coverage/lcov-report/src/components/MlGPXViewer/index.html +1 -1
  18. package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js.html +96 -30
  19. package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +19 -19
  20. package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html +45 -150
  21. package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +19 -19
  22. package/coverage/lcov-report/src/components/MlLayer/MlLayer.js.html +93 -27
  23. package/coverage/lcov-report/src/components/MlLayer/index.html +19 -19
  24. package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.js.html +1 -1
  25. package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +1 -1
  26. package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.js.html +1 -1
  27. package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +1 -1
  28. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +1 -1
  29. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
  30. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
  31. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
  32. package/coverage/lcov-report/src/components/MlMarker/MlMarker.js.html +1 -1
  33. package/coverage/lcov-report/src/components/MlMarker/index.html +1 -1
  34. package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.js.html +1 -1
  35. package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +1 -1
  36. package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.js.html +10 -13
  37. package/coverage/lcov-report/src/components/MlNavigationTools/index.html +7 -7
  38. package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +1 -1
  39. package/coverage/lcov-report/src/components/MlOsmLayer/index.html +1 -1
  40. package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +1 -1
  41. package/coverage/lcov-report/src/components/MlScaleReference/index.html +1 -1
  42. package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +208 -16
  43. package/coverage/lcov-report/src/components/MlShareMapState/index.html +9 -9
  44. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +1 -1
  45. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
  46. package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +1 -1
  47. package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +1 -1
  48. package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
  49. package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
  50. package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.js.html +1 -1
  51. package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +1 -1
  52. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +1 -1
  53. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +1 -1
  54. package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.js.html +1 -1
  55. package/coverage/lcov-report/src/components/MlWmsLayer/index.html +1 -1
  56. package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.js.html +1 -1
  57. package/coverage/lcov-report/src/components/MlWmsLoader/index.html +1 -1
  58. package/coverage/lcov-report/src/hooks/index.html +32 -32
  59. package/coverage/lcov-report/src/hooks/useMap.js.html +85 -163
  60. package/coverage/lcov-report/src/hooks/useMapState.js.html +82 -82
  61. package/coverage/lcov-report/src/hooks/useWms.js.html +1 -1
  62. package/coverage/lcov-report/src/i18n.js.html +1 -1
  63. package/coverage/lcov-report/src/index.html +1 -1
  64. package/coverage/lcov-report/src/translations/english.js.html +1 -1
  65. package/coverage/lcov-report/src/translations/german.js.html +1 -1
  66. package/coverage/lcov-report/src/translations/index.html +1 -1
  67. package/coverage/lcov.info +620 -570
  68. package/dist/index.esm.js +787 -665
  69. package/dist/index.esm.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +13 -12
  72. package/src/components/MlFollowGps/MlFollowGps.js +23 -22
  73. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +23 -1
  74. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +21 -56
  75. package/src/components/MlLayer/MlLayer.js +26 -4
  76. package/src/components/MlNavigationTools/MlNavigationTools.js +4 -5
  77. package/src/components/MlShareMapState/MlShareMapState.js +73 -9
  78. package/src/components/MlShareMapState/MlShareMapState.stories.js +24 -1
  79. package/src/hooks/useMap.js +36 -62
  80. package/src/hooks/useMapState.js +3 -3
  81. package/src/index.js +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapcomponents/react-maplibre",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "module": "dist/index.esm.js",
@@ -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
  /**
@@ -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
  */
@@ -499,17 +500,17 @@ const MapLibreGlWrapper = function (props) {
499
500
  self.wrapper.refreshViewport();
500
501
  self.wrapper.fire("viewportchange");
501
502
 
502
- self.map.on("move", () => {
503
- self.wrapper.viewportState = self.wrapper.getViewport();
504
- self.wrapper.fire("viewportchange");
505
- });
506
- self.map.on("data", () => {
507
- self.wrapper.refreshLayerState();
508
- self.wrapper.fire("layerchange");
509
- });
510
- if (typeof props.onReady === "function") {
511
- props.onReady(self.map, self);
512
- }
503
+ self.map.on("move", () => {
504
+ self.wrapper.viewportState = self.wrapper.getViewport();
505
+ self.wrapper.fire("viewportchange");
506
+ });
507
+ self.map.on("data", () => {
508
+ self.wrapper.refreshLayerState();
509
+ self.wrapper.fire("layerchange");
510
+ });
511
+ if (typeof props.onReady === "function") {
512
+ props.onReady(self.map, self);
513
+ }
513
514
  };
514
515
  initializeMapLibre();
515
516
  };
@@ -5,7 +5,7 @@ import {MapContext} from "@mapcomponents/react-core";
5
5
  import {v4 as uuidv4} from "uuid";
6
6
  import Button from "@mui/material/Button";
7
7
  import RoomIcon from "@mui/icons-material/Room";
8
- import {point} from "@turf/turf"
8
+ import {point, circle} from "@turf/turf"
9
9
  import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
10
10
  import MlImageMarkerLayer from "../MlImageMarkerLayer/MlImageMarkerLayer";
11
11
 
@@ -31,7 +31,7 @@ const MlFollowGps = (props) => {
31
31
  const initializedRef = useRef(false);
32
32
  const mapRef = useRef(undefined);
33
33
  const componentId = useRef((props.idPrefix ? props.idPrefix : "MlFollowGps-") + uuidv4());
34
- const [accuracyRadius, setAccuracyRadius] = useState(30);
34
+ const [accuracyGeoJson, setAccuracyGeoJson] = useState();
35
35
 
36
36
  useEffect(() => {
37
37
  let _componentId = componentId.current;
@@ -67,8 +67,9 @@ const MlFollowGps = (props) => {
67
67
  const getLocationSuccess = (pos) => {
68
68
  if (!mapRef.current) return;
69
69
  mapRef.current.setCenter([pos.coords.longitude, pos.coords.latitude]);
70
- setAccuracyRadius(pos.coords.accuracy);
71
- setGeoJson(point([pos.coords.longitude, pos.coords.latitude]));
70
+ const geoJsonPoint = point([pos.coords.longitude, pos.coords.latitude])
71
+ setGeoJson(geoJsonPoint);
72
+ setAccuracyGeoJson(circle(geoJsonPoint, pos.coords.accuracy/1000))
72
73
  };
73
74
 
74
75
  const getLocationError = (err) => {
@@ -80,29 +81,19 @@ const MlFollowGps = (props) => {
80
81
  <>
81
82
  {isFollowed && geoJson && (
82
83
  <MlGeoJsonLayer
83
- geojson={geoJson}
84
- type={"circle"}
84
+ geojson={accuracyGeoJson}
85
+ type={"fill"}
85
86
  paint={{
86
- "circle-radius": {
87
- stops: [
88
- [0, 0],
89
- [
90
- 20,
91
- accuracyRadius /
92
- 0.075 /
93
- Math.cos((geoJson.geometry.coordinates[1] * Math.PI) / 180),
94
- ],
95
- ],
96
- base: 2,
97
- },
98
- "circle-color": "#ee7700",
99
- "circle-opacity": 0.5,
87
+ "fill-color": "#ee7700",
88
+ "fill-opacity": 0.5,
100
89
  }}
90
+ insertBeforeLayer={"MlFollowGpsMarker"}
101
91
  />
102
92
  )}
103
93
 
104
94
  {isFollowed && geoJson && (
105
95
  <MlImageMarkerLayer
96
+ layerId={"MlFollowGpsMarker"}
106
97
  options={{
107
98
  type: "symbol",
108
99
  source: {
@@ -119,7 +110,7 @@ const MlFollowGps = (props) => {
119
110
  )}
120
111
 
121
112
  <Button
122
- sx={{ zIndex: 1002, color: isFollowed ? "#bbb" : "#666", ...props.style }}
113
+ sx={{ zIndex: 1002, color: isFollowed ? props.onColor : props.offColor, ...props.style }}
123
114
  disabled={locationAccessDenied}
124
115
  onClick={() => {
125
116
  if (isFollowed) {
@@ -134,7 +125,7 @@ const MlFollowGps = (props) => {
134
125
  }}
135
126
  >
136
127
  {" "}
137
- <RoomIcon sx={{fontSize: props.style.fontSize}}/>{" "}
128
+ <RoomIcon sx={{ fontSize: props.style.fontSize }} />{" "}
138
129
  </Button>
139
130
  </>
140
131
  );
@@ -156,6 +147,8 @@ MlFollowGps.defaultProps = {
156
147
  color: "#ececec",
157
148
  },
158
149
  },
150
+ onColor: "#ececec",
151
+ offColor: "#666"
159
152
  };
160
153
 
161
154
  MlFollowGps.propTypes = {
@@ -167,5 +160,13 @@ MlFollowGps.propTypes = {
167
160
  * CSS style object that is applied to the button component
168
161
  */
169
162
  style: PropTypes.object,
163
+ /**
164
+ * Active button font color
165
+ */
166
+ onColor: PropTypes.string,
167
+ /**
168
+ * Inactive button font color
169
+ */
170
+ offColor: PropTypes.string,
170
171
  };
171
172
  export default MlFollowGps;
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
4
4
  import { v4 as uuidv4 } from "uuid";
5
5
  import * as turf from "@turf/turf";
6
6
  import { MapContext } from "@mapcomponents/react-core";
7
+ import useMapState from "../../hooks/useMapState";
7
8
 
8
9
  import { _transitionToGeojson } from "./util/transitionFunctions";
9
10
 
@@ -17,6 +18,14 @@ const msPerStep = 50;
17
18
  const MlGeoJsonLayer = (props) => {
18
19
  // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
19
20
  const mapContext = useContext(MapContext);
21
+ const mapState = useMapState({
22
+ mapId: props.mapId,
23
+ watch: {
24
+ viewport: false,
25
+ layers: true,
26
+ sources: false,
27
+ },
28
+ });
20
29
  const oldGeojsonRef = useRef(null);
21
30
  const mapRef = useRef(null);
22
31
  const initializedRef = useRef(false);
@@ -114,6 +123,19 @@ const MlGeoJsonLayer = (props) => {
114
123
  // initialize the layer and add it to the MapLibre-gl instance or do something else with it
115
124
 
116
125
  if (props.geojson) {
126
+ //check if insertBeforeLayer exists
127
+ if (props.insertBeforeLayer) {
128
+ let layerFound = false;
129
+
130
+ mapState?.layers?.forEach((layer) => {
131
+ if (layer.id === props.insertBeforeLayer) {
132
+ layerFound = true;
133
+ }
134
+ });
135
+ if (!layerFound) {
136
+ return;
137
+ }
138
+ }
117
139
  initializedRef.current = true;
118
140
  let geojson = props.geojson;
119
141
 
@@ -168,7 +190,7 @@ const MlGeoJsonLayer = (props) => {
168
190
  oldGeojsonRef.current = props.geojson;
169
191
  }
170
192
  }
171
- }, [mapContext.mapIds, mapContext, props, transitionToGeojson]);
193
+ }, [mapContext.mapIds, mapContext, props, transitionToGeojson, mapState.layers]);
172
194
 
173
195
  return <></>;
174
196
  };
@@ -1,34 +1,18 @@
1
- import React, { useRef, useCallback, useEffect, useContext } from "react";
1
+ import React, { useRef, useCallback, useEffect } from "react";
2
2
 
3
- import { v4 as uuidv4 } from "uuid";
4
- import { MapContext } from "@mapcomponents/react-core";
3
+ import useMap from "../../hooks/useMap";
5
4
 
6
5
  const MlImageMarkerLayer = (props) => {
7
- // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
8
- const mapRef = useRef(null);
9
- const componentId = useRef((props.idPrefix ? props.idPrefix : "MlImageMarkerLayer-") + uuidv4());
10
- const mapContext = useContext(MapContext);
6
+ const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
7
+
11
8
  const layerInitializedRef = useRef(false);
12
- const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
13
9
  const imageIdRef = useRef(props.imageId || "img_" + new Date().getTime());
14
- const layerId = useRef(props.layerId || componentId.current);
15
-
16
- useEffect(() => {
17
- let _componentId = componentId.current;
18
- return () => {
19
- // This is the cleanup function, it is called when this react component is removed from react-dom
20
- if (mapRef.current) {
21
- mapRef.current.cleanup(_componentId);
22
-
23
- mapRef.current = null;
24
- }
25
- };
26
- }, []);
10
+ const layerId = useRef(props.layerId || "MlImageMarkerLayer-" + mapHook.componentId);
27
11
 
28
12
  useEffect(() => {
29
13
  if (
30
- !mapRef.current ||
31
- (mapRef.current && !mapContext.getMap(props.mapId).getLayer(layerId.current)) ||
14
+ !mapHook.mapIsReady ||
15
+ (mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
32
16
  !props.options
33
17
  )
34
18
  return;
@@ -38,19 +22,15 @@ const MlImageMarkerLayer = (props) => {
38
22
 
39
23
  if (props.options.layout) {
40
24
  for (key in props.options.layout) {
41
- mapContext
42
- .getMap(props.mapId)
43
- .setLayoutProperty(layerId.current, key, props.options.layout[key]);
25
+ mapHook.map.setLayoutProperty(layerId.current, key, props.options.layout[key]);
44
26
  }
45
27
  }
46
28
  if (props.options.paint) {
47
29
  for (key in props.options.paint) {
48
- mapContext
49
- .getMap(props.mapId)
50
- .setPaintProperty(layerId.current, key, props.options.paint[key]);
30
+ mapHook.map.setPaintProperty(layerId.current, key, props.options.paint[key]);
51
31
  }
52
32
  }
53
- }, [props.options, layerId.current, mapContext, props.mapId]);
33
+ }, [props.options, layerId.current, props.mapId]);
54
34
 
55
35
  const addLayer = useCallback(() => {
56
36
  let tmpOptions = {
@@ -59,50 +39,35 @@ const MlImageMarkerLayer = (props) => {
59
39
  ...props.options,
60
40
  };
61
41
  tmpOptions.layout["icon-image"] = imageIdRef.current;
62
- mapRef.current.addLayer(
63
- tmpOptions,
64
- props.insertBeforeLayer,
65
- componentId.current
66
- );
67
- }, [props]);
42
+ mapHook.map.addLayer(tmpOptions, props.insertBeforeLayer, mapHook.componentId);
43
+ }, [props, mapHook.mapIsReady, mapHook.map]);
68
44
 
69
45
  useEffect(() => {
70
- if (
71
- !props.options ||
72
- !mapContext.mapExists(props.mapId) ||
73
- layerInitializedRef.current
74
- )
75
- return;
76
-
77
- // the MapLibre-gl instance (mapContext.map) is accessible here
78
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
79
- mapRef.current = mapContext.getMap(props.mapId);
46
+ if (!props.options || !mapHook.mapIsReady || layerInitializedRef.current) return;
80
47
 
81
48
  layerInitializedRef.current = true;
82
49
 
83
- console.log(props.imgSrc);
84
50
  if (props.imgSrc) {
85
- mapRef.current.loadImage(props.imgSrc, function (error, image) {
51
+ mapHook.map.loadImage(props.imgSrc, function (error, image) {
86
52
  if (error) throw error;
87
- mapRef.current.addImage(imageIdRef.current, image, componentId.current);
53
+ mapHook.map.addImage(imageIdRef.current, image, mapHook.componentId);
88
54
  });
89
55
  }
56
+
90
57
  addLayer();
91
- }, [mapContext.mapIds, mapContext, props, addLayer]);
58
+ }, [mapHook.mapIsReady, mapHook.map, addLayer, props]);
92
59
 
93
60
  useEffect(() => {
94
61
  if (
95
- !mapRef.current ||
96
- (mapRef.current && !mapContext.getMap(props.mapId).getLayer(layerId.current)) ||
62
+ !mapHook.mapIsReady ||
63
+ (mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
97
64
  !props.options
98
65
  ) {
99
66
  return;
100
67
  }
101
- // the MapLibre-gl instance (mapContext.map) is accessible here
102
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
103
68
 
104
- mapRef.current.getSource(layerId.current).setData(props.options.source.data);
105
- }, [props.options.source.data, mapContext, props]);
69
+ mapHook.map.getSource(layerId.current).setData(props.options.source.data);
70
+ }, [props.options.source.data, props]);
106
71
 
107
72
  return <></>;
108
73
  };
@@ -2,15 +2,23 @@ import React, { useRef, useEffect, useContext } from "react";
2
2
 
3
3
  import { v4 as uuidv4 } from "uuid";
4
4
  import { MapContext } from "@mapcomponents/react-core";
5
+ import useMapState from "../../hooks/useMapState";
5
6
 
6
7
  const MlLayer = (props) => {
7
8
  // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
8
9
  const mapContext = useContext(MapContext);
10
+
11
+ const mapState = useMapState({
12
+ mapId: props.mapId,
13
+ watch: {
14
+ viewport: false,
15
+ layers: true,
16
+ sources: false,
17
+ },
18
+ });
9
19
  const layerInitializedRef = useRef(false);
10
20
  const mapRef = useRef(null);
11
- const componentId = useRef(
12
- (props.layerId ? props.layerId : "MlLayer-") + uuidv4()
13
- );
21
+ const componentId = useRef((props.layerId ? props.layerId : "MlLayer-") + uuidv4());
14
22
  const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
15
23
  const layerId = useRef(props.layerId || componentId.current);
16
24
  const layerPaintConfRef = useRef(undefined);
@@ -60,6 +68,20 @@ const MlLayer = (props) => {
60
68
  // the MapLibre-gl instance (mapContext.map) is accessible here
61
69
  // initialize the layer and add it to the MapLibre-gl instance or do something else with it
62
70
 
71
+ //check if insertBeforeLayer exists
72
+ if (props.insertBeforeLayer) {
73
+ let layerFound = false;
74
+
75
+ mapState?.layers?.forEach((layer) => {
76
+ if (layer.id === props.insertBeforeLayer) {
77
+ layerFound = true;
78
+ }
79
+ });
80
+ if (!layerFound) {
81
+ return;
82
+ }
83
+ }
84
+
63
85
  mapRef.current = mapContext.getMap(props.mapId);
64
86
  if (mapRef.current) {
65
87
  layerInitializedRef.current = true;
@@ -78,7 +100,7 @@ const MlLayer = (props) => {
78
100
  layerPaintConfRef.current = JSON.stringify(props.options?.paint);
79
101
  layerLayoutConfRef.current = JSON.stringify(props.options?.layout);
80
102
  }
81
- }, [mapContext.mapIds, mapContext, props, layerId]);
103
+ }, [mapContext.mapIds, mapContext, props, mapState.layers]);
82
104
 
83
105
  return <></>;
84
106
  };
@@ -29,7 +29,6 @@ const MlNavigationTools = (props) => {
29
29
  minHeight: "20px",
30
30
  width: mediaIsMobile ? "50px" : "30px",
31
31
  height: mediaIsMobile ? "50px" : "30px",
32
- color: "#bbb",
33
32
  backgroundColor: "#414141",
34
33
  borderRadius: "23%",
35
34
  //border: "1px solid #bbb",
@@ -38,8 +37,8 @@ const MlNavigationTools = (props) => {
38
37
  fontSize: mediaIsMobile ? "1.5em" : "1.2em",
39
38
  ":hover": {
40
39
  backgroundColor: "#515151",
41
- color: "#ececec",
42
40
  },
41
+ color: "#ececec"
43
42
  };
44
43
 
45
44
  useEffect(() => {
@@ -144,7 +143,7 @@ const MlNavigationTools = (props) => {
144
143
  <Button sx={buttonStyle} onClick={moveToCurrentLocation} disabled={locationAccessDenied}>
145
144
  <GpsFixedIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
146
145
  </Button>
147
- <MlFollowGps style={buttonStyle}/>
146
+ <MlFollowGps style={{...(({color, ...rest}) => rest)(buttonStyle)}} />
148
147
  <ButtonGroup
149
148
  orientation="vertical"
150
149
  sx={{
@@ -154,10 +153,10 @@ const MlNavigationTools = (props) => {
154
153
  "Button:hover": {border: "none"},
155
154
  }}
156
155
  >
157
- <Button sx={buttonStyle} onClick={zoomIn}>
156
+ <Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomIn}>
158
157
  <ControlPointIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
159
158
  </Button>
160
- <Button sx={buttonStyle} onClick={zoomOut}>
159
+ <Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomOut}>
161
160
  <RemoveCircleOutlineIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
162
161
  </Button>
163
162
  </ButtonGroup>
@@ -1,8 +1,9 @@
1
- import React, { useRef, useEffect, useContext, useState } from "react";
1
+ import React, {useRef, useEffect, useContext, useState} 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
+ import useMapState from "../../hooks/useMapState";
6
7
 
7
8
  /**
8
9
  * TODO: Add short & useful description
@@ -15,11 +16,21 @@ import { v4 as uuidv4 } from "uuid";
15
16
  const MlShareMapState = (props) => {
16
17
  // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
17
18
  const mapContext = useContext(MapContext);
18
-
19
19
  const initializedRef = useRef(false);
20
20
  const mapRef = useRef(undefined);
21
21
  const [map, setMap] = useState(undefined);
22
22
  const componentId = useRef((props.idPrefix ? props.idPrefix : "MlShareMapState-") + uuidv4());
23
+ const [isInitialState, setIsInitialState] = useState(true);
24
+ const mapState = useMapState({
25
+ watch: {
26
+ viewport: false,
27
+ layers: true,
28
+ sources: false
29
+ },
30
+ filter: {
31
+ includeBaseLayers: false
32
+ }
33
+ })
23
34
 
24
35
  const mapStateRef = useRef({});
25
36
 
@@ -49,32 +60,59 @@ const MlShareMapState = (props) => {
49
60
  mapRef.current = mapContext.getMap(props.mapId);
50
61
  setMap(mapRef.current);
51
62
 
52
- let currentUrlParams = getCurrentUrlParameters();
63
+ const currentUrlParams = getCurrentUrlParameters();
53
64
  if (currentUrlParams.lat && currentUrlParams.lng) {
54
65
  mapStateRef.current.lat = currentUrlParams.lat;
55
66
  mapStateRef.current.lng = currentUrlParams.lng;
56
67
  mapStateRef.current.zoom = currentUrlParams.zoom;
57
- mapRef.current.setCenter([mapStateRef.current.lng, mapStateRef.current.lat]);
58
68
  mapRef.current.setZoom(mapStateRef.current.zoom);
59
69
  }
60
70
  }, [mapContext.mapIds, mapContext, props.mapId, props.active]);
61
71
 
62
72
  useEffect(() => {
63
73
  if (!map) return;
74
+ if(!mapState.layers) return;
75
+ if(!isInitialState) return;
76
+
77
+ const currentUrlParams = getCurrentUrlParameters()
78
+
79
+ if(currentUrlParams.layers) {
80
+ for (let x in currentUrlParams.layers) {
81
+ mapRef.current.getLayer(currentUrlParams.layers[x].id).visibility = currentUrlParams.layers[x].visible ? "visible" : "none"
82
+ mapRef.current.getLayer(currentUrlParams.layers[x].id).type = currentUrlParams.layers[x].type
83
+ }
84
+ }
85
+
86
+ }, [mapState.layers, props.mapId, props.active])
87
+
88
+ useEffect(() => {
89
+ if (!map) return;
90
+ if (!mapState.layers) return;
64
91
 
65
92
  if (props.active) {
93
+ setIsInitialState(false)
66
94
  map.on(
67
95
  "moveend",
68
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
+ }
69
105
  refreshMapState();
70
106
  let urlParams = new URLSearchParams({
71
107
  ...getCurrentUrlParameters(),
72
108
  ...mapStateRef.current,
109
+ layers : mapLayers
73
110
  });
111
+
74
112
  let currentParams = new URLSearchParams(window.location.search);
75
113
  if (urlParams.toString() !== currentParams.toString()) {
76
114
  window.history.pushState(
77
- { ...mapStateRef.current },
115
+ {...mapStateRef.current},
78
116
  document.title,
79
117
  "?" + urlParams.toString()
80
118
  );
@@ -88,7 +126,33 @@ const MlShareMapState = (props) => {
88
126
  }, [props.active, map]);
89
127
 
90
128
  const getCurrentUrlParameters = () => {
91
- return Object.fromEntries(new URLSearchParams(window.location.search));
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
92
156
  };
93
157
 
94
158
  const refreshMapState = () => {
@@ -99,7 +163,7 @@ const MlShareMapState = (props) => {
99
163
 
100
164
  window.onpopstate = (event) => {
101
165
  if (event.state && event.state.lng && event.state.lat && event.state.zoom) {
102
- mapRef.current.easeTo({ zoom: event.state.zoom, center: [event.state.lng, event.state.lat] });
166
+ mapRef.current.easeTo({zoom: event.state.zoom, center: [event.state.lng, event.state.lat]});
103
167
  }
104
168
  };
105
169
 
@@ -2,6 +2,8 @@ import React, { useState} from "react";
2
2
 
3
3
  import MlShareMapState from "./MlShareMapState";
4
4
  import mapContextDecorator from "../../decorators/MapContextDecorator";
5
+ import useMapState from "../../hooks/useMapState";
6
+ import MlLayer from "../MlLayer/MlLayer";
5
7
 
6
8
  const storyoptions = {
7
9
  title: "MapComponents/MlShareMapState",
@@ -12,7 +14,19 @@ const storyoptions = {
12
14
  export default storyoptions;
13
15
 
14
16
  const Template = (args) => {
15
- const [watchState, setWatchState] = useState(true);
17
+ const [watchState, setWatchState] = useState(false);
18
+ const [testLayerVisible, setTestLayerVisible] = useState(true);
19
+ const mapState = useMapState({
20
+ watch : {
21
+ viewport : false,
22
+ layers : true,
23
+ sources : false
24
+ },
25
+ filter : {
26
+ includeBaseLayers : false
27
+ }
28
+ }
29
+ )
16
30
 
17
31
  return (
18
32
  <>
@@ -22,7 +36,16 @@ const Template = (args) => {
22
36
  >
23
37
  watch map state {watchState?1:0}
24
38
  </button>
39
+ <button
40
+ style={{ zIndex: "1000", position: "absolute" }}
41
+ onClick={() => setTestLayerVisible(!testLayerVisible)}
42
+ >
43
+ visibility {testLayerVisible?1:0}
44
+ </button>
25
45
  <MlShareMapState active={watchState} />
46
+ <MlLayer layerId={"MlLayer-testLayer"} options={{layout: {visibility: (testLayerVisible ? "visible":"none")}}} />
47
+ <MlLayer layerId={"MlLayer-testLayer2"} options={{layout: {visibility: (testLayerVisible ? "visible":"none")}}} />
48
+ <MlLayer layerId={"MlLayer-testLayer3"} options={{layout: {visibility: (testLayerVisible ? "visible":"none")}}} />
26
49
  </>
27
50
  );
28
51
  };