@mapcomponents/react-maplibre 0.1.9 → 0.1.13

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 (134) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +2 -2
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +3 -3
  3. package/.github/workflows/node_version_test.yml +25 -0
  4. package/.github/workflows/storybook.yml +6 -3
  5. package/CONTRIBUTING.md +2 -2
  6. package/README.md +3 -7
  7. package/coverage/clover.xml +748 -625
  8. package/coverage/coverage-final.json +19 -14
  9. package/coverage/lcov-report/block-navigation.js +8 -0
  10. package/coverage/lcov-report/index.html +170 -104
  11. package/coverage/lcov-report/sorter.js +26 -0
  12. package/coverage/lcov-report/{components → src/components}/MapLibreMap/MapLibreMap.js.html +17 -11
  13. package/coverage/lcov-report/{components → src/components}/MapLibreMap/index.html +17 -11
  14. package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/MlCreatePdfButton.js.html +17 -11
  15. package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/index.html +17 -11
  16. package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/MlFeatureEditor.js.html +17 -11
  17. package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/index.html +17 -11
  18. package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +17 -11
  19. package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/index.html +17 -11
  20. package/coverage/lcov-report/{components → src/components}/MlFollowGps/MlFollowGps.js.html +99 -48
  21. package/coverage/lcov-report/{components → src/components}/MlFollowGps/index.html +27 -21
  22. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/MlGPXViewer.js.html +73 -61
  23. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/gpxConverter.js.html +56 -71
  24. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/index.html +32 -26
  25. package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/MlGeoJsonLayer.js.html +91 -31
  26. package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/index.html +35 -29
  27. package/coverage/lcov-report/{components → src/components}/MlImageMarkerLayer/MlImageMarkerLayer.js.html +26 -23
  28. package/coverage/lcov-report/{components → src/components}/MlImageMarkerLayer/index.html +26 -20
  29. package/coverage/lcov-report/{components → src/components}/MlLayer/MlLayer.js.html +37 -31
  30. package/coverage/lcov-report/{components → src/components}/MlLayer/index.html +33 -27
  31. package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/MlLayerMagnify.js.html +48 -42
  32. package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/index.html +31 -25
  33. package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/MlLayerSwipe.js.html +45 -42
  34. package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/index.html +31 -25
  35. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +755 -0
  36. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +380 -0
  37. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +117 -0
  38. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +117 -0
  39. package/coverage/lcov-report/{components → src/components}/MlMarker/MlMarker.js.html +18 -12
  40. package/coverage/lcov-report/{components → src/components}/MlMarker/index.html +17 -11
  41. package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/MlNavigationCompass.js.html +17 -11
  42. package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/index.html +17 -11
  43. package/coverage/lcov-report/{components → src/components}/MlNavigationTools/MlNavigationTools.js.html +55 -37
  44. package/coverage/lcov-report/{components → src/components}/MlNavigationTools/index.html +23 -17
  45. package/coverage/lcov-report/{components → src/components}/MlOsmLayer/MlOsmLayer.js.html +17 -11
  46. package/coverage/lcov-report/{components → src/components}/MlOsmLayer/index.html +17 -11
  47. package/coverage/lcov-report/{components → src/components}/MlScaleReference/MlScaleReference.js.html +17 -11
  48. package/coverage/lcov-report/{components → src/components}/MlScaleReference/index.html +17 -11
  49. package/coverage/lcov-report/{components → src/components}/MlShareMapState/MlShareMapState.js.html +17 -11
  50. package/coverage/lcov-report/{components → src/components}/MlShareMapState/index.html +17 -11
  51. package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +17 -11
  52. package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/index.html +17 -11
  53. package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/MlThreeJsLayer.js.html +37 -55
  54. package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/index.html +31 -25
  55. package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/MlUseMapDebugger.js.html +17 -11
  56. package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/index.html +17 -11
  57. package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/MlVectorTileLayer.js.html +17 -11
  58. package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/index.html +17 -11
  59. package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +17 -11
  60. package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/index.html +17 -11
  61. package/coverage/lcov-report/{components → src/components}/MlWmsLayer/MlWmsLayer.js.html +20 -14
  62. package/coverage/lcov-report/{components → src/components}/MlWmsLayer/index.html +21 -15
  63. package/coverage/lcov-report/{components → src/components}/MlWmsLoader/MlWmsLoader.js.html +38 -20
  64. package/coverage/lcov-report/{components → src/components}/MlWmsLoader/index.html +23 -17
  65. package/coverage/lcov-report/{hooks → src/hooks}/index.html +17 -11
  66. package/coverage/lcov-report/{hooks → src/hooks}/useMap.js.html +17 -11
  67. package/coverage/lcov-report/{hooks → src/hooks}/useMapState.js.html +17 -11
  68. package/coverage/lcov-report/{hooks → src/hooks}/useWms.js.html +25 -19
  69. package/coverage/lcov-report/src/i18n.js.html +167 -0
  70. package/coverage/lcov-report/src/index.html +117 -0
  71. package/coverage/lcov-report/src/translations/english.js.html +95 -0
  72. package/coverage/lcov-report/src/translations/german.js.html +95 -0
  73. package/coverage/lcov-report/src/translations/index.html +132 -0
  74. package/coverage/lcov.info +1278 -1010
  75. package/dist/b556faa3bc6829d2.png +0 -0
  76. package/dist/index.esm.js +170 -109
  77. package/dist/index.esm.js.map +1 -1
  78. package/package.json +3 -1
  79. package/public/assets/dop.png +0 -0
  80. package/public/assets/historic.png +0 -0
  81. package/public/assets/osm.png +0 -0
  82. package/public/thumbnails/MlFollowGps.png +0 -0
  83. package/public/thumbnails/MlThreeJsLayer.png +0 -0
  84. package/rollup.config.js +10 -2
  85. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +58 -73
  86. package/src/components/MlCreatePdfButton/MlCreatePdfButton.meta.json +1 -1
  87. package/src/components/MlFeatureEditor/MlFeatureEditor.meta.json +2 -2
  88. package/src/components/MlFollowGps/MlFollowGps.js +46 -31
  89. package/src/components/MlFollowGps/MlFollowGps.meta.json +2 -2
  90. package/src/components/MlFollowGps/assets/marker.png +0 -0
  91. package/src/components/MlGPXViewer/MlGPXViewer.js +45 -43
  92. package/src/components/MlGPXViewer/gpxConverter.js +22 -29
  93. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +27 -9
  94. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.meta.json +1 -1
  95. package/src/components/MlGeoJsonLayer/util/transitionFunctions.js +19 -12
  96. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +3 -4
  97. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.test.js +6 -7
  98. package/src/components/MlLayer/MlLayer.js +2 -2
  99. package/src/components/MlLayer/MlLayer.test.js +12 -10
  100. package/src/components/MlLayerMagnify/MlLayerMagnify.js +3 -3
  101. package/src/components/MlLayerSwipe/MlLayerSwipe.js +4 -5
  102. package/src/components/MlLayerSwitcher/MlLayerSwitcher.css +17 -0
  103. package/src/components/MlLayerSwitcher/MlLayerSwitcher.doc.de.md +3 -0
  104. package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +223 -0
  105. package/src/components/MlLayerSwitcher/MlLayerSwitcher.meta_.json +15 -0
  106. package/src/components/MlLayerSwitcher/MlLayerSwitcher.stories.js +106 -0
  107. package/src/components/MlLayerSwitcher/assets/sample_1.json +26 -0
  108. package/src/components/MlLayerSwitcher/assets/sample_2.json +22 -0
  109. package/src/components/MlLayerSwitcher/components/LayerBox.js +98 -0
  110. package/src/components/MlMarker/MlMarker.js +1 -1
  111. package/src/components/MlNavigationTools/MlNavigationTools.js +26 -22
  112. package/src/components/MlScaleReference/MlScaleReference.meta.json +1 -1
  113. package/src/components/MlScaleReference/MlScaleReference.stories.js +25 -21
  114. package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.js +12 -6
  115. package/src/components/MlThreeJsLayer/MlThreeJsLayer.js +8 -15
  116. package/src/components/MlVectorTileLayer/MlVectorTileLayer.meta.json +3 -3
  117. package/src/components/MlWmsLayer/MlWmsLayer.js +1 -1
  118. package/src/components/MlWmsLoader/MlWmsLoader.js +8 -4
  119. package/src/components/MlWmsLoader/MlWmsLoader.meta.json +1 -1
  120. package/src/components/MlWmsLoader/MlWmsLoader.stories.js +5 -4
  121. package/src/decorators/EmptyMapContextDecorator.js +11 -6
  122. package/src/decorators/MapContext3DDecorator.js +25 -20
  123. package/src/decorators/MapContextDashboardDecorator.js +7 -7
  124. package/src/decorators/MapContextDecorator.js +7 -8
  125. package/src/decorators/MapContextKlokantechBasicDecorator.js +8 -9
  126. package/src/decorators/MultiMapContextDecorator.js +2 -6
  127. package/src/hooks/useMapState.stories.js +7 -2
  128. package/src/hooks/useWms.js +7 -6
  129. package/src/i18n.js +28 -0
  130. package/src/translations/english.js +4 -0
  131. package/src/translations/german.js +4 -0
  132. package/src/ui_components/ImageLoader.js +73 -0
  133. package/src/ui_components/Sidebar.js +76 -22
  134. package/src/ui_components/TopToolbar.js +18 -18
