@mapcomponents/react-maplibre 0.1.24 → 0.1.28

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 (112) hide show
  1. package/CHANGELOG.md +72 -7
  2. package/coverage/clover.xml +461 -489
  3. package/coverage/coverage-final.json +21 -20
  4. package/coverage/lcov-report/index.html +94 -79
  5. package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.js.html +22 -22
  6. package/coverage/lcov-report/src/components/MapLibreMap/index.html +1 -1
  7. package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.js.html +11 -11
  8. package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +11 -11
  9. package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.js.html +1 -1
  10. package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +1 -1
  11. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +4 -4
  12. package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +1 -1
  13. package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.js.html +212 -77
  14. package/coverage/lcov-report/src/components/MlFollowGps/index.html +19 -19
  15. package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.js.html +129 -165
  16. package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +8 -8
  17. package/coverage/lcov-report/src/components/MlGPXViewer/index.html +20 -20
  18. package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js.html +45 -297
  19. package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +19 -19
  20. package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html +1 -1
  21. package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +1 -1
  22. package/coverage/lcov-report/src/components/MlLayer/MlLayer.js.html +2 -2
  23. package/coverage/lcov-report/src/components/MlLayer/index.html +1 -1
  24. package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.js.html +4 -4
  25. package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +1 -1
  26. package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.js.html +3 -3
  27. package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +1 -1
  28. package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +1 -1
  29. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
  30. package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
  31. package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
  32. package/coverage/lcov-report/src/components/MlMarker/MlMarker.js.html +1 -1
  33. package/coverage/lcov-report/src/components/MlMarker/index.html +1 -1
  34. package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.js.html +38 -104
  35. package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +19 -19
  36. package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.js.html +40 -139
  37. package/coverage/lcov-report/src/components/MlNavigationTools/index.html +15 -15
  38. package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +32 -155
  39. package/coverage/lcov-report/src/components/MlOsmLayer/index.html +19 -19
  40. package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +39 -198
  41. package/coverage/lcov-report/src/components/MlScaleReference/index.html +9 -9
  42. package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +1 -1
  43. package/coverage/lcov-report/src/components/MlShareMapState/index.html +1 -1
  44. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +4 -4
  45. package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
  46. package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +1 -1
  47. package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +1 -1
  48. package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.js.html +580 -0
  49. package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/index.html +116 -0
  50. package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
  51. package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
  52. package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.js.html +3 -3
  53. package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +1 -1
  54. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +1 -1
  55. package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +1 -1
  56. package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.js.html +8 -11
  57. package/coverage/lcov-report/src/components/MlWmsLayer/index.html +1 -1
  58. package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.js.html +1 -1
  59. package/coverage/lcov-report/src/components/MlWmsLoader/index.html +1 -1
  60. package/coverage/lcov-report/src/hooks/index.html +6 -6
  61. package/coverage/lcov-report/src/hooks/useMap.js.html +38 -26
  62. package/coverage/lcov-report/src/hooks/useMapState.js.html +47 -38
  63. package/coverage/lcov-report/src/hooks/useWms.js.html +2 -2
  64. package/coverage/lcov-report/src/i18n.js.html +1 -1
  65. package/coverage/lcov-report/src/index.html +1 -1
  66. package/coverage/lcov-report/src/translations/english.js.html +1 -1
  67. package/coverage/lcov-report/src/translations/german.js.html +1 -1
  68. package/coverage/lcov-report/src/translations/index.html +1 -1
  69. package/coverage/lcov.info +826 -882
  70. package/dist/index.esm.js +288 -517
  71. package/dist/index.esm.js.map +1 -1
  72. package/jsdoc.json +3 -3
  73. package/package.json +9 -9
  74. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +5 -1
  75. package/src/components/MapLibreMap/lib/MapLibreGlWrapper.test.js +3 -3
  76. package/src/components/MlFeatureEditor/MlFeatureEditor.test.js +2 -2
  77. package/src/components/MlFollowGps/MlFollowGps.js +99 -54
  78. package/src/components/MlFollowGps/MlFollowGps.test.js +1 -1
  79. package/src/components/MlGPXViewer/MlGPXViewer.js +69 -81
  80. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +6 -90
  81. package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.stories.js +4 -22
  82. package/src/components/MlGeoJsonLayer/util/getDefaultPaintPropsByType.js +2 -2
  83. package/src/components/MlNavigationCompass/MlNavigationCompass.js +17 -39
  84. package/src/components/MlNavigationCompass/MlNavigationCompass.test.js +3 -3
  85. package/src/components/MlNavigationTools/MlNavigationTools.js +30 -63
  86. package/src/components/MlOsmLayer/MlOsmLayer.js +15 -56
  87. package/src/components/MlOsmLayer/MlOsmLayer.stories.js +21 -10
  88. package/src/components/MlOsmLayer/MlOsmLayer.test.js +4 -4
  89. package/src/components/MlScaleReference/MlScaleReference.js +29 -82
  90. package/src/components/MlShareMapState/MlShareMapState.stories.js +1 -3
  91. package/src/components/MlThreeJsLayer/lib/GLTFLoader.js +2369 -2591
  92. package/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.doc.de.md +3 -0
  93. package/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.js +165 -0
  94. package/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.meta.json +15 -0
  95. package/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.stories.js +52 -0
  96. package/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.test.js +20 -0
  97. package/src/components/MlTransitionGeoJsonLayer/assets/sample_1.json +26 -0
  98. package/src/components/MlTransitionGeoJsonLayer/assets/sample_2.json +22 -0
  99. package/src/components/MlTransitionGeoJsonLayer/assets/sample_polygon_1.json +33 -0
  100. package/src/components/{MlGeoJsonLayer → MlTransitionGeoJsonLayer}/util/transitionFunctions.js +63 -97
  101. package/src/components/MlWmsLayer/MlWmsLayer.js +1 -2
  102. package/src/decorators/MapContextDecorator.js +5 -0
  103. package/src/decorators/MultiMapContextDecorator.js +6 -0
  104. package/src/hooks/useMap.js +8 -4
  105. package/src/hooks/useMapState.js +4 -1
  106. package/src/hooks/useWms.js +1 -1
  107. package/dist/b556faa3bc6829d2.png +0 -0
  108. package/src/components/MlFollowGps/assets/marker.png +0 -0
  109. package/src/decorators/EmptyMapContextDecorator.js +0 -25
  110. package/src/decorators/MapContext3DDecorator.js +0 -39
  111. package/src/decorators/MapContextDashboardDecorator.js +0 -19
  112. package/src/decorators/MapContextKlokantechBasicDecorator.js +0 -39
@@ -1,15 +1,11 @@
1
1
  import React, { useRef, useEffect, useCallback } from "react";
2
2
  import PropTypes from "prop-types";
3
3
 
4
- import * as turf from "@turf/turf";
5
-
6
4
  import useMap from "../../hooks/useMap";
7
5
 
8
- import { _transitionToGeojson } from "./util/transitionFunctions";
9
6
  import getDefaultPaintPropsByType from "./util/getDefaultPaintPropsByType";
10
7
  import getDefaulLayerTypeByGeometry from "./util/getDefaultLayerTypeByGeometry";
11
8
 
12
- const msPerStep = 50;
13
9
  const legalLayerTypes = ["circle", "fill", "line"];
14
10
 
15
11
  /**
@@ -24,23 +20,6 @@ const MlGeoJsonLayer = (props) => {
24
20
  const layerId = useRef(props.layerId || "MlGeoJsonLayer-" + mapHook.componentId);
25
21
  const layerTypeRef = useRef(undefined);
26
22
 
27
- // transition effect variables
28
- const oldGeojsonRef = useRef(null);
29
- const transitionInProgressRef = useRef(false);
30
- const transitionTimeoutRef = useRef(undefined);
31
- const currentTransitionStepRef = useRef(false);
32
- const transitionGeojsonDataRef = useRef([]);
33
- const transitionGeojsonCommonDataRef = useRef([]);
34
-
35
- useEffect(() => {
36
- return () => {
37
- // This is the cleanup function, it is called when this react component is removed from react-dom
38
- if (transitionTimeoutRef.current) {
39
- clearTimeout(transitionTimeoutRef.current);
40
- }
41
- };
42
- }, []);
43
-
44
23
  useEffect(() => {
45
24
  if (!mapHook.map || !initializedRef.current) return;
46
25
 
@@ -60,64 +39,15 @@ const MlGeoJsonLayer = (props) => {
60
39
  }
61
40
  }, [props.paint, mapHook.map, props.mapId, props.defaultPaintOverrides]);
62
41
 
63
- const transitionToGeojson = useCallback(
64
- (newGeojson) => {
65
- _transitionToGeojson(
66
- newGeojson,
67
- props,
68
- transitionGeojsonCommonDataRef,
69
- transitionGeojsonDataRef,
70
- transitionInProgressRef,
71
- oldGeojsonRef,
72
- msPerStep,
73
- currentTransitionStepRef,
74
- mapHook.map,
75
- layerId.current,
76
- transitionTimeoutRef
77
- );
78
- },
79
- [props, mapHook.map]
80
- );
81
-
82
42
  useEffect(() => {
83
43
  if (!mapHook?.map?.getSource(layerId.current) || !initializedRef.current) return;
84
44
 
85
- if (
86
- typeof props.transitionTime !== "undefined" &&
87
- props.type === "line" &&
88
- oldGeojsonRef.current
89
- ) {
90
- transitionInProgressRef.current = false;
91
- currentTransitionStepRef.current = false;
92
- transitionGeojsonDataRef.current = [];
93
- transitionGeojsonCommonDataRef.current = [];
94
- transitionToGeojson(props.geojson);
95
- } else {
96
- mapHook.map.getSource(layerId.current).setData(props.geojson);
97
- }
98
- oldGeojsonRef.current = props.geojson;
99
- }, [
100
- props.geojson,
101
- props.mapId,
102
- mapHook.map,
103
- props.type,
104
- transitionToGeojson,
105
- props.transitionTime,
106
- ]);
45
+ mapHook.map.getSource(layerId.current).setData(props.geojson);
46
+ }, [props.geojson, mapHook.map, props.type]);
107
47
 
108
48
  const createLayer = useCallback(() => {
109
49
  let geojson = props.geojson;
110
50
 
111
- if (
112
- props.type === "line" &&
113
- typeof props.transitionTime !== "undefined" &&
114
- props.transitionTime &&
115
- typeof props.geojson.geometry !== "undefined"
116
- ) {
117
- var tmpChunks = turf.lineChunk(props.geojson, 0.01);
118
- geojson = tmpChunks.features[0];
119
- }
120
-
121
51
  layerTypeRef.current = props.type || getDefaulLayerTypeByGeometry(props.geojson);
122
52
 
123
53
  mapHook.map.addLayer(
@@ -149,19 +79,10 @@ const MlGeoJsonLayer = (props) => {
149
79
  if (typeof props.onLeave !== "undefined") {
150
80
  mapHook.map.on("mouseleave", layerId.current, props.onLeave, mapHook.componentId);
151
81
  }
152
-
153
- if (
154
- props.type === "line" &&
155
- typeof props.transitionTime !== "undefined" &&
156
- typeof props.geojson.geometry !== "undefined"
157
- ) {
158
- transitionToGeojson(props.geojson);
159
- oldGeojsonRef.current = props.geojson;
160
- }
161
- }, [mapHook.map, props, transitionToGeojson]);
82
+ }, [mapHook, props]);
162
83
 
163
84
  useEffect(() => {
164
- if (!mapHook.mapIsReady || !props.geojson) return;
85
+ if (!mapHook.map || !props.geojson) return;
165
86
 
166
87
  if (
167
88
  initializedRef.current &&
@@ -169,6 +90,7 @@ const MlGeoJsonLayer = (props) => {
169
90
  layerTypeRef.current &&
170
91
  props.type !== layerTypeRef.current
171
92
  ) {
93
+ // remove (cleanup) & reinitialize the layer if type has changed
172
94
  mapHook.map.cleanup(mapHook.componentId);
173
95
  } else if (
174
96
  initializedRef.current &&
@@ -178,11 +100,10 @@ const MlGeoJsonLayer = (props) => {
178
100
  return;
179
101
  }
180
102
 
181
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
182
103
  initializedRef.current = true;
183
104
 
184
105
  createLayer();
185
- }, [mapHook.mapIsReady, createLayer, props]);
106
+ }, [mapHook, createLayer, props]);
186
107
 
187
108
  return <></>;
188
109
  };
@@ -247,11 +168,6 @@ MlGeoJsonLayer.propTypes = {
247
168
  * left/unhovered.
248
169
  */
249
170
  onLeave: PropTypes.func,
250
- /**
251
- * Creates transition animation whenever the geojson prop changes.
252
- * Only works with layer type "line" and LineString GeoJSON data.
253
- */
254
- transitionTime: PropTypes.number,
255
171
  };
256
172
 
257
173
  export default MlGeoJsonLayer;
@@ -1,12 +1,10 @@
1
- import React, { useState, useContext, useRef, useEffect } from "react";
1
+ import React from "react";
2
2
 
3
3
  import MlGeoJsonLayer from "./MlGeoJsonLayer";
4
4
 
5
5
  import mapContextDecorator from "../../decorators/MapContextDecorator";
6
- import { MapContext } from "@mapcomponents/react-core";
7
6
 
8
7
  import sample_geojson_1 from "./assets/sample_1.json";
9
- import sample_geojson_2 from "./assets/sample_2.json";
10
8
  import sample_polygon_geojson_1 from "./assets/sample_polygon_1.json";
11
9
 
12
10
  console.log(sample_polygon_geojson_1);
@@ -28,31 +26,15 @@ const Template = (props) => {
28
26
  </>
29
27
  );
30
28
  };
31
- const LinestringTransitionTemplate = (props) => {
32
- const mapContext = useContext(MapContext);
33
- const [geojson, setGeojson] = useState(sample_geojson_1);
34
- const initializedRef = useRef(false);
35
-
36
- useEffect(() => {
37
- if (!mapContext.getMap() || initializedRef.current) return;
38
-
39
- initializedRef.current = true;
40
- mapContext.getMap().setCenter({ lng: 7.137609868988648, lat: 50.74746799549129 });
41
- mapContext.getMap().setZoom(9.5);
42
-
43
- setTimeout(() => {
44
- setGeojson(sample_geojson_2);
45
- }, 4000);
46
- }, [geojson, mapContext]);
47
-
29
+ const LinestringTemplate = (props) => {
48
30
  return (
49
31
  <>
50
- <MlGeoJsonLayer type="line" geojson={geojson} transitionTime={2000} />
32
+ <MlGeoJsonLayer type="line" geojson={sample_geojson_1} />
51
33
  </>
52
34
  );
53
35
  };
54
36
 
55
- export const Linestring = LinestringTransitionTemplate.bind({});
37
+ export const Linestring = LinestringTemplate.bind({});
56
38
  Linestring.parameters = {};
57
39
  Linestring.args = {};
58
40
 
@@ -12,7 +12,7 @@ const getDefaultPaintPropsByType = (type, defaultPaintOverrides) => {
12
12
  return defaultPaintOverrides.line;
13
13
  }
14
14
  return {
15
- "line-color": "rgb(100,200,100)",
15
+ "line-color": "rgb(203,211,2)",
16
16
  "line-width": 5,
17
17
  };
18
18
  case "circle":
@@ -21,7 +21,7 @@ const getDefaultPaintPropsByType = (type, defaultPaintOverrides) => {
21
21
  return defaultPaintOverrides.circle;
22
22
  }
23
23
  return {
24
- "circle-color": "#44aaaa",
24
+ "circle-color": "rgba(10,240,256)",
25
25
  "circle-stroke-color": "#fff",
26
26
  "circle-stroke-width": 2,
27
27
  };
@@ -1,15 +1,13 @@
1
- import React, { useState, useRef, useEffect, useContext } from "react";
1
+ import React, { useState, useEffect } 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";
6
-
7
4
  import { ReactComponent as RotateRightIcon } from "./assets/rotate_right.svg";
8
5
  import { ReactComponent as RotateLeftIcon } from "./assets/rotate_left.svg";
9
6
  import { ReactComponent as NeedleIcon } from "./assets/needle.svg";
10
7
 
11
8
  import styled from "@emotion/styled";
12
9
  import { css } from "@emotion/css";
10
+ import useMap from "../../hooks/useMap";
13
11
 
14
12
  const NeedleButton = styled.div`
15
13
  width: 40%;
@@ -88,43 +86,23 @@ const RotateButton = styled.div`
88
86
  * @component
89
87
  */
90
88
  const MlNavigationCompass = (props) => {
91
- // Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
92
- const mapContext = useContext(MapContext);
93
-
94
- const initializedRef = useRef(false);
95
- const mapRef = useRef(undefined);
96
- const componentId = useRef((props.idPrefix ? props.idPrefix : "MlNavigationCompass-") + uuidv4());
97
-
89
+ const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
98
90
  const [bearing, setBearing] = useState(0);
99
91
 
100
92
  useEffect(() => {
101
- let _componentId = componentId.current;
102
-
103
- return () => {
104
- // This is the cleanup function, it is called when this react component is removed from react-dom
93
+ if (!mapHook.map) return;
105
94
 
106
- if (mapRef.current) {
107
- mapRef.current.cleanup(_componentId);
108
- mapRef.current = undefined;
109
- }
110
- initializedRef.current = false;
95
+ let _updateBearing = () => {
96
+ setBearing(Math.round(mapHook.map.getBearing()));
111
97
  };
112
- }, []);
113
98
 
114
- useEffect(() => {
115
- if (!mapContext.mapExists(props.mapId) || initializedRef.current) return;
116
- initializedRef.current = true;
117
- mapRef.current = mapContext.getMap(props.mapId);
99
+ mapHook.map.on("rotate", _updateBearing, mapHook.componentId);
100
+ _updateBearing();
118
101
 
119
- mapRef.current.on(
120
- "rotate",
121
- function () {
122
- setBearing(Math.round(mapRef.current.getBearing()));
123
- },
124
- componentId.current
125
- );
126
- setBearing(Math.round(mapRef.current.getBearing()));
127
- }, [mapContext.mapIds, mapContext, props.mapId]);
102
+ return () => {
103
+ mapHook.map.off("rotate", _updateBearing);
104
+ };
105
+ }, [mapHook.map, props.mapId]);
128
106
 
129
107
  return (
130
108
  <>
@@ -154,7 +132,7 @@ const MlNavigationCompass = (props) => {
154
132
  <RotateButton className={css({ ...props.rotateRightStyle })}>
155
133
  <RotateRightIcon
156
134
  onClick={() => {
157
- let bearing = Math.round(mapRef.current?.getBearing());
135
+ let bearing = Math.round(mapHook.map?.getBearing());
158
136
  let rest = Math.round(bearing % 90);
159
137
  if (bearing > 0) {
160
138
  rest = 90 - rest;
@@ -162,14 +140,14 @@ const MlNavigationCompass = (props) => {
162
140
  if (rest === 0) {
163
141
  rest = 90;
164
142
  }
165
- mapRef.current?.setBearing(Math.round(bearing + Math.abs(rest)));
143
+ mapHook.map?.setBearing(Math.round(bearing + Math.abs(rest)));
166
144
  }}
167
145
  ></RotateRightIcon>
168
146
  </RotateButton>
169
147
  <NeedleButton
170
148
  className={css({ ...props.needleStyle })}
171
149
  onClick={() => {
172
- mapRef.current?.setBearing(0);
150
+ mapHook.map?.setBearing(0);
173
151
  }}
174
152
  >
175
153
  <NeedleContainer
@@ -183,7 +161,7 @@ const MlNavigationCompass = (props) => {
183
161
  <RotateButton className={css({ ...props.rotateLeftStyle })}>
184
162
  <RotateLeftIcon
185
163
  onClick={() => {
186
- let bearing = Math.round(mapRef.current?.getBearing());
164
+ let bearing = Math.round(mapHook.map?.getBearing());
187
165
  let rest = Math.round(bearing % 90);
188
166
  if (bearing < 0) {
189
167
  rest = 90 + rest;
@@ -191,7 +169,7 @@ const MlNavigationCompass = (props) => {
191
169
  if (rest === 0) {
192
170
  rest = 90;
193
171
  }
194
- mapRef.current?.setBearing(Math.round(bearing - Math.abs(rest)));
172
+ mapHook.map?.setBearing(Math.round(bearing - Math.abs(rest)));
195
173
  }}
196
174
  ></RotateLeftIcon>
197
175
  </RotateButton>
@@ -48,7 +48,7 @@ describe("<MlNavigationCompass>", () => {
48
48
  );
49
49
 
50
50
  // MapLibreGlWrapper now subscribes to "data", "move" events on its own
51
- await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4));
51
+ await waitFor(() => expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(5));
52
52
  });
53
53
 
54
54
  it("should deregister 1 event listener to the maplibre instance", async () => {
@@ -59,10 +59,10 @@ describe("<MlNavigationCompass>", () => {
59
59
  );
60
60
 
61
61
  // MapLibreGlWrapper now subscribes to "data", "move" events on its own
62
- expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(4);
62
+ expect(mockMapLibreMethods.on).toHaveBeenCalledTimes(5);
63
63
 
64
64
  wrapper.find(".toggle_layer_visible").simulate("click");
65
65
 
66
- expect(mockMapLibreMethods.off).toHaveBeenCalledTimes(1);
66
+ expect(mockMapLibreMethods.off).toHaveBeenCalledTimes(2);
67
67
  });
68
68
  });
@@ -1,25 +1,17 @@
1
- import React from "react";
2
-
3
- import {MapContext} from "@mapcomponents/react-core";
4
- import {useEffect, useRef, useContext, useState} from "react";
1
+ import React, { useEffect, useState } from "react";
5
2
  import Button from "@mui/material/Button";
6
3
  import ButtonGroup from "@mui/material/ButtonGroup";
7
4
  import ControlPointIcon from "@mui/icons-material/ControlPoint";
8
5
  import RemoveCircleOutlineIcon from "@mui/icons-material/RemoveCircleOutline";
9
- //import ZoomOutIcon from "@mui/icons-material/ZoomOut";
10
- //import ZoomInIcon from "@mui/icons-material/ZoomIn";
11
6
  import GpsFixedIcon from "@mui/icons-material/GpsFixed";
12
- import {v4 as uuidv4} from "uuid";
13
7
 
14
8
  import MlNavigationCompass from "../MlNavigationCompass/MlNavigationCompass";
15
9
  import MlFollowGps from "../MlFollowGps/MlFollowGps";
16
10
  import useMediaQuery from "@mui/material/useMediaQuery";
11
+ import useMap from "../../hooks/useMap";
17
12
 
18
13
  const MlNavigationTools = (props) => {
19
- const mapContext = useContext(MapContext);
20
- const initializedRef = useRef(false);
21
- const mapRef = useRef(undefined);
22
- const componentId = useRef((props.idPrefix ? props.idPrefix : "MlComponentTemplate-") + uuidv4());
14
+ const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
23
15
 
24
16
  const [pitch, setPitch] = useState(0);
25
17
  const [locationAccessDenied, setLocationAccessDenied] = useState(false);
@@ -38,67 +30,42 @@ const MlNavigationTools = (props) => {
38
30
  ":hover": {
39
31
  backgroundColor: "#515151",
40
32
  },
41
- color: "#ececec"
33
+ color: "#ececec",
42
34
  };
43
35
 
44
36
  useEffect(() => {
45
- let _componentId = componentId.current;
46
-
47
- return () => {
48
- // This is the cleanup function, it is called when this react component is removed from react-dom
49
- // try to remove anything this component has added to the MapLibre-gl instance
50
- // e.g.: remove the layer
51
- // mapContext.getMap(props.mapId).removeLayer(layerRef.current);
52
- // check for the existence of map.style before calling getLayer or getSource
53
-
54
- if (mapRef.current) {
55
- mapRef.current.cleanup(_componentId);
56
- mapRef.current = undefined;
57
- }
58
- initializedRef.current = false;
59
- };
60
- }, []);
37
+ if (!mapHook.map) return;
61
38
 
62
- useEffect(() => {
63
- if (!mapContext.mapExists(props.mapId) || initializedRef.current) return;
64
- // the MapLibre-gl instance (mapContext.getMap(props.mapId)) is accessible here
65
- // initialize the layer and add it to the MapLibre-gl instance or do something else with it
66
- initializedRef.current = true;
67
- mapRef.current = mapContext.getMap(props.mapId);
68
- mapRef.current.on(
69
- "pitchend",
70
- () => {
71
- setPitch(mapRef.current.getPitch());
72
- },
73
- componentId.current
74
- );
75
- setPitch(mapRef.current.getPitch());
76
- }, [mapContext.mapIds, mapContext, props.mapId]);
39
+ mapHook.map.on("pitchend", () => {
40
+ setPitch(mapHook.map.getPitch());
41
+ });
42
+ setPitch(mapHook.map.getPitch());
43
+ }, [mapHook.map, props.mapId]);
77
44
 
78
45
  const zoomIn = () => {
79
- if (!mapRef.current) return;
46
+ if (!mapHook.map) return;
80
47
 
81
- if (mapRef.current.transform._zoom + 0.5 <= mapRef.current.transform._maxZoom) {
82
- mapRef.current.easeTo({zoom: mapRef.current.transform._zoom + 0.5});
48
+ if (mapHook.map.transform._zoom + 0.5 <= mapHook.map.transform._maxZoom) {
49
+ mapHook.map.easeTo({ zoom: mapHook.map.transform._zoom + 0.5 });
83
50
  }
84
51
  };
85
52
 
86
53
  const zoomOut = () => {
87
- if (!mapRef.current) return;
54
+ if (!mapHook.map) return;
88
55
 
89
- if (mapRef.current.transform._zoom - 0.5 >= mapRef.current.transform._minZoom) {
90
- mapRef.current.easeTo({zoom: mapRef.current.transform._zoom - 0.5});
56
+ if (mapHook.map.transform._zoom - 0.5 >= mapHook.map.transform._minZoom) {
57
+ mapHook.map.easeTo({ zoom: mapHook.map.transform._zoom - 0.5 });
91
58
  }
92
59
  };
93
60
 
94
61
  const adjustPitch = () => {
95
- if (!mapRef.current) return;
62
+ if (!mapHook.map) return;
96
63
 
97
64
  let targetPitch = 60;
98
- if (mapRef.current.getPitch() !== 0) {
65
+ if (mapHook.map.getPitch() !== 0) {
99
66
  targetPitch = 0;
100
67
  }
101
- mapRef.current.easeTo({pitch: targetPitch});
68
+ mapHook.map.easeTo({ pitch: targetPitch });
102
69
  };
103
70
 
104
71
  const moveToCurrentLocation = () => {
@@ -106,7 +73,7 @@ const MlNavigationTools = (props) => {
106
73
  };
107
74
 
108
75
  const getLocationSuccess = (location) => {
109
- mapRef.current.setCenter([location.coords.longitude, location.coords.latitude]);
76
+ mapHook.map.setCenter([location.coords.longitude, location.coords.latitude]);
110
77
  };
111
78
 
112
79
  const getLocationError = () => {
@@ -131,33 +98,33 @@ const MlNavigationTools = (props) => {
131
98
  position: "relative",
132
99
  height: mediaIsMobile ? "55px" : "45px",
133
100
  marginLeft: mediaIsMobile ? "3px" : "-5px",
134
- transform: mediaIsMobile ? "scale(1.6)" : "scale(1)"
101
+ transform: mediaIsMobile ? "scale(1.6)" : "scale(1)",
135
102
  }}
136
103
  backgroundStyle={{
137
104
  boxShadow: "0px 0px 18px rgba(0,0,0,.5)",
138
105
  }}
139
106
  />
140
- <Button sx={{...buttonStyle, fontWeight: 600}} onClick={adjustPitch}>
107
+ <Button sx={{ ...buttonStyle, fontWeight: 600 }} onClick={adjustPitch}>
141
108
  {pitch ? "2D" : "3D"}
142
109
  </Button>
143
110
  <Button sx={buttonStyle} onClick={moveToCurrentLocation} disabled={locationAccessDenied}>
144
- <GpsFixedIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
111
+ <GpsFixedIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
145
112
  </Button>
146
- <MlFollowGps style={{...(({color, ...rest}) => rest)(buttonStyle)}} />
113
+ <MlFollowGps style={{ ...(({ color, ...rest }) => rest)(buttonStyle) }} />
147
114
  <ButtonGroup
148
115
  orientation="vertical"
149
116
  sx={{
150
117
  width: "50px",
151
118
  border: "none",
152
- Button: {minWidth: "20px !important", border: "none", padding: 0},
153
- "Button:hover": {border: "none"},
119
+ Button: { minWidth: "20px !important", border: "none", padding: 0 },
120
+ "Button:hover": { border: "none" },
154
121
  }}
155
122
  >
156
- <Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomIn}>
157
- <ControlPointIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
123
+ <Button sx={{ ...buttonStyle, color: "#ececec" }} onClick={zoomIn}>
124
+ <ControlPointIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
158
125
  </Button>
159
- <Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomOut}>
160
- <RemoveCircleOutlineIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
126
+ <Button sx={{ ...buttonStyle, color: "#ececec" }} onClick={zoomOut}>
127
+ <RemoveCircleOutlineIcon sx={{ fontSize: mediaIsMobile ? "1.5em" : "1.2em" }} />
161
128
  </Button>
162
129
  </ButtonGroup>
163
130
  </div>
@@ -1,9 +1,7 @@
1
- import React, { useContext, useRef, useEffect, useState } from "react";
2
- import { MapContext } from "@mapcomponents/react-core";
3
- import { v4 as uuidv4 } from "uuid";
1
+ import React, { useRef, useEffect, useState } from "react";
4
2
 
5
- import Button from "@mui/material/Button";
6
3
  import PropTypes from "prop-types";
4
+ import useMap from "../../hooks/useMap";
7
5
 
8
6
  /**
9
7
  * Adds a standard OSM tile layer to the maplibre-gl instancereference by
@@ -12,81 +10,42 @@ import PropTypes from "prop-types";
12
10
  * @component
13
11
  */
14
12
  const MlOsmLayer = (props) => {
15
- const mapContext = useContext(MapContext);
16
- const mapRef = useRef(undefined);
13
+ const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
17
14
 
18
- const [showLayer, setShowLayer] = useState(true);
19
- const componentId = useRef((props.idPrefix ? props.idPrefix : "MlOsmLayer-") + uuidv4());
20
- const initializedRef = useRef(false);
21
- const sourceIdRef = useRef((props.idPrefix ? props.idPrefix : "MlOsmLayer-source-") + uuidv4());
22
- const layerIdRef = useRef((props.idPrefix ? props.idPrefix : "MlOsmLayer-layer-") + uuidv4());
15
+ const layerId = useRef(props.layerId || "MlOsmLayer-" + mapHook.componentId);
23
16
 
24
17
  useEffect(() => {
25
- let _componentId = componentId.current;
26
- return () => {
27
- // This is the cleanup function, it is called when this react component is removed from react-dom
28
- if (mapRef.current) {
29
- mapRef.current.cleanup(_componentId);
18
+ if (!mapHook.map) return;
30
19
 
31
- mapRef.current = null;
32
- }
33
- };
34
- }, []);
35
-
36
- useEffect(() => {
37
- if (!mapContext.mapExists(props.mapId) || initializedRef.current) return;
38
-
39
- initializedRef.current = true;
40
- mapRef.current = mapContext.getMap(props.mapId);
41
-
42
- mapRef.current.addSource(
43
- sourceIdRef.current,
20
+ mapHook.map.addSource(
21
+ layerId.current,
44
22
  {
45
23
  type: "raster",
46
24
  tileSize: 256,
47
25
  ...props.sourceOptions,
48
26
  },
49
- componentId.current
27
+ mapHook.componentId
50
28
  );
51
- mapRef.current.addLayer(
29
+ mapHook.map.addLayer(
52
30
  {
53
- id: layerIdRef.current,
31
+ id: layerId.current,
54
32
  type: "raster",
55
- source: sourceIdRef.current,
33
+ source: layerId.current,
56
34
  minzoom: 0,
57
35
  maxzoom: 22,
58
36
  ...props.layerOptions,
59
37
  },
60
38
  props.insertBeforeLayer,
61
- componentId.current
39
+ mapHook.componentId
62
40
  );
63
- }, [mapContext.mapIds, props, mapContext]);
64
-
65
- useEffect(() => {
66
- if (!mapRef.current) return;
67
-
68
- // toggle layer visibility by changing the layout object's visibility property
69
- if (showLayer) {
70
- mapRef.current.setLayoutProperty(layerIdRef.current, "visibility", "visible");
71
- } else {
72
- mapRef.current.setLayoutProperty(layerIdRef.current, "visibility", "none");
73
- }
74
- }, [showLayer]);
41
+ }, [props, mapHook.map]);
75
42
 
76
- return (
77
- <Button
78
- color="primary"
79
- variant={showLayer ? "contained" : "outlined"}
80
- onClick={() => setShowLayer(!showLayer)}
81
- >
82
- OSM
83
- </Button>
84
- );
43
+ return <></>;
85
44
  };
86
45
 
87
46
  MlOsmLayer.propTypes = {
88
47
  /**
89
- * Id of the target MapLibre instance in mapContext
48
+ * Id of the target MapLibre instance in mapHook
90
49
  */
91
50
  mapId: PropTypes.string,
92
51
  /**