@mapcomponents/react-maplibre 0.1.12 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) 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 +893 -760
  5. package/coverage/coverage-final.json +22 -17
  6. package/coverage/lcov-report/index.html +183 -123
  7. package/coverage/lcov-report/{components → src/components}/MapLibreMap/MapLibreMap.js.html +10 -10
  8. package/coverage/lcov-report/{components → src/components}/MapLibreMap/index.html +10 -10
  9. package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/MlCreatePdfButton.js.html +10 -10
  10. package/coverage/lcov-report/{components → src/components}/MlCreatePdfButton/index.html +10 -10
  11. package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/MlFeatureEditor.js.html +10 -10
  12. package/coverage/lcov-report/{components → src/components}/MlFeatureEditor/index.html +10 -10
  13. package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +10 -10
  14. package/coverage/lcov-report/{components → src/components}/MlFillExtrusionLayer/index.html +10 -10
  15. package/coverage/lcov-report/{components → src/components}/MlFollowGps/MlFollowGps.js.html +148 -136
  16. package/coverage/lcov-report/{components → src/components}/MlFollowGps/index.html +24 -24
  17. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/MlGPXViewer.js.html +66 -60
  18. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/gpxConverter.js.html +49 -70
  19. package/coverage/lcov-report/{components → src/components}/MlGPXViewer/index.html +25 -25
  20. package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/MlGeoJsonLayer.js.html +155 -47
  21. package/coverage/lcov-report/{components → src/components}/MlGeoJsonLayer/index.html +28 -28
  22. package/coverage/lcov-report/{components/MlLayer/MlLayer.js.html → src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html} +88 -121
  23. package/coverage/lcov-report/{components → src/components}/MlImageMarkerLayer/index.html +28 -28
  24. package/coverage/lcov-report/{components/MlImageMarkerLayer/MlImageMarkerLayer.js.html → src/components/MlLayer/MlLayer.js.html} +116 -125
  25. package/coverage/lcov-report/src/components/MlLayer/index.html +117 -0
  26. package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/MlLayerMagnify.js.html +41 -41
  27. package/coverage/lcov-report/{components → src/components}/MlLayerMagnify/index.html +24 -24
  28. package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/MlLayerSwipe.js.html +38 -41
  29. package/coverage/lcov-report/{components → src/components}/MlLayerSwipe/index.html +24 -24
  30. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +755 -0
  31. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +380 -0
  32. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +117 -0
  33. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +117 -0
  34. package/coverage/lcov-report/{components → src/components}/MlMarker/MlMarker.js.html +11 -11
  35. package/coverage/lcov-report/{components → src/components}/MlMarker/index.html +10 -10
  36. package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/MlNavigationCompass.js.html +10 -10
  37. package/coverage/lcov-report/{components → src/components}/MlNavigationCompass/index.html +10 -10
  38. package/coverage/lcov-report/{components → src/components}/MlNavigationTools/MlNavigationTools.js.html +50 -41
  39. package/coverage/lcov-report/{components → src/components}/MlNavigationTools/index.html +18 -18
  40. package/coverage/lcov-report/{components → src/components}/MlOsmLayer/MlOsmLayer.js.html +10 -10
  41. package/coverage/lcov-report/{components → src/components}/MlOsmLayer/index.html +10 -10
  42. package/coverage/lcov-report/{components → src/components}/MlScaleReference/MlScaleReference.js.html +10 -10
  43. package/coverage/lcov-report/{components → src/components}/MlScaleReference/index.html +10 -10
  44. package/coverage/lcov-report/{components → src/components}/MlShareMapState/MlShareMapState.js.html +217 -25
  45. package/coverage/lcov-report/{components → src/components}/MlShareMapState/index.html +18 -18
  46. package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +10 -10
  47. package/coverage/lcov-report/{components → src/components}/MlSpatialElevationProfile/index.html +10 -10
  48. package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/MlThreeJsLayer.js.html +30 -54
  49. package/coverage/lcov-report/{components → src/components}/MlThreeJsLayer/index.html +24 -24
  50. package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/MlUseMapDebugger.js.html +10 -10
  51. package/coverage/lcov-report/{components → src/components}/MlUseMapDebugger/index.html +10 -10
  52. package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/MlVectorTileLayer.js.html +10 -10
  53. package/coverage/lcov-report/{components → src/components}/MlVectorTileLayer/index.html +10 -10
  54. package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +10 -10
  55. package/coverage/lcov-report/{components → src/components}/MlWmsFeatureInfoPopup/index.html +10 -10
  56. package/coverage/lcov-report/{components → src/components}/MlWmsLayer/MlWmsLayer.js.html +13 -13
  57. package/coverage/lcov-report/{components → src/components}/MlWmsLayer/index.html +14 -14
  58. package/coverage/lcov-report/{components → src/components}/MlWmsLoader/MlWmsLoader.js.html +31 -19
  59. package/coverage/lcov-report/{components → src/components}/MlWmsLoader/index.html +16 -16
  60. package/coverage/lcov-report/src/hooks/index.html +147 -0
  61. package/coverage/lcov-report/src/hooks/useMap.js.html +296 -0
  62. package/coverage/lcov-report/{hooks → src/hooks}/useMapState.js.html +91 -91
  63. package/coverage/lcov-report/{hooks → src/hooks}/useWms.js.html +18 -18
  64. package/coverage/lcov-report/src/i18n.js.html +167 -0
  65. package/coverage/lcov-report/src/index.html +117 -0
  66. package/coverage/lcov-report/src/translations/english.js.html +95 -0
  67. package/coverage/lcov-report/src/translations/german.js.html +95 -0
  68. package/coverage/lcov-report/src/translations/index.html +132 -0
  69. package/coverage/lcov.info +1610 -1314
  70. package/dist/b556faa3bc6829d2.png +0 -0
  71. package/dist/index.esm.js +934 -668
  72. package/dist/index.esm.js.map +1 -1
  73. package/package.json +3 -1
  74. package/public/assets/dop.png +0 -0
  75. package/public/assets/historic.png +0 -0
  76. package/public/assets/osm.png +0 -0
  77. package/public/thumbnails/MlFollowGps.png +0 -0
  78. package/public/thumbnails/MlThreeJsLayer.png +0 -0
  79. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +53 -67
  80. package/src/components/MlComponentTemplate/MlComponentTemplate.js +6 -31
  81. package/src/components/MlFeatureEditor/MlFeatureEditor.meta.json +2 -2
  82. package/src/components/MlFollowGps/MlFollowGps.js +92 -88
  83. package/src/components/MlFollowGps/MlFollowGps.meta.json +2 -2
  84. package/src/components/MlFollowGps/MlFollowGps.test.js +3 -5
  85. package/src/components/MlFollowGps/assets/marker.png +0 -0
  86. package/src/components/MlGPXViewer/MlGPXViewer.js +45 -43
  87. package/src/components/MlGPXViewer/gpxConverter.js +22 -29
  88. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +45 -9
  89. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +21 -57
  90. package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.test.js +6 -7
  91. package/src/components/MlLayer/MlLayer.js +28 -6
  92. package/src/components/MlLayer/MlLayer.test.js +12 -10
  93. package/src/components/MlLayerMagnify/MlLayerMagnify.js +3 -3
  94. package/src/components/MlLayerSwipe/MlLayerSwipe.js +4 -5
  95. package/src/components/MlLayerSwitcher/MlLayerSwitcher.css +17 -0
  96. package/src/components/MlLayerSwitcher/MlLayerSwitcher.doc.de.md +3 -0
  97. package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +223 -0
  98. package/src/components/MlLayerSwitcher/MlLayerSwitcher.meta_.json +15 -0
  99. package/src/components/MlLayerSwitcher/MlLayerSwitcher.stories.js +106 -0
  100. package/src/components/MlLayerSwitcher/assets/sample_1.json +26 -0
  101. package/src/components/MlLayerSwitcher/assets/sample_2.json +22 -0
  102. package/src/components/MlLayerSwitcher/components/LayerBox.js +98 -0
  103. package/src/components/MlMarker/MlMarker.js +1 -1
  104. package/src/components/MlNavigationTools/MlNavigationTools.js +29 -26
  105. package/src/components/MlScaleReference/MlScaleReference.meta.json +1 -1
  106. package/src/components/MlScaleReference/MlScaleReference.stories.js +25 -21
  107. package/src/components/MlShareMapState/MlShareMapState.js +73 -9
  108. package/src/components/MlShareMapState/MlShareMapState.stories.js +24 -1
  109. package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.js +12 -6
  110. package/src/components/MlThreeJsLayer/MlThreeJsLayer.js +8 -15
  111. package/src/components/MlWmsLayer/MlWmsLayer.js +1 -1
  112. package/src/components/MlWmsLoader/MlWmsLoader.js +8 -4
  113. package/src/components/MlWmsLoader/MlWmsLoader.meta.json +1 -1
  114. package/src/components/MlWmsLoader/MlWmsLoader.stories.js +5 -4
  115. package/src/decorators/EmptyMapContextDecorator.js +11 -6
  116. package/src/decorators/MapContext3DDecorator.js +25 -20
  117. package/src/decorators/MapContextDashboardDecorator.js +7 -2
  118. package/src/decorators/MapContextDecorator.js +7 -3
  119. package/src/decorators/MapContextKlokantechBasicDecorator.js +8 -4
  120. package/src/decorators/MultiMapContextDecorator.js +2 -1
  121. package/src/hooks/useMap.js +33 -62
  122. package/src/hooks/useMapState.js +3 -3
  123. package/src/hooks/useWms.js +7 -6
  124. package/src/i18n.js +28 -0
  125. package/src/index.js +3 -0
  126. package/src/translations/english.js +4 -0
  127. package/src/translations/german.js +4 -0
  128. package/src/ui_components/ImageLoader.js +73 -0
  129. package/src/ui_components/Sidebar.js +75 -20
  130. package/src/ui_components/TopToolbar.js +18 -18
  131. package/coverage/lcov-report/components/MlLayer/index.html +0 -117
  132. package/coverage/lcov-report/hooks/index.html +0 -147
  133. package/coverage/lcov-report/hooks/useMap.js.html +0 -383
@@ -1,21 +1,22 @@
1
- import React, { useContext, useRef, useEffect, useState } from "react";
1
+ import React, {useContext, useRef, useEffect, useState} from "react";
2
2
  import PropTypes from "prop-types";
3
- import { MapContext } from "@mapcomponents/react-core";
4
- import { bbox } from "@turf/turf";
3
+ import {MapContext} from "@mapcomponents/react-core";
4
+ import {bbox} from "@turf/turf";
5
5
  import Divider from "@mui/material/Divider";
6
6
  import Typography from "@mui/material/Typography";
7
7
  import Drawer from "@mui/material/Drawer";
8
8
  import IconButton from "@mui/material/IconButton";
9
9
  import InfoIcon from "@mui/icons-material/Info";
10
10
  import FileCopy from "@mui/icons-material/FileCopy";
11
- import { Popup } from "maplibre-gl";
11
+ import {Popup} from "maplibre-gl";
12
12
  import List from "@mui/material/List";
13
13
  import ListItem from "@mui/material/ListItem";
14
14
  import ListItemText from "@mui/material/ListItemText";
15
15
  import GeoJsonContext from "./util/GeoJsonContext";
16
16
  import toGeoJSON from "./gpxConverter";
17
+ import useMediaQuery from "@mui/material/useMediaQuery";
17
18
 
18
- import { v4 as uuidv4 } from "uuid";
19
+ import {v4 as uuidv4} from "uuid";
19
20
 
20
21
  /**
21
22
  * MlGPXViewer returns a dropzone and a button to load a GPX Track into the map.
@@ -38,6 +39,7 @@ const MlGPXViewer = (props) => {
38
39
  const [zIndex, setZIndex] = useState(0);
39
40
  const [metaData, setMetaData] = useState([]);
40
41
  const fileupload = useRef(null);
42
+ const mediaIsMobile = useMediaQuery("(max-width:900px)");
41
43
 
42
44
  const popup = useRef(
43
45
  new Popup({
@@ -255,42 +257,42 @@ const MlGPXViewer = (props) => {
255
257
  };
256
258
  return (
257
259
  <>
258
- <IconButton
259
- onClick={manualUpload}
260
- style={{
261
- position: "absolute",
262
- right: "5px",
263
- bottom: "75px",
264
- backgroundColor: "rgba(255,255,255,1)",
265
-
266
- zIndex: 1000,
267
- }}
268
- size="large"
269
- >
270
- <input
271
- ref={fileupload}
272
- onChange={fileUploadOnChange}
273
- type="file"
274
- id="input"
275
- multiple
276
- style={{ display: "none" }}
277
- ></input>
278
- <FileCopy />
279
- </IconButton>
280
- <IconButton
281
- onClick={toogleDrawer}
282
- style={{
283
- position: "absolute",
284
- right: "5px",
285
- bottom: "25px",
286
- backgroundColor: "rgba(255,255,255,1)",
287
-
288
- zIndex: 1000,
289
- }}
290
- size="large"
291
- >
292
- <InfoIcon />
293
- </IconButton>
260
+ <div style={{
261
+ position: "fixed",
262
+ right: "5px",
263
+ bottom: mediaIsMobile ? "40px" : "25px",
264
+ display: "flex",
265
+ flexDirection: "column",
266
+ gap: "5px",
267
+ zIndex: 1000,
268
+ }}>
269
+ <IconButton
270
+ onClick={manualUpload}
271
+ style={{
272
+ backgroundColor: "rgba(255,255,255,1)",
273
+ }}
274
+ size="large"
275
+ >
276
+ <input
277
+ ref={fileupload}
278
+ onChange={fileUploadOnChange}
279
+ type="file"
280
+ id="input"
281
+ multiple
282
+ style={{display: "none"}}
283
+ ></input>
284
+ <FileCopy/>
285
+ </IconButton>
286
+ <IconButton
287
+ onClick={toogleDrawer}
288
+ style={{
289
+ backgroundColor: "rgba(255,255,255,1)",
290
+ }}
291
+ size="large"
292
+ >
293
+ <InfoIcon/>
294
+ </IconButton>
295
+ </div>
294
296
  <Drawer variant="persistent" anchor="left" open={open}>
295
297
  <Typography
296
298
  variant="h6"
@@ -302,11 +304,11 @@ const MlGPXViewer = (props) => {
302
304
  >
303
305
  Informationen zur Route
304
306
  </Typography>
305
- <Divider />
307
+ <Divider/>
306
308
  <List>
307
309
  {metaData.map((item) => (
308
310
  <ListItem key={`item--${item.id}`}>
309
- <ListItemText primary={item.value} />
311
+ <ListItemText primary={item.value}/>
310
312
  </ListItem>
311
313
  ))}
312
314
  </List>
@@ -1,3 +1,16 @@
1
+ /**
2
+ * https://github.com/mapbox/togeojson
3
+ *
4
+ * Copyright (c) 2016 Mapbox All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9
+ *
10
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
+ *
12
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13
+ */
1
14
  var toGeoJSON = (function () {
2
15
  var removeSpace = /\s*/g,
3
16
  trimSpace = /^\s*|\s*$/g,
@@ -145,15 +158,11 @@ var toGeoJSON = (function () {
145
158
  styleByHash[hash] = styles[k];
146
159
  }
147
160
  for (var l = 0; l < styleMaps.length; l++) {
148
- styleIndex["#" + attr(styleMaps[l], "id")] = okhash(
149
- xml2str(styleMaps[l])
150
- ).toString(16);
161
+ styleIndex["#" + attr(styleMaps[l], "id")] = okhash(xml2str(styleMaps[l])).toString(16);
151
162
  var pairs = get(styleMaps[l], "Pair");
152
163
  var pairsMap = {};
153
164
  for (var m = 0; m < pairs.length; m++) {
154
- pairsMap[nodeVal(get1(pairs[m], "key"))] = nodeVal(
155
- get1(pairs[m], "styleUrl")
156
- );
165
+ pairsMap[nodeVal(get1(pairs[m], "key"))] = nodeVal(get1(pairs[m], "styleUrl"));
157
166
  }
158
167
  styleMapIndex["#" + attr(styleMaps[l], "id")] = pairsMap;
159
168
  }
@@ -183,8 +192,7 @@ var toGeoJSON = (function () {
183
192
  coords = [],
184
193
  times = [];
185
194
  if (elems.length === 0) elems = get(root, "gx:coord");
186
- for (var i = 0; i < elems.length; i++)
187
- coords.push(gxCoord(nodeVal(elems[i])));
195
+ for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
188
196
  var timeElems = get(root, "when");
189
197
  for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
190
198
  return {
@@ -322,26 +330,19 @@ var toGeoJSON = (function () {
322
330
  outline = nodeVal(get1(polyStyle, "outline"));
323
331
  if (pcolor) properties.fill = pcolor;
324
332
  if (!isNaN(popacity)) properties["fill-opacity"] = popacity;
325
- if (fill)
326
- properties["fill-opacity"] =
327
- fill === "1" ? properties["fill-opacity"] || 1 : 0;
333
+ if (fill) properties["fill-opacity"] = fill === "1" ? properties["fill-opacity"] || 1 : 0;
328
334
  if (outline)
329
- properties["stroke-opacity"] =
330
- outline === "1" ? properties["stroke-opacity"] || 1 : 0;
335
+ properties["stroke-opacity"] = outline === "1" ? properties["stroke-opacity"] || 1 : 0;
331
336
  }
332
337
  if (extendedData) {
333
338
  var datas = get(extendedData, "Data"),
334
339
  simpleDatas = get(extendedData, "SimpleData");
335
340
 
336
341
  for (i = 0; i < datas.length; i++) {
337
- properties[datas[i].getAttribute("name")] = nodeVal(
338
- get1(datas[i], "value")
339
- );
342
+ properties[datas[i].getAttribute("name")] = nodeVal(get1(datas[i], "value"));
340
343
  }
341
344
  for (i = 0; i < simpleDatas.length; i++) {
342
- properties[simpleDatas[i].getAttribute("name")] = nodeVal(
343
- simpleDatas[i]
344
- );
345
+ properties[simpleDatas[i].getAttribute("name")] = nodeVal(simpleDatas[i]);
345
346
  }
346
347
  }
347
348
  if (visibility) {
@@ -444,8 +445,7 @@ var toGeoJSON = (function () {
444
445
  if (track.length === 0) return;
445
446
  var properties = getProperties(node);
446
447
  extend(properties, getLineStyle(get1(node, "extensions")));
447
- if (times.length)
448
- properties.coordTimes = track.length === 1 ? times[0] : times;
448
+ if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
449
449
  if (heartRates.length)
450
450
  properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
451
451
  return {
@@ -501,14 +501,7 @@ var toGeoJSON = (function () {
501
501
  return style;
502
502
  }
503
503
  function getProperties(node) {
504
- var prop = getMulti(node, [
505
- "name",
506
- "cmt",
507
- "desc",
508
- "type",
509
- "time",
510
- "keywords",
511
- ]),
504
+ var prop = getMulti(node, ["name", "cmt", "desc", "type", "time", "keywords"]),
512
505
  links = get(node, "link");
513
506
  if (links.length) prop.links = [];
514
507
  for (var i = 0, link; i < links.length; i++) {
@@ -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);
@@ -34,11 +43,10 @@ const MlGeoJsonLayer = (props) => {
34
43
  let _componentId = componentId.current;
35
44
  return () => {
36
45
  // 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)
46
+ if (transitionTimeoutRef.current) {
47
+ clearTimeout(transitionTimeoutRef.current);
39
48
  }
40
49
  if (mapRef.current) {
41
-
42
50
  mapRef.current.cleanup(_componentId);
43
51
 
44
52
  mapRef.current = null;
@@ -48,11 +56,17 @@ const MlGeoJsonLayer = (props) => {
48
56
 
49
57
  useEffect(() => {
50
58
  if (!mapRef.current || !initializedRef.current) return;
51
- // the MapLibre-gl instance (mapContext.map) is accessible here
52
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
59
+
60
+ for (var key in props.layout) {
61
+ mapContext.getMap(props.mapId).setLayoutProperty(layerId.current, key, props.layout[key]);
62
+ }
63
+ }, [props.layout, mapContext, props.mapId]);
64
+
65
+ useEffect(() => {
66
+ if (!mapRef.current || !initializedRef.current) return;
53
67
 
54
68
  for (var key in props.paint) {
55
- mapContext.getMap(props.mapId).setPaintProperty(componentId.current, key, props.paint[key]);
69
+ mapContext.getMap(props.mapId).setPaintProperty(layerId.current, key, props.paint[key]);
56
70
  }
57
71
  }, [props.paint, mapContext, props.mapId]);
58
72
 
@@ -109,6 +123,19 @@ const MlGeoJsonLayer = (props) => {
109
123
  // initialize the layer and add it to the MapLibre-gl instance or do something else with it
110
124
 
111
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
+ }
112
139
  initializedRef.current = true;
113
140
  let geojson = props.geojson;
114
141
 
@@ -136,6 +163,7 @@ const MlGeoJsonLayer = (props) => {
136
163
  "line-color": "rgb(100,200,100)",
137
164
  "line-width": 10,
138
165
  },
166
+ layout: props.layout || {},
139
167
  },
140
168
  props.insertBeforeLayer,
141
169
  componentId.current
@@ -162,7 +190,7 @@ const MlGeoJsonLayer = (props) => {
162
190
  oldGeojsonRef.current = props.geojson;
163
191
  }
164
192
  }
165
- }, [mapContext.mapIds, mapContext, props, transitionToGeojson]);
193
+ }, [mapContext.mapIds, mapContext, props, transitionToGeojson, mapState.layers]);
166
194
 
167
195
  return <></>;
168
196
  };
@@ -178,8 +206,16 @@ MlGeoJsonLayer.propTypes = {
178
206
  */
179
207
  type: PropTypes.string,
180
208
  /**
181
- * Paint object, that is passed to the addLayer call.
182
- * Possible propsdepend on the layer type.
209
+ * Layout property object, that is passed to the addLayer call.
210
+ * Possible props depend on the layer type.
211
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#line
212
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#circle
213
+ * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#fill
214
+ */
215
+ layout: PropTypes.object,
216
+ /**
217
+ * Paint property object, that is passed to the addLayer call.
218
+ * Possible props depend on the layer type.
183
219
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#line
184
220
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#circle
185
221
  * https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#fill
@@ -1,36 +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(
10
- (props.idPrefix ? props.idPrefix : "MlOsmLayer-") + uuidv4()
11
- );
12
- const mapContext = useContext(MapContext);
6
+ const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
7
+
13
8
  const layerInitializedRef = useRef(false);
14
- const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
15
9
  const imageIdRef = useRef(props.imageId || "img_" + new Date().getTime());
16
- const layerId = useRef((props.layerId || "MlImageMarkerLayer-") + idSuffixRef.current);
17
-
18
- useEffect(() => {
19
- let _componentId = componentId.current;
20
- return () => {
21
- // This is the cleanup function, it is called when this react component is removed from react-dom
22
- if (mapRef.current) {
23
- mapRef.current.cleanup(_componentId);
24
-
25
- mapRef.current = null;
26
- }
27
- };
28
- }, []);
10
+ const layerId = useRef(props.layerId || "MlImageMarkerLayer-" + mapHook.componentId);
29
11
 
30
12
  useEffect(() => {
31
13
  if (
32
- !mapRef.current ||
33
- (mapRef.current && !mapContext.getMap(props.mapId).getLayer(layerId.current)) ||
14
+ !mapHook.mapIsReady ||
15
+ (mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
34
16
  !props.options
35
17
  )
36
18
  return;
@@ -40,19 +22,15 @@ const MlImageMarkerLayer = (props) => {
40
22
 
41
23
  if (props.options.layout) {
42
24
  for (key in props.options.layout) {
43
- mapContext
44
- .getMap(props.mapId)
45
- .setLayoutProperty(layerId.current, key, props.options.layout[key]);
25
+ mapHook.map.setLayoutProperty(layerId.current, key, props.options.layout[key]);
46
26
  }
47
27
  }
48
28
  if (props.options.paint) {
49
29
  for (key in props.options.paint) {
50
- mapContext
51
- .getMap(props.mapId)
52
- .setPaintProperty(layerId.current, key, props.options.paint[key]);
30
+ mapHook.map.setPaintProperty(layerId.current, key, props.options.paint[key]);
53
31
  }
54
32
  }
55
- }, [props.options, layerId.current, mapContext, props.mapId]);
33
+ }, [props.options, layerId.current, props.mapId]);
56
34
 
57
35
  const addLayer = useCallback(() => {
58
36
  let tmpOptions = {
@@ -61,49 +39,35 @@ const MlImageMarkerLayer = (props) => {
61
39
  ...props.options,
62
40
  };
63
41
  tmpOptions.layout["icon-image"] = imageIdRef.current;
64
- mapRef.current.addLayer(
65
- tmpOptions,
66
- props.insertBeforeLayer,
67
- componentId.current
68
- );
69
- }, [props]);
42
+ mapHook.map.addLayer(tmpOptions, props.insertBeforeLayer, mapHook.componentId);
43
+ }, [props, mapHook.mapIsReady, mapHook.map]);
70
44
 
71
45
  useEffect(() => {
72
- if (
73
- !props.options ||
74
- !mapContext.mapExists(props.mapId) ||
75
- layerInitializedRef.current
76
- )
77
- return;
78
-
79
- // the MapLibre-gl instance (mapContext.map) is accessible here
80
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
81
- mapRef.current = mapContext.getMap(props.mapId);
46
+ if (!props.options || !mapHook.mapIsReady || layerInitializedRef.current) return;
82
47
 
83
48
  layerInitializedRef.current = true;
84
49
 
85
50
  if (props.imgSrc) {
86
- mapRef.current.loadImage(props.imgSrc, function (error, image) {
51
+ mapHook.map.loadImage(props.imgSrc, function (error, image) {
87
52
  if (error) throw error;
88
- mapRef.current.addImage(imageIdRef.current, image, componentId.current);
53
+ mapHook.map.addImage(imageIdRef.current, image, mapHook.componentId);
89
54
  });
90
55
  }
56
+
91
57
  addLayer();
92
- }, [mapContext.mapIds, mapContext, props, addLayer]);
58
+ }, [mapHook.mapIsReady, mapHook.map, addLayer, props]);
93
59
 
94
60
  useEffect(() => {
95
61
  if (
96
- !mapRef.current ||
97
- (mapRef.current && !mapContext.getMap(props.mapId).getLayer(layerId.current)) ||
62
+ !mapHook.mapIsReady ||
63
+ (mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
98
64
  !props.options
99
65
  ) {
100
66
  return;
101
67
  }
102
- // the MapLibre-gl instance (mapContext.map) is accessible here
103
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
104
68
 
105
- mapRef.current.getSource(layerId.current).setData(props.options.source.data);
106
- }, [props.options.source.data, mapContext, props]);
69
+ mapHook.map.getSource(layerId.current).setData(props.options.source.data);
70
+ }, [props.options.source.data, props]);
107
71
 
108
72
  return <></>;
109
73
  };
@@ -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
  );
@@ -2,17 +2,25 @@ 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
- const layerId = (props.layerId || "MlLayer-") + idSuffixRef.current;
23
+ const layerId = useRef(props.layerId || componentId.current);
16
24
  const layerPaintConfRef = useRef(undefined);
17
25
  const layerLayoutConfRef = useRef(undefined);
18
26
 
@@ -60,12 +68,26 @@ 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;
66
88
  mapRef.current.addLayer(
67
89
  {
68
- id: layerId,
90
+ id: layerId.current,
69
91
  type: "background",
70
92
  paint: {
71
93
  "background-color": "rgba(0,0,0,0)",
@@ -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
  };
@@ -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 (