@@ -21,6 +21,7 @@ const MlGeoJsonLayer = (props) => {
21
21
  const mapRef = useRef(null);
22
22
  const initializedRef = useRef(false);
23
23
  const transitionInProgressRef = useRef(false);
24
+ const transitionTimeoutRef = useRef(undefined);
24
25
  const currentTransitionStepRef = useRef(false);
25
26
  const transitionGeojsonDataRef = useRef([]);
26
27
  const transitionGeojsonCommonDataRef = useRef([]);
@@ -33,6 +34,9 @@ const MlGeoJsonLayer = (props) => {
33
34
  let _componentId = componentId.current;
34
35
  return () => {
35
36
  // This is the cleanup function, it is called when this react component is removed from react-dom
37
+ if (transitionTimeoutRef.current) {
38
+ clearTimeout(transitionTimeoutRef.current);
39
+ }
36
40
  if (mapRef.current) {
37
41
  mapRef.current.cleanup(_componentId);
38
42
 
@@ -43,11 +47,17 @@ const MlGeoJsonLayer = (props) => {
43
47
 
44
48
  useEffect(() => {
45
49
  if (!mapRef.current || !initializedRef.current) return;
46
- // the MapLibre-gl instance (mapContext.map) is accessible here
47
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
50
+
51
+ for (var key in props.layout) {
52
+ mapContext.getMap(props.mapId).setLayoutProperty(layerId.current, key, props.layout[key]);
53
+ }
54
+ }, [props.layout, mapContext, props.mapId]);
55
+
56
+ useEffect(() => {
57
+ if (!mapRef.current || !initializedRef.current) return;
48
58
 
49
59
  for (var key in props.paint) {
50
- mapContext.getMap(props.mapId).setPaintProperty(componentId.current, key, props.paint[key]);
60
+ mapContext.getMap(props.mapId).setPaintProperty(layerId.current, key, props.paint[key]);
51
61
  }
52
62
  }, [props.paint, mapContext, props.mapId]);
53
63
 
@@ -63,7 +73,8 @@ const MlGeoJsonLayer = (props) => {
63
73
  msPerStep,
64
74
  currentTransitionStepRef,
65
75
  mapRef.current,
66
- componentId.current
76
+ componentId.current,
77
+ transitionTimeoutRef
67
78
  );
68
79
  },
69
80
  [props]
@@ -130,6 +141,7 @@ const MlGeoJsonLayer = (props) => {
130
141
  "line-color": "rgb(100,200,100)",
131
142
  "line-width": 10,
132
143
  },
144
+ layout: props.layout || {},
133
145
  },
134
146
  props.insertBeforeLayer,
135
147
  componentId.current
@@ -153,9 +165,7 @@ const MlGeoJsonLayer = (props) => {
153
165
  typeof props.geojson.geometry !== "undefined"
154
166
  ) {
155
167
  transitionToGeojson(props.geojson);
156
- setTimeout(() => {
157
- oldGeojsonRef.current = props.geojson;
158
- }, props.transitionTime / 2);
168
+ oldGeojsonRef.current = props.geojson;
159
169
  }
160
170
  }
161
171
  }, [mapContext.mapIds, mapContext, props, transitionToGeojson]);
@@ -174,8 +184,16 @@ MlGeoJsonLayer.propTypes = {
174
184
  */
175
185
  type: PropTypes.string,
176
186
  /**
177
- * Paint object, that is passed to the addLayer call.
178
- * Possible propsdepend on the layer type.
187
+ * Layout property object, that is passed to the addLayer call.
188
+ * Possible props depend on the layer type.
189
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#line
190
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#circle
191
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#fill
192
+ */
193
+ layout: PropTypes.object,
194
+ /**
195
+ * Paint property object, that is passed to the addLayer call.
196
+ * Possible props depend on the layer type.
179
197
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#line
180
198
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#circle
181
199
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#fill
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "MlGeoJsonLayer",
3
- "title": "GeoJSON level",
3
+ "title": "GeoJSON layer",
4
4
  "description": "",
5
5
  "i18n": {
6
6
  "de": {
@@ -8,13 +8,14 @@ const _showNextTransitionSegment = function (
8
8
  transitionGeojsonDataRef,
9
9
  transitionGeojsonCommonDataRef,
10
10
  currentTransitionStepRef,
11
- msPerStep
11
+ msPerStep,
12
+ transitionTimeoutRef
12
13
  ) {
13
14
  if (
14
15
  typeof map.getSource(layerId) === "undefined" ||
15
16
  !transitionInProgressRef.current
16
17
  ) {
17
- setTimeout(() => _showNextTransitionSegment(...arguments), msPerStep);
18
+ transitionTimeoutRef.current = setTimeout(() => _showNextTransitionSegment(...arguments), msPerStep);
18
19
  return;
19
20
  }
20
21
  if (
@@ -31,6 +32,10 @@ const _showNextTransitionSegment = function (
31
32
  .geometry.coordinates,
32
33
  ]);
33
34
 
35
+ if (!map?.getSource?.(layerId)) {
36
+ return;
37
+ }
38
+
34
39
  map.getSource(layerId).setData(newData);
35
40
 
36
41
  if (typeof props.onTransitionFrame === "function") {
@@ -42,7 +47,7 @@ const _showNextTransitionSegment = function (
42
47
  transitionInProgressRef.current &&
43
48
  currentTransitionStepRef.current < transitionGeojsonDataRef.current.length
44
49
  ) {
45
- setTimeout(() => _showNextTransitionSegment(...arguments), msPerStep);
50
+ transitionTimeoutRef.current = setTimeout(() => _showNextTransitionSegment(...arguments), msPerStep);
46
51
  } else {
47
52
  if (typeof props.onTransitionEnd === "function") {
48
53
  props.onTransitionEnd(props.geojson);
@@ -62,7 +67,8 @@ const _transitionToGeojson = (
62
67
  msPerStep,
63
68
  currentTransitionStepRef,
64
69
  map,
65
- layerId
70
+ layerId,
71
+ transitionTimeoutRef
66
72
  ) => {
67
73
  // create the transition geojson between oldGeojsonRef.current and props.geojson
68
74
 
@@ -189,12 +195,12 @@ const _transitionToGeojson = (
189
195
  );
190
196
  // for some reason turf.lineChunk returns the full lineString as element 0, chunks start at 1
191
197
  tmpLinestring = tmpChunks.features[1];
192
- for (i = 1; i < srcTransitionSteps; i++) {
198
+ for (i = 0; i < srcTransitionSteps; i++) {
193
199
  transitionGeojsonDataRef.current.push(tmpLinestring);
194
- if (typeof tmpChunks.features[i + 1] !== "undefined") {
200
+ if (typeof tmpChunks.features[i] !== "undefined") {
195
201
  tmpLinestring = turf.lineString([
196
202
  ...tmpLinestring.geometry.coordinates,
197
- ...tmpChunks.features[i + 1].geometry.coordinates,
203
+ ...tmpChunks.features[i].geometry.coordinates,
198
204
  ]);
199
205
  } else {
200
206
  transitionGeojsonDataRef.current.push(tmpLinestring);
@@ -212,12 +218,12 @@ const _transitionToGeojson = (
212
218
  );
213
219
  // for some reason turf.lineChunk returns the full lineString as element 0, chunks start at 1
214
220
  tmpLinestring = tmpChunks.features[1];
215
- for (i = 1; i < targetTransitionSteps; i++) {
221
+ for (i = 0; i < targetTransitionSteps; i++) {
216
222
  transitionGeojsonDataRef.current.push(tmpLinestring);
217
- if (typeof tmpChunks.features[i + 1] !== "undefined") {
223
+ if (typeof tmpChunks.features[i] !== "undefined") {
218
224
  tmpLinestring = turf.lineString([
219
225
  ...tmpLinestring.geometry.coordinates,
220
- ...tmpChunks.features[i + 1].geometry.coordinates,
226
+ ...tmpChunks.features[i].geometry.coordinates,
221
227
  ]);
222
228
  } else {
223
229
  transitionGeojsonDataRef.current.push(tmpLinestring);
@@ -229,7 +235,7 @@ const _transitionToGeojson = (
229
235
 
230
236
  currentTransitionStepRef.current = 1;
231
237
  transitionInProgressRef.current = true;
232
- setTimeout(
238
+ transitionTimeoutRef.current = setTimeout(
233
239
  () =>
234
240
  _showNextTransitionSegment(
235
241
  props,
@@ -239,7 +245,8 @@ const _transitionToGeojson = (
239
245
  transitionGeojsonDataRef,
240
246
  transitionGeojsonCommonDataRef,
241
247
  currentTransitionStepRef,
242
- msPerStep
248
+ msPerStep,
249
+ transitionTimeoutRef
243
250
  ),
244
251
  msPerStep
245
252
  );
@@ -6,14 +6,12 @@ import { MapContext } from "@mapcomponents/react-core";
6
6
  const MlImageMarkerLayer = (props) => {
7
7
  // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
8
8
  const mapRef = useRef(null);
9
- const componentId = useRef(
10
- (props.idPrefix ? props.idPrefix : "MlOsmLayer-") + uuidv4()
11
- );
9
+ const componentId = useRef((props.idPrefix ? props.idPrefix : "MlImageMarkerLayer-") + uuidv4());
12
10
  const mapContext = useContext(MapContext);
13
11
  const layerInitializedRef = useRef(false);
14
12
  const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
15
13
  const imageIdRef = useRef(props.imageId || "img_" + new Date().getTime());
16
- const layerId = useRef((props.layerId || "MlImageMarkerLayer-") + idSuffixRef.current);
14
+ const layerId = useRef(props.layerId || componentId.current);
17
15
 
18
16
  useEffect(() => {
19
17
  let _componentId = componentId.current;
@@ -82,6 +80,7 @@ const MlImageMarkerLayer = (props) => {
82
80
 
83
81
  layerInitializedRef.current = true;
84
82
 
83
+ console.log(props.imgSrc);
85
84
  if (props.imgSrc) {
86
85
  mapRef.current.loadImage(props.imgSrc, function (error, image) {
87
86
  if (error) throw error;
@@ -1,20 +1,19 @@
1
1
  import { layerRemovalTest, sourceRemovalTest } from "../../util";
2
+ import { uuid_regex } from "../../setupTests";
2
3
 
3
4
  import MlImageMarkerLayer from "./MlImageMarkerLayer";
4
5
 
5
- const testComponent = (
6
- <MlImageMarkerLayer options={{ source: {} }} imgSrc="testImage" />
7
- );
6
+ const testComponent = <MlImageMarkerLayer options={{ source: {} }} imgSrc="testImage" />;
8
7
 
9
8
  layerRemovalTest(
10
9
  "<MlImageMarkerLayer />",
11
10
  testComponent,
12
- /^.*\"MlImageMarkerLayer\-[0-9]*\".*$/,
13
- "MlImageMarkerLayer-{unix-timestamp}"
11
+ new RegExp('^.*"MlImageMarkerLayer-' + uuid_regex + '".*$'),
12
+ "MlImageMarkerLayer-{uuid}"
14
13
  );
15
14
  sourceRemovalTest(
16
15
  "<MlImageMarkerLayer />",
17
16
  testComponent,
18
- /^.*\"MlImageMarkerLayer\-[0-9]*\".*$/,
19
- "MlImageMarkerLayer-{unix-timestamp}"
17
+ new RegExp('^.*"MlImageMarkerLayer-' + uuid_regex + '".*$'),
18
+ "MlImageMarkerLayer-{uuid}"
20
19
  );
@@ -12,7 +12,7 @@ const MlLayer = (props) => {
12
12
  (props.layerId ? props.layerId : "MlLayer-") + uuidv4()
13
13
  );
14
14
  const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
15
- const layerId = (props.layerId || "MlLayer-") + idSuffixRef.current;
15
+ const layerId = useRef(props.layerId || componentId.current);
16
16
  const layerPaintConfRef = useRef(undefined);
17
17
  const layerLayoutConfRef = useRef(undefined);
18
18
 
@@ -65,7 +65,7 @@ const MlLayer = (props) => {
65
65
  layerInitializedRef.current = true;
66
66
  mapRef.current.addLayer(
67
67
  {
68
- id: layerId,
68
+ id: layerId.current,
69
69
  type: "background",
70
70
  paint: {
71
71
  "background-color": "rgba(0,0,0,0)",
@@ -5,6 +5,8 @@ import { MapContext, MapComponentsProvider } from "@mapcomponents/react-core";
5
5
  import MapLibreMap from "./../MapLibreMap/MapLibreMap";
6
6
  import MlLayer from "./MlLayer";
7
7
 
8
+ import { uuid_regex } from "../../setupTests";
9
+
8
10
  const MlLayerTestComponent = (props) => {
9
11
  const [layerVisible, setLayerVisible] = useState(true);
10
12
  const [refreshTrigger, setRefreshTrigger] = useState(0);
@@ -59,57 +61,57 @@ const createWrapper = () =>
59
61
  );
60
62
 
61
63
  describe("<MlLayer>", () => {
62
- it("should add a Layer with the id 'MlLayer-{unix-timestamp}' to the MapLibre instance", async () => {
64
+ it("should add a Layer with the id 'MlLayer-{uuid}' to the MapLibre instance", async () => {
63
65
  const wrapper = createWrapper();
64
66
 
65
67
  wrapper.find(".trigger_refresh").simulate("click");
66
68
 
67
69
  expect(
68
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".layers_json").text())
70
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".layers_json").text())
69
71
  ).toEqual(true);
70
72
  });
71
73
 
72
- it("should remove a Layer with the id 'MlLayer-{unix-timestamp}' from the MapLibre instance", async () => {
74
+ it("should remove a Layer with the id 'MlLayer-{uuid}' from the MapLibre instance", async () => {
73
75
  const wrapper = createWrapper();
74
76
 
75
77
  wrapper.find(".trigger_refresh").simulate("click");
76
78
 
77
79
  expect(
78
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".layers_json").text())
80
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".layers_json").text())
79
81
  ).toEqual(true);
80
82
 
81
83
  wrapper.find(".toggle_layer_visible").simulate("click");
82
84
  wrapper.find(".trigger_refresh").simulate("click");
83
85
 
84
86
  expect(
85
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".layers_json").text())
87
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".layers_json").text())
86
88
  ).toEqual(false);
87
89
  });
88
90
 
89
- it("should add a Source with the id 'MlLayer-{unix-timestamp}' to the MapLibre instance", async () => {
91
+ it("should add a Source with the id 'MlLayer-{uuid}' to the MapLibre instance", async () => {
90
92
  const wrapper = createWrapper();
91
93
 
92
94
  wrapper.find(".trigger_refresh").simulate("click");
93
95
 
94
96
  expect(
95
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".sources_json").text())
97
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".sources_json").text())
96
98
  ).toEqual(true);
97
99
  });
98
100
 
99
- it("should remove a Source with the id 'MlLayer-{unix-timestamp}' from the MapLibre instance", async () => {
101
+ it("should remove a Source with the id 'MlLayer-{uuid}' from the MapLibre instance", async () => {
100
102
  const wrapper = createWrapper();
101
103
 
102
104
  wrapper.find(".trigger_refresh").simulate("click");
103
105
 
104
106
  expect(
105
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".sources_json").text())
107
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".sources_json").text())
106
108
  ).toEqual(true);
107
109
 
108
110
  wrapper.find(".toggle_layer_visible").simulate("click");
109
111
  wrapper.find(".trigger_refresh").simulate("click");
110
112
 
111
113
  expect(
112
- /^.*\"MlLayer\-[0-9]*\".*$/.test(wrapper.find(".sources_json").text())
114
+ new RegExp('^.*"MlLayer-' + uuid_regex + '".*$').test(wrapper.find(".sources_json").text())
113
115
  ).toEqual(false);
114
116
  });
115
117
  });
@@ -29,7 +29,7 @@ const MlLayerMagnify = (props) => {
29
29
  if (!props.map1Id || !props.map2Id) {
30
30
  return false;
31
31
  }
32
- if (!mapContext.mapExists(props.map1Id) || !mapContext.mapExists(props.map2Id)) {
32
+ if (!mapContext.getMap(props.map1Id) || !mapContext.getMap(props.map2Id)) {
33
33
  return false;
34
34
  }
35
35
 
@@ -100,8 +100,8 @@ const MlLayerMagnify = (props) => {
100
100
 
101
101
  syncMoveInitializedRef.current = true;
102
102
  syncCleanupFunctionRef.current = syncMove(
103
- mapContext.getMap(props.map1Id),
104
- mapContext.getMap(props.map2Id)
103
+ mapContext.getMap(props.map1Id).map,
104
+ mapContext.getMap(props.map2Id).map
105
105
  );
106
106
 
107
107
  if (
@@ -22,7 +22,7 @@ const MlLayerSwipe = (props) => {
22
22
  if (!props.map1Id || !props.map2Id) {
23
23
  return false;
24
24
  }
25
- if (!mapContext.mapExists(props.map1Id) || !mapContext.mapExists(props.map2Id)) {
25
+ if (!mapContext.getMap(props.map1Id) || !mapContext.getMap(props.map2Id)) {
26
26
  return false;
27
27
  }
28
28
 
@@ -53,8 +53,7 @@ const MlLayerSwipe = (props) => {
53
53
  setSwipeX(swipeX_tmp);
54
54
  swipeXRef.current = swipeX_tmp;
55
55
 
56
- var clipA =
57
- "rect(0, " + (swipeXRef.current * bounds.width) / 100 + "px, 999em, 0)";
56
+ var clipA = "rect(0, " + (swipeXRef.current * bounds.width) / 100 + "px, 999em, 0)";
58
57
 
59
58
  mapContext.maps[props.map2Id].getContainer().style.clip = clipA;
60
59
  }
@@ -71,8 +70,8 @@ const MlLayerSwipe = (props) => {
71
70
 
72
71
  initializedRef.current = true;
73
72
  syncCleanupFunctionRef.current = syncMove(
74
- mapContext.getMap(props.map1Id),
75
- mapContext.getMap(props.map2Id)
73
+ mapContext.getMap(props.map1Id).map,
74
+ mapContext.getMap(props.map2Id).map
76
75
  );
77
76
  onMove({ clientX: mapContext.maps[props.map1Id].getCanvas().clientWidth / 2 });
78
77
  }, [mapContext.mapIds, mapContext, props, onMove, mapExists]);
@@ -0,0 +1,17 @@
1
+ .mllayerswitcher-layer-box.activeHighlight > .mllayerswitcher-layer-image {
2
+ border-color: rgb(181, 215, 238);
3
+ border-radius: 8px;
4
+ }
5
+ .mllayerswitcher-layer-box.activeHighlight > .mllayerswitcher-layer-text {
6
+ color: rgb(181, 215, 238) !important;
7
+
8
+ }
9
+
10
+ .mllayerswitcher-layer-box.active > .mllayerswitcher-layer-image {
11
+ border-color: rgb(196, 240, 0);
12
+ border-radius: 8px;
13
+ }
14
+ .mllayerswitcher-layer-box.active > .mllayerswitcher-layer-text {
15
+ color: rgb(252, 0, 0) !important;
16
+
17
+ }
@@ -0,0 +1,3 @@
1
+ # Component Beschreibung
2
+
3
+ Beschreibungstext
@@ -0,0 +1,223 @@
1
+ //CSS
2
+ import "@fontsource/roboto/300.css";
3
+ import "@fontsource/roboto/400.css";
4
+ import "@fontsource/roboto/500.css";
5
+ import { css, cx } from '@emotion/css'
6
+ import "./MlLayerSwitcher.css";
7
+ //External
8
+ import { useEffect, useContext, useState } from "react";
9
+ import PropTypes from "prop-types";
10
+ import { useTranslation } from "react-i18next";
11
+ import { Card, CardContent, Typography, Box } from "@mui/material";
12
+ //Internal
13
+ import { MapContext } from "@mapcomponents/react-core";
14
+ import LayerBox from "./components/LayerBox";
15
+ import Divider from "@mui/material/Divider";
16
+ import useMapState from "../../hooks/useMapState";
17
+ import LoadingOverlay from "../../ui_components/LoadingOverlay";
18
+ /**
19
+ * @component
20
+ *
21
+ *
22
+ */
23
+ const MlLayerSwitcher = (props) => {
24
+ const mapContext = useContext(MapContext);
25
+ const showBaseSources = !!props.baseSourceConfig?.layers?.length;
26
+ const showDetailLayer = !!props.detailLayerConfig?.layers?.length;
27
+ const { layers } = useMapState({
28
+ mapId: props.mapId,
29
+ watch: {
30
+ viewport: false,
31
+ layers: true,
32
+ sources: false,
33
+ },
34
+ filter: {},
35
+ });
36
+ const [activeLayers, setActiveLayers] = useState([]);
37
+ const [activeDetailLayers, setActiveDetailLayers] = useState([]);
38
+ const { t } = useTranslation();
39
+
40
+ useEffect(() => {
41
+ //Set base state to activate only the first layer
42
+ if (mapContext.map) {
43
+ const disableAllButFirst = (config, i) => {
44
+ const layers = getLayerListFromId(config.layerId);
45
+ const visible = i === 0 ? "visible" : "none";
46
+
47
+ layers.forEach((layer) => {
48
+ if (layer) {
49
+ changeLayerState(layer, visible);
50
+ }
51
+ });
52
+ };
53
+
54
+ props.baseSourceConfig.layers.forEach((config, i) => disableAllButFirst(config, i));
55
+ props.detailLayerConfig.layers.forEach((config, i) => disableAllButFirst(config, i));
56
+ }
57
+ return () => {
58
+ // This is the cleanup function, it is called when this react component is removed from react-dom
59
+ // try to remove anything this component has added to the MapLibre-gl instance
60
+ // e.g.: remove the layer
61
+ // mapContext.getMap(props.mapId).removeLayer(layerRef.current);
62
+ // check for the existence of map.style before calling getLayer or getSource
63
+ };
64
+ }, [mapContext.map]);
65
+
66
+ useEffect(() => {
67
+ if (mapContext.map?.style?._layers) {
68
+ let newactiveLayers = [];
69
+ let newactiveDetailLayers = [];
70
+ props.baseSourceConfig.layers.forEach((layerConfig) => {
71
+ const layers = getLayerListFromId(layerConfig.layerId);
72
+
73
+ layers.forEach((layer) => {
74
+ const visibilty = mapContext.map?.getLayoutProperty(layer, "visibility");
75
+ if (mapContext.map.baseLayers.indexOf(layer) !== -1) {
76
+ layer = "styleBase";
77
+ }
78
+
79
+ if (newactiveLayers.indexOf(layer) === -1 && visibilty === "visible") {
80
+ newactiveLayers.push(layer);
81
+ }
82
+ });
83
+ });
84
+ props.detailLayerConfig.layers.forEach(({ layerId }) => {
85
+ const visibilty = mapContext.map?.getLayoutProperty(layerId, "visibility");
86
+ if (newactiveDetailLayers.indexOf(layerId) === -1 && visibilty === "visible") {
87
+ newactiveDetailLayers.push(layerId);
88
+ }
89
+ });
90
+ setActiveLayers(newactiveLayers);
91
+
92
+ setActiveDetailLayers(newactiveDetailLayers);
93
+ }
94
+ }, [layers]);
95
+
96
+ const getLayerListFromId = (id) => {
97
+ return id === "styleBase" ? mapContext?.map.baseLayers : [id];
98
+ };
99
+
100
+ const handleDetailLayerBoxClick = (layerId) => {
101
+ const cfg = props.detailLayerConfig.layers.find((e) => e.layerId === layerId);
102
+ if (cfg.linkedTo) {
103
+ handleLayerBoxClick(cfg.linkedTo);
104
+ }
105
+ const nextVisiblityClickedLayer =
106
+ mapContext?.map.getLayer(layerId)?.getLayoutProperty("visibility") === "visible"
107
+ ? "none"
108
+ : "visible";
109
+ changeLayerState(layerId, nextVisiblityClickedLayer);
110
+ };
111
+
112
+ const handleLayerBoxClick = (id) => {
113
+ let layers = getLayerListFromId(id);
114
+ const nextVisiblityClickedLayer =
115
+ mapContext?.map.getLayer(layers[0])?.getLayoutProperty("visibility") === "visible"
116
+ ? "none"
117
+ : "visible";
118
+
119
+ props.baseSourceConfig.layers.forEach((config, i) => {
120
+ let layers = getLayerListFromId(config.layerId);
121
+ let visible = "none";
122
+ if (config.layerId === id) {
123
+ visible = nextVisiblityClickedLayer;
124
+ }
125
+
126
+ //To avoid disabling all base layers we activate the first one
127
+ if (nextVisiblityClickedLayer === "none" && i === 0) {
128
+ visible = "visible";
129
+ }
130
+ layers.forEach((layer) => {
131
+ if (layer) {
132
+ changeLayerState(layer, visible);
133
+ }
134
+ });
135
+ });
136
+ };
137
+
138
+ const changeLayerState = (layer, visible = "none") => {
139
+ mapContext.map?.setLayoutProperty(layer, "visibility", visible);
140
+ };
141
+
142
+ return (
143
+ <>
144
+ <Card sx={{ zIndex: 101, position: "absolute", minWidth: "200px" }}>
145
+ <CardContent>
146
+ {showBaseSources && (
147
+ <Box sx={{ minHeight: "150px" }}>
148
+ <Typography variant="h6">{t(props.baseSourceConfig.label || "Map type")}</Typography>
149
+ <Divider />
150
+ <Box sx={{ display: "flex", paddingTop: "1rem" }}>
151
+ {props.baseSourceConfig.layers.map(({ src, label, layerId }) => {
152
+ return (
153
+ <LayerBox
154
+ mapId={props.mapId}
155
+ key={layerId}
156
+ activeLayers={activeLayers}
157
+ label={t(label)}
158
+ layerId={layerId}
159
+ thumbnail={src}
160
+ handleLayerBoxClick={() => {
161
+ handleLayerBoxClick(layerId);
162
+ }}
163
+ />
164
+ );
165
+ })}
166
+ </Box>
167
+ </Box>
168
+ )}
169
+ {showDetailLayer && (
170
+ <Box sx={{ minHeight: "150px" }}>
171
+ <Typography variant="h6">{t("Map details")}</Typography>
172
+ <Divider />
173
+ <Box sx={{ display: "flex", paddingTop: "1rem" }}>
174
+ {props.detailLayerConfig.layers.map(({ src, label, layerId }) => {
175
+ return (
176
+ <LayerBox
177
+ mapId={props.mapId}
178
+ activeLayers={activeDetailLayers}
179
+ label={t(label)}
180
+ layerId={layerId}
181
+ key={layerId}
182
+ thumbnail={src}
183
+ handleLayerBoxClick={() => {
184
+ handleDetailLayerBoxClick(layerId);
185
+ }}
186
+ />
187
+ );
188
+ })}
189
+ </Box>
190
+ </Box>
191
+ )}
192
+ </CardContent>{" "}
193
+ </Card>
194
+ </>
195
+ );
196
+ };
197
+
198
+ MlLayerSwitcher.propTypes = {
199
+ baseSourceConfig: PropTypes.shape({
200
+ label: PropTypes.string,
201
+ layers: PropTypes.arrayOf(
202
+ PropTypes.shape({
203
+ layerId: PropTypes.string.isRequired,
204
+ src: PropTypes.string,
205
+ label: PropTypes.string.isRequired,
206
+ })
207
+ ),
208
+ }),
209
+ detailLayerConfig: PropTypes.shape({
210
+ label: PropTypes.string,
211
+ layers: PropTypes.arrayOf(
212
+ PropTypes.shape({
213
+ layerId: PropTypes.string.isRequired,
214
+ src: PropTypes.string,
215
+ label: PropTypes.string.isRequired,
216
+ linkedTo: PropTypes.string,
217
+ })
218
+ ),
219
+ }),
220
+ mapId: PropTypes.string,
221
+ };
222
+
223
+ export default MlLayerSwitcher;
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "MlLayerSwitcher",
3
+ "title": "Layer switcher",
4
+ "description": "",
5
+ "i18n": {
6
+ "de": {
7
+ "title": "Ebenen wechsler",
8
+ "description": ""
9
+ }
10
+ },
11
+ "tags": [],
12
+ "category": "",
13
+ "type": "component",
14
+ "price": 0
15
+ }