@mapcomponents/react-maplibre 0.1.13 → 0.1.17

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 (100) hide show
  1. package/.github/workflows/storybook.yml +4 -2
  2. package/CHANGELOG.md +33 -0
  3. package/README.md +22 -6
  4. package/coverage/clover.xml +447 -460
  5. package/coverage/coverage-final.json +14 -14
  6. package/coverage/lcov-report/index.html +77 -78
  7. package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.js.html +2 -3
  8. package/coverage/lcov-report/src/components/MapLibreMap/index.html +2 -3
  9. package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.js.html +2 -3
  10. package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +2 -3
  11. package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.js.html +2 -3
  12. package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +2 -3
  13. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +2 -3
  14. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +2 -3
  15. package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.js.html +112 -107
  16. package/coverage/lcov-report/src/components/MlFollowGps/index.html +16 -17
  17. package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.js.html +2 -3
  18. package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +2 -3
  19. package/coverage/lcov-report/src/components/MlGPXViewer/index.html +2 -3
  20. package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js.html +142 -134
  21. package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +20 -21
  22. package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html +46 -152
  23. package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +20 -21
  24. package/coverage/lcov-report/src/components/MlLayer/MlLayer.js.html +92 -30
  25. package/coverage/lcov-report/src/components/MlLayer/index.html +20 -21
  26. package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.js.html +2 -3
  27. package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +2 -3
  28. package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.js.html +2 -3
  29. package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +2 -3
  30. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +3 -10
  31. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +9 -82
  32. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +10 -11
  33. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +2 -3
  34. package/coverage/lcov-report/src/components/MlMarker/MlMarker.js.html +6 -7
  35. package/coverage/lcov-report/src/components/MlMarker/index.html +6 -7
  36. package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.js.html +2 -3
  37. package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +2 -3
  38. package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.js.html +11 -15
  39. package/coverage/lcov-report/src/components/MlNavigationTools/index.html +8 -9
  40. package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +2 -3
  41. package/coverage/lcov-report/src/components/MlOsmLayer/index.html +2 -3
  42. package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +2 -3
  43. package/coverage/lcov-report/src/components/MlScaleReference/index.html +2 -3
  44. package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +209 -18
  45. package/coverage/lcov-report/src/components/MlShareMapState/index.html +10 -11
  46. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +2 -3
  47. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +2 -3
  48. package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +2 -3
  49. package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +2 -3
  50. package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +6 -25
  51. package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +6 -7
  52. package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.js.html +2 -3
  53. package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +2 -3
  54. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +2 -3
  55. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +2 -3
  56. package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.js.html +2 -3
  57. package/coverage/lcov-report/src/components/MlWmsLayer/index.html +2 -3
  58. package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.js.html +6 -19
  59. package/coverage/lcov-report/src/components/MlWmsLoader/index.html +8 -9
  60. package/coverage/lcov-report/src/hooks/index.html +35 -36
  61. package/coverage/lcov-report/src/hooks/useMap.js.html +81 -169
  62. package/coverage/lcov-report/src/hooks/useMapState.js.html +82 -125
  63. package/coverage/lcov-report/src/hooks/useWms.js.html +9 -22
  64. package/coverage/lcov-report/src/i18n.js.html +2 -3
  65. package/coverage/lcov-report/src/index.html +2 -3
  66. package/coverage/lcov-report/src/translations/english.js.html +2 -3
  67. package/coverage/lcov-report/src/translations/german.js.html +2 -3
  68. package/coverage/lcov-report/src/translations/index.html +2 -3
  69. package/coverage/lcov.info +891 -896
  70. package/dist/index.esm.js +941 -717
  71. package/dist/index.esm.js.map +1 -1
  72. package/package.json +2 -2
  73. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +16 -14
  74. package/src/components/MlComponentTemplate/MlComponentTemplate.js +7 -32
  75. package/src/components/MlFollowGps/MlFollowGps.js +67 -65
  76. package/src/components/MlFollowGps/MlFollowGps.test.js +3 -5
  77. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +91 -88
  78. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.stories.js +20 -6
  79. package/src/components/MlGeoJsonLayer/assets/sample_polygon_1.json +33 -0
  80. package/src/components/MlGeoJsonLayer/util/getDefaultLayerTypeByGeometry.js +25 -0
  81. package/src/components/MlGeoJsonLayer/util/getDefaultPaintPropsByType.js +22 -0
  82. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +21 -56
  83. package/src/components/MlLayer/MlLayer.js +26 -5
  84. package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +0 -2
  85. package/src/components/MlLayerSwitcher/MlLayerSwitcher.stories.js +3 -6
  86. package/src/components/MlLayerSwitcher/components/LayerBox.js +2 -26
  87. package/src/components/MlMarker/MlMarker.js +1 -1
  88. package/src/components/MlNavigationTools/MlNavigationTools.js +4 -5
  89. package/src/components/MlShareMapState/MlShareMapState.js +73 -9
  90. package/src/components/MlShareMapState/MlShareMapState.stories.js +22 -2
  91. package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.js +1 -3
  92. package/src/components/MlUseMapDebugger/MlUseMapDebugger.js +1 -7
  93. package/src/components/MlWmsLoader/MlWmsLoader.js +0 -4
  94. package/src/hooks/useMap.js +33 -62
  95. package/src/hooks/useMapState.js +3 -17
  96. package/src/hooks/useWms.js +2 -7
  97. package/src/index.js +3 -0
  98. package/src/ui_components/ImageLoader.js +8 -3
  99. package/src/ui_components/Sidebar.js +1 -1
  100. package/src/ui_components/TopToolbar.js +0 -2
@@ -7,7 +7,9 @@ import { MapContext } from "@mapcomponents/react-core";
7
7
 
8
8
  import sample_geojson_1 from "./assets/sample_1.json";
9
9
  import sample_geojson_2 from "./assets/sample_2.json";
10
+ import sample_polygon_geojson_1 from "./assets/sample_polygon_1.json";
10
11
 
12
+ console.log(sample_polygon_geojson_1);
11
13
  const storyoptions = {
12
14
  title: "MapComponents/MlGeoJsonLayer",
13
15
  component: MlGeoJsonLayer,
@@ -20,6 +22,13 @@ const storyoptions = {
20
22
  export default storyoptions;
21
23
 
22
24
  const Template = (props) => {
25
+ return (
26
+ <>
27
+ <MlGeoJsonLayer {...props} />
28
+ </>
29
+ );
30
+ };
31
+ const LinestringTransitionTemplate = (props) => {
23
32
  const mapContext = useContext(MapContext);
24
33
  const [geojson, setGeojson] = useState(sample_geojson_1);
25
34
  const initializedRef = useRef(false);
@@ -28,9 +37,7 @@ const Template = (props) => {
28
37
  if (!mapContext.getMap() || initializedRef.current) return;
29
38
 
30
39
  initializedRef.current = true;
31
- mapContext
32
- .getMap()
33
- .setCenter({ lng: 7.137609868988648, lat: 50.74746799549129 });
40
+ mapContext.getMap().setCenter({ lng: 7.137609868988648, lat: 50.74746799549129 });
34
41
  mapContext.getMap().setZoom(9.5);
35
42
 
36
43
  setTimeout(() => {
@@ -45,6 +52,13 @@ const Template = (props) => {
45
52
  );
46
53
  };
47
54
 
48
- export const ExampleConfig = Template.bind({});
49
- ExampleConfig.parameters = {};
50
- ExampleConfig.args = {};
55
+ export const LinestringExample = LinestringTransitionTemplate.bind({});
56
+ LinestringExample.parameters = {};
57
+ LinestringExample.args = {};
58
+
59
+ export const PolygonExample = Template.bind({});
60
+ PolygonExample.parameters = {};
61
+ PolygonExample.args = {
62
+ type: "line",
63
+ geojson: sample_polygon_geojson_1,
64
+ };
@@ -0,0 +1,33 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [
4
+ {
5
+ "type": "Feature",
6
+ "properties": {},
7
+ "geometry": {
8
+ "coordinates": [
9
+ [
10
+ [7.08646747303149, 50.74485058672653],
11
+ [7.084287513691095, 50.74371917250187],
12
+ [7.084437772332876, 50.743610683782215],
13
+ [7.084640903561933, 50.743721758552354],
14
+ [7.085805654941254, 50.74293993704128],
15
+ [7.087023278906713, 50.74218320888983],
16
+ [7.087791368229503, 50.74258090834434],
17
+ [7.088796806075749, 50.743261830692745],
18
+ [7.089275088452752, 50.743701110992674],
19
+ [7.088087117762917, 50.74409411011173],
20
+ [7.087662548338368, 50.743784963165815],
21
+ [7.087184330538875, 50.7440368518605],
22
+ [7.087233860417484, 50.744077781245316],
23
+ [7.08714938625954, 50.744122118772154],
24
+ [7.087057544749172, 50.74427276821896],
25
+ [7.087104984084277, 50.744509715654885],
26
+ [7.08646747303149, 50.74485058672653]
27
+ ]
28
+ ],
29
+ "type": "Polygon"
30
+ }
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,25 @@
1
+ const mapGeometryTypesToLayerTypes = {
2
+ Position: "circle",
3
+ Point: "circle",
4
+ MultiPoint: "circle",
5
+ LineString: "line",
6
+ MultiLineString: "line",
7
+ Polygon: "fill",
8
+ MultiPolygon: "fill",
9
+ GeometryCollection: "circle",
10
+ };
11
+
12
+ const getDefaulLayerTypeByGeometry = (geojson) => {
13
+ if (geojson?.type === "Feature") {
14
+ return mapGeometryTypesToLayerTypes?.[geojson?.geometry?.type]
15
+ ? mapGeometryTypesToLayerTypes[geojson.geometry.type]
16
+ : "circle";
17
+ }
18
+ if (geojson?.type === "FeatureCollection") {
19
+ if (geojson.features.length) {
20
+ return getDefaulLayerTypeByGeometry(geojson.features[0]);
21
+ }
22
+ return "circle";
23
+ }
24
+ };
25
+ export default getDefaulLayerTypeByGeometry;
@@ -0,0 +1,22 @@
1
+ const getDefaultPaintPropsByType = (type) => {
2
+ switch (type) {
3
+ case "fill":
4
+ return {
5
+ "fill-color": "rgba(10,240,256,0.6)",
6
+ };
7
+ case "line":
8
+ return {
9
+ "line-color": "rgb(100,200,100)",
10
+ "line-width": 5,
11
+ };
12
+ case "circle":
13
+ default:
14
+ return {
15
+ "circle-color": "#44aaaa",
16
+ "circle-stroke-color": "#fff",
17
+ "circle-stroke-width": 2,
18
+ };
19
+ }
20
+ };
21
+
22
+ export default getDefaultPaintPropsByType;
@@ -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,16 +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
- );
14
- const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
21
+ const componentId = useRef((props.layerId ? props.layerId : "MlLayer-") + uuidv4());
15
22
  const layerId = useRef(props.layerId || componentId.current);
16
23
  const layerPaintConfRef = useRef(undefined);
17
24
  const layerLayoutConfRef = useRef(undefined);
@@ -60,6 +67,20 @@ const MlLayer = (props) => {
60
67
  // the MapLibre-gl instance (mapContext.map) is accessible here
61
68
  // initialize the layer and add it to the MapLibre-gl instance or do something else with it
62
69
 
70
+ //check if insertBeforeLayer exists
71
+ if (props.insertBeforeLayer) {
72
+ let layerFound = false;
73
+
74
+ mapState?.layers?.forEach((layer) => {
75
+ if (layer.id === props.insertBeforeLayer) {
76
+ layerFound = true;
77
+ }
78
+ });
79
+ if (!layerFound) {
80
+ return;
81
+ }
82
+ }
83
+
63
84
  mapRef.current = mapContext.getMap(props.mapId);
64
85
  if (mapRef.current) {
65
86
  layerInitializedRef.current = true;
@@ -78,7 +99,7 @@ const MlLayer = (props) => {
78
99
  layerPaintConfRef.current = JSON.stringify(props.options?.paint);
79
100
  layerLayoutConfRef.current = JSON.stringify(props.options?.layout);
80
101
  }
81
- }, [mapContext.mapIds, mapContext, props, layerId]);
102
+ }, [mapContext.mapIds, mapContext, props, mapState.layers]);
82
103
 
83
104
  return <></>;
84
105
  };
@@ -2,7 +2,6 @@
2
2
  import "@fontsource/roboto/300.css";
3
3
  import "@fontsource/roboto/400.css";
4
4
  import "@fontsource/roboto/500.css";
5
- import { css, cx } from '@emotion/css'
6
5
  import "./MlLayerSwitcher.css";
7
6
  //External
8
7
  import { useEffect, useContext, useState } from "react";
@@ -14,7 +13,6 @@ import { MapContext } from "@mapcomponents/react-core";
14
13
  import LayerBox from "./components/LayerBox";
15
14
  import Divider from "@mui/material/Divider";
16
15
  import useMapState from "../../hooks/useMapState";
17
- import LoadingOverlay from "../../ui_components/LoadingOverlay";
18
16
  /**
19
17
  * @component
20
18
  *
@@ -1,11 +1,10 @@
1
- import React, { useState, useContext, useRef, useEffect } from "react";
1
+ import React from "react";
2
2
  import MlWmsLayer from "../MlWmsLayer/MlWmsLayer";
3
3
  import MlLayerSwitcher from "./MlLayerSwitcher";
4
- import MlGeoJsonLayer from '../MlGeoJsonLayer/MlGeoJsonLayer'
4
+ import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
5
5
  import mapContextDecorator from "../../decorators/MapContextDecorator";
6
6
  import sample_geojson_1 from "./assets/sample_1.json";
7
7
  import sample_geojson_2 from "./assets/sample_2.json";
8
- import { Props } from "@storybook/addon-docs/blocks";
9
8
 
10
9
  const storyoptions = {
11
10
  title: "MapComponents/MlLayerSwitcher",
@@ -17,9 +16,7 @@ const storyoptions = {
17
16
  decorators: mapContextDecorator,
18
17
  };
19
18
  export default storyoptions;
20
- const layerId = "nw_uraufnahme_rw";
21
19
  const Template = (args) => {
22
- const [geojson, setGeojson] = useState(sample_geojson_1);
23
20
  return (
24
21
  <>
25
22
  <MlWmsLayer
@@ -39,7 +36,7 @@ const Template = (args) => {
39
36
  <MlGeoJsonLayer
40
37
  type="line"
41
38
  layout={{ visibility: args.geojsonLayerVisible ? "visible" : "none" }}
42
- geojson={geojson}
39
+ geojson={sample_geojson_1}
43
40
  layerId="geojson1"
44
41
  />
45
42
  <MlGeoJsonLayer
@@ -1,8 +1,7 @@
1
- import { React, useEffect, useState } from "react";
2
- import { css, cx } from "@emotion/css";
1
+ import React from "react";
2
+ import { css } from "@emotion/css";
3
3
  import { Box } from "@mui/system";
4
4
  import ImageLoader from "../../../ui_components/ImageLoader";
5
- import { propsToClassKey } from "@mui/styles";
6
5
  import useMapState from "../../../hooks/useMapState";
7
6
 
8
7
  /**
@@ -10,8 +9,6 @@ import useMapState from "../../../hooks/useMapState";
10
9
  *
11
10
  */
12
11
  const LayerBox = (props) => {
13
- const [activeClassName, setActiveClassName] = useState("");
14
- const [className, setClassName] = useState("mllayerswitcher-layer-box ");
15
12
  const { layers } = useMapState({
16
13
  mapId: props.mapId,
17
14
  watch: {
@@ -23,33 +20,12 @@ const LayerBox = (props) => {
23
20
  matchLayerIds: props.layerId,
24
21
  },
25
22
  });
26
- const hoverBorderColor = "#1C62D7"; //Navy Blue
27
- const activeBorderColor = "";
28
23
  const width = "40px";
29
24
 
30
25
  const defaultClass = css`
31
26
  & img:hover {
32
27
  }
33
28
  `;
34
- const activeClass =
35
- defaultClass +
36
- `& img {
37
- border-color: rgb(196, 240, 0);
38
- border-radius: 8px;
39
- }
40
-
41
- `;
42
- const hoverClass = css``;
43
-
44
- useEffect(() => {
45
- const isActive = props.activeLayers?.indexOf(props.layerId) !== -1;
46
-
47
- if (isActive) {
48
- setClassName(activeClass);
49
- } else {
50
- setClassName(defaultClass);
51
- }
52
- }, [props.activeLayers]);
53
29
 
54
30
  return (
55
31
  <>
@@ -67,7 +67,6 @@ const MlMarker = (props) => {
67
67
  useEffect(() => {
68
68
  if (mapRef.current && iframe.current?.contentWindow?.document?.body?.scrollHeight) {
69
69
  setTimeout(() => {
70
- let mapWidth = mapRef.current._container.clientWidth;
71
70
  let mapHeight = mapRef.current._container.clientHeight;
72
71
 
73
72
  const _pixelPos = mapRef.current.project([props.lng, props.lat]);
@@ -124,6 +123,7 @@ const MlMarker = (props) => {
124
123
  ref={iframe}
125
124
  sandbox="allow-same-origin allow-popups-to-escape-sandbox"
126
125
  frameBorder="0"
126
+ title={componentId.current}
127
127
  ></iframe>
128
128
  </Paper>
129
129
  )}
@@ -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,7 @@ import React, { useState} from "react";
2
2
 
3
3
  import MlShareMapState from "./MlShareMapState";
4
4
  import mapContextDecorator from "../../decorators/MapContextDecorator";
5
+ import MlLayer from "../MlLayer/MlLayer";
5
6
 
6
7
  const storyoptions = {
7
8
  title: "MapComponents/MlShareMapState",
@@ -12,7 +13,8 @@ const storyoptions = {
12
13
  export default storyoptions;
13
14
 
14
15
  const Template = (args) => {
15
- const [watchState, setWatchState] = useState(true);
16
+ const [watchState, setWatchState] = useState(false);
17
+ const [testLayerVisible, setTestLayerVisible] = useState(true);
16
18
 
17
19
  return (
18
20
  <>
@@ -20,9 +22,27 @@ const Template = (args) => {
20
22
  style={{ zIndex: "1000", position: "absolute" }}
21
23
  onClick={() => setWatchState(!watchState)}
22
24
  >
23
- watch map state {watchState?1:0}
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}
24
32
  </button>
25
33
  <MlShareMapState active={watchState} />
34
+ <MlLayer
35
+ layerId={"MlLayer-testLayer"}
36
+ options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
37
+ />
38
+ <MlLayer
39
+ layerId={"MlLayer-testLayer2"}
40
+ options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
41
+ />
42
+ <MlLayer
43
+ layerId={"MlLayer-testLayer3"}
44
+ options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
45
+ />
26
46
  </>
27
47
  );
28
48
  };
@@ -5,9 +5,7 @@ import MlGPXViewer from "../MlGPXViewer/MlGPXViewer";
5
5
 
6
6
  import mapContextDecorator from "../../decorators/MapContextDecorator";
7
7
  import GeoJsonProvider from "../MlGPXViewer/util/GeoJsonProvider";
8
- import Button from "@mui/material/Button";
9
- import FileDownloadIcon from '@mui/icons-material/FileDownload';
10
- import InfoIcon from "@mui/icons-material/Info";
8
+ import FileDownloadIcon from "@mui/icons-material/FileDownload";
11
9
  import IconButton from "@mui/material/IconButton";
12
10
  import useMediaQuery from "@mui/material/useMediaQuery";
13
11