@mapcomponents/react-maplibre 0.1.13 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/storybook.yml +4 -2
- package/CHANGELOG.md +33 -0
- package/README.md +22 -6
- package/coverage/clover.xml +447 -460
- package/coverage/coverage-final.json +14 -14
- package/coverage/lcov-report/index.html +77 -78
- package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.js.html +2 -3
- package/coverage/lcov-report/src/components/MapLibreMap/index.html +2 -3
- package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.js.html +2 -3
- package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +2 -3
- package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.js.html +2 -3
- package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +2 -3
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.js.html +112 -107
- package/coverage/lcov-report/src/components/MlFollowGps/index.html +16 -17
- package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +2 -3
- package/coverage/lcov-report/src/components/MlGPXViewer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js.html +142 -134
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +20 -21
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js.html +46 -152
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +20 -21
- package/coverage/lcov-report/src/components/MlLayer/MlLayer.js.html +92 -30
- package/coverage/lcov-report/src/components/MlLayer/index.html +20 -21
- package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.js.html +2 -3
- package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +2 -3
- package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.js.html +2 -3
- package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +2 -3
- package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +3 -10
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +9 -82
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +10 -11
- package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +2 -3
- package/coverage/lcov-report/src/components/MlMarker/MlMarker.js.html +6 -7
- package/coverage/lcov-report/src/components/MlMarker/index.html +6 -7
- package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.js.html +2 -3
- package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +2 -3
- package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.js.html +11 -15
- package/coverage/lcov-report/src/components/MlNavigationTools/index.html +8 -9
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlOsmLayer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +2 -3
- package/coverage/lcov-report/src/components/MlScaleReference/index.html +2 -3
- package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +209 -18
- package/coverage/lcov-report/src/components/MlShareMapState/index.html +10 -11
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +2 -3
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +2 -3
- package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +6 -25
- package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +6 -7
- package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +2 -3
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +2 -3
- package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.js.html +2 -3
- package/coverage/lcov-report/src/components/MlWmsLayer/index.html +2 -3
- package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.js.html +6 -19
- package/coverage/lcov-report/src/components/MlWmsLoader/index.html +8 -9
- package/coverage/lcov-report/src/hooks/index.html +35 -36
- package/coverage/lcov-report/src/hooks/useMap.js.html +81 -169
- package/coverage/lcov-report/src/hooks/useMapState.js.html +82 -125
- package/coverage/lcov-report/src/hooks/useWms.js.html +9 -22
- package/coverage/lcov-report/src/i18n.js.html +2 -3
- package/coverage/lcov-report/src/index.html +2 -3
- package/coverage/lcov-report/src/translations/english.js.html +2 -3
- package/coverage/lcov-report/src/translations/german.js.html +2 -3
- package/coverage/lcov-report/src/translations/index.html +2 -3
- package/coverage/lcov.info +891 -896
- package/dist/index.esm.js +941 -717
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/MapLibreMap/lib/MapLibreGlWrapper.js +16 -14
- package/src/components/MlComponentTemplate/MlComponentTemplate.js +7 -32
- package/src/components/MlFollowGps/MlFollowGps.js +67 -65
- package/src/components/MlFollowGps/MlFollowGps.test.js +3 -5
- package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.js +91 -88
- package/src/components/MlGeoJsonLayer/MlGeoJsonLayer.stories.js +20 -6
- package/src/components/MlGeoJsonLayer/assets/sample_polygon_1.json +33 -0
- package/src/components/MlGeoJsonLayer/util/getDefaultLayerTypeByGeometry.js +25 -0
- package/src/components/MlGeoJsonLayer/util/getDefaultPaintPropsByType.js +22 -0
- package/src/components/MlImageMarkerLayer/MlImageMarkerLayer.js +21 -56
- package/src/components/MlLayer/MlLayer.js +26 -5
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.js +0 -2
- package/src/components/MlLayerSwitcher/MlLayerSwitcher.stories.js +3 -6
- package/src/components/MlLayerSwitcher/components/LayerBox.js +2 -26
- package/src/components/MlMarker/MlMarker.js +1 -1
- package/src/components/MlNavigationTools/MlNavigationTools.js +4 -5
- package/src/components/MlShareMapState/MlShareMapState.js +73 -9
- package/src/components/MlShareMapState/MlShareMapState.stories.js +22 -2
- package/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.stories.js +1 -3
- package/src/components/MlUseMapDebugger/MlUseMapDebugger.js +1 -7
- package/src/components/MlWmsLoader/MlWmsLoader.js +0 -4
- package/src/hooks/useMap.js +33 -62
- package/src/hooks/useMapState.js +3 -17
- package/src/hooks/useWms.js +2 -7
- package/src/index.js +3 -0
- package/src/ui_components/ImageLoader.js +8 -3
- package/src/ui_components/Sidebar.js +1 -1
- package/src/ui_components/TopToolbar.js +0 -2
|
@@ -7,7 +7,9 @@ import { MapContext } from "@mapcomponents/react-core";
|
|
|
7
7
|
|
|
8
8
|
import sample_geojson_1 from "./assets/sample_1.json";
|
|
9
9
|
import sample_geojson_2 from "./assets/sample_2.json";
|
|
10
|
+
import sample_polygon_geojson_1 from "./assets/sample_polygon_1.json";
|
|
10
11
|
|
|
12
|
+
console.log(sample_polygon_geojson_1);
|
|
11
13
|
const storyoptions = {
|
|
12
14
|
title: "MapComponents/MlGeoJsonLayer",
|
|
13
15
|
component: MlGeoJsonLayer,
|
|
@@ -20,6 +22,13 @@ const storyoptions = {
|
|
|
20
22
|
export default storyoptions;
|
|
21
23
|
|
|
22
24
|
const Template = (props) => {
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
<MlGeoJsonLayer {...props} />
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
const LinestringTransitionTemplate = (props) => {
|
|
23
32
|
const mapContext = useContext(MapContext);
|
|
24
33
|
const [geojson, setGeojson] = useState(sample_geojson_1);
|
|
25
34
|
const initializedRef = useRef(false);
|
|
@@ -28,9 +37,7 @@ const Template = (props) => {
|
|
|
28
37
|
if (!mapContext.getMap() || initializedRef.current) return;
|
|
29
38
|
|
|
30
39
|
initializedRef.current = true;
|
|
31
|
-
mapContext
|
|
32
|
-
.getMap()
|
|
33
|
-
.setCenter({ lng: 7.137609868988648, lat: 50.74746799549129 });
|
|
40
|
+
mapContext.getMap().setCenter({ lng: 7.137609868988648, lat: 50.74746799549129 });
|
|
34
41
|
mapContext.getMap().setZoom(9.5);
|
|
35
42
|
|
|
36
43
|
setTimeout(() => {
|
|
@@ -45,6 +52,13 @@ const Template = (props) => {
|
|
|
45
52
|
);
|
|
46
53
|
};
|
|
47
54
|
|
|
48
|
-
export const
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
export const LinestringExample = LinestringTransitionTemplate.bind({});
|
|
56
|
+
LinestringExample.parameters = {};
|
|
57
|
+
LinestringExample.args = {};
|
|
58
|
+
|
|
59
|
+
export const PolygonExample = Template.bind({});
|
|
60
|
+
PolygonExample.parameters = {};
|
|
61
|
+
PolygonExample.args = {
|
|
62
|
+
type: "line",
|
|
63
|
+
geojson: sample_polygon_geojson_1,
|
|
64
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "FeatureCollection",
|
|
3
|
+
"features": [
|
|
4
|
+
{
|
|
5
|
+
"type": "Feature",
|
|
6
|
+
"properties": {},
|
|
7
|
+
"geometry": {
|
|
8
|
+
"coordinates": [
|
|
9
|
+
[
|
|
10
|
+
[7.08646747303149, 50.74485058672653],
|
|
11
|
+
[7.084287513691095, 50.74371917250187],
|
|
12
|
+
[7.084437772332876, 50.743610683782215],
|
|
13
|
+
[7.084640903561933, 50.743721758552354],
|
|
14
|
+
[7.085805654941254, 50.74293993704128],
|
|
15
|
+
[7.087023278906713, 50.74218320888983],
|
|
16
|
+
[7.087791368229503, 50.74258090834434],
|
|
17
|
+
[7.088796806075749, 50.743261830692745],
|
|
18
|
+
[7.089275088452752, 50.743701110992674],
|
|
19
|
+
[7.088087117762917, 50.74409411011173],
|
|
20
|
+
[7.087662548338368, 50.743784963165815],
|
|
21
|
+
[7.087184330538875, 50.7440368518605],
|
|
22
|
+
[7.087233860417484, 50.744077781245316],
|
|
23
|
+
[7.08714938625954, 50.744122118772154],
|
|
24
|
+
[7.087057544749172, 50.74427276821896],
|
|
25
|
+
[7.087104984084277, 50.744509715654885],
|
|
26
|
+
[7.08646747303149, 50.74485058672653]
|
|
27
|
+
]
|
|
28
|
+
],
|
|
29
|
+
"type": "Polygon"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const mapGeometryTypesToLayerTypes = {
|
|
2
|
+
Position: "circle",
|
|
3
|
+
Point: "circle",
|
|
4
|
+
MultiPoint: "circle",
|
|
5
|
+
LineString: "line",
|
|
6
|
+
MultiLineString: "line",
|
|
7
|
+
Polygon: "fill",
|
|
8
|
+
MultiPolygon: "fill",
|
|
9
|
+
GeometryCollection: "circle",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const getDefaulLayerTypeByGeometry = (geojson) => {
|
|
13
|
+
if (geojson?.type === "Feature") {
|
|
14
|
+
return mapGeometryTypesToLayerTypes?.[geojson?.geometry?.type]
|
|
15
|
+
? mapGeometryTypesToLayerTypes[geojson.geometry.type]
|
|
16
|
+
: "circle";
|
|
17
|
+
}
|
|
18
|
+
if (geojson?.type === "FeatureCollection") {
|
|
19
|
+
if (geojson.features.length) {
|
|
20
|
+
return getDefaulLayerTypeByGeometry(geojson.features[0]);
|
|
21
|
+
}
|
|
22
|
+
return "circle";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export default getDefaulLayerTypeByGeometry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const getDefaultPaintPropsByType = (type) => {
|
|
2
|
+
switch (type) {
|
|
3
|
+
case "fill":
|
|
4
|
+
return {
|
|
5
|
+
"fill-color": "rgba(10,240,256,0.6)",
|
|
6
|
+
};
|
|
7
|
+
case "line":
|
|
8
|
+
return {
|
|
9
|
+
"line-color": "rgb(100,200,100)",
|
|
10
|
+
"line-width": 5,
|
|
11
|
+
};
|
|
12
|
+
case "circle":
|
|
13
|
+
default:
|
|
14
|
+
return {
|
|
15
|
+
"circle-color": "#44aaaa",
|
|
16
|
+
"circle-stroke-color": "#fff",
|
|
17
|
+
"circle-stroke-width": 2,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default getDefaultPaintPropsByType;
|
|
@@ -1,34 +1,18 @@
|
|
|
1
|
-
import React, { useRef, useCallback, useEffect
|
|
1
|
+
import React, { useRef, useCallback, useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import { MapContext } from "@mapcomponents/react-core";
|
|
3
|
+
import useMap from "../../hooks/useMap";
|
|
5
4
|
|
|
6
5
|
const MlImageMarkerLayer = (props) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const componentId = useRef((props.idPrefix ? props.idPrefix : "MlImageMarkerLayer-") + uuidv4());
|
|
10
|
-
const mapContext = useContext(MapContext);
|
|
6
|
+
const mapHook = useMap({ mapId: props.mapId, waitForLayer: props.insertBeforeLayer });
|
|
7
|
+
|
|
11
8
|
const layerInitializedRef = useRef(false);
|
|
12
|
-
const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
|
|
13
9
|
const imageIdRef = useRef(props.imageId || "img_" + new Date().getTime());
|
|
14
|
-
const layerId = useRef(props.layerId || componentId
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
let _componentId = componentId.current;
|
|
18
|
-
return () => {
|
|
19
|
-
// This is the cleanup function, it is called when this react component is removed from react-dom
|
|
20
|
-
if (mapRef.current) {
|
|
21
|
-
mapRef.current.cleanup(_componentId);
|
|
22
|
-
|
|
23
|
-
mapRef.current = null;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
}, []);
|
|
10
|
+
const layerId = useRef(props.layerId || "MlImageMarkerLayer-" + mapHook.componentId);
|
|
27
11
|
|
|
28
12
|
useEffect(() => {
|
|
29
13
|
if (
|
|
30
|
-
!
|
|
31
|
-
(
|
|
14
|
+
!mapHook.mapIsReady ||
|
|
15
|
+
(mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
|
|
32
16
|
!props.options
|
|
33
17
|
)
|
|
34
18
|
return;
|
|
@@ -38,19 +22,15 @@ const MlImageMarkerLayer = (props) => {
|
|
|
38
22
|
|
|
39
23
|
if (props.options.layout) {
|
|
40
24
|
for (key in props.options.layout) {
|
|
41
|
-
|
|
42
|
-
.getMap(props.mapId)
|
|
43
|
-
.setLayoutProperty(layerId.current, key, props.options.layout[key]);
|
|
25
|
+
mapHook.map.setLayoutProperty(layerId.current, key, props.options.layout[key]);
|
|
44
26
|
}
|
|
45
27
|
}
|
|
46
28
|
if (props.options.paint) {
|
|
47
29
|
for (key in props.options.paint) {
|
|
48
|
-
|
|
49
|
-
.getMap(props.mapId)
|
|
50
|
-
.setPaintProperty(layerId.current, key, props.options.paint[key]);
|
|
30
|
+
mapHook.map.setPaintProperty(layerId.current, key, props.options.paint[key]);
|
|
51
31
|
}
|
|
52
32
|
}
|
|
53
|
-
}, [props.options, layerId.current,
|
|
33
|
+
}, [props.options, layerId.current, props.mapId]);
|
|
54
34
|
|
|
55
35
|
const addLayer = useCallback(() => {
|
|
56
36
|
let tmpOptions = {
|
|
@@ -59,50 +39,35 @@ const MlImageMarkerLayer = (props) => {
|
|
|
59
39
|
...props.options,
|
|
60
40
|
};
|
|
61
41
|
tmpOptions.layout["icon-image"] = imageIdRef.current;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
props.insertBeforeLayer,
|
|
65
|
-
componentId.current
|
|
66
|
-
);
|
|
67
|
-
}, [props]);
|
|
42
|
+
mapHook.map.addLayer(tmpOptions, props.insertBeforeLayer, mapHook.componentId);
|
|
43
|
+
}, [props, mapHook.mapIsReady, mapHook.map]);
|
|
68
44
|
|
|
69
45
|
useEffect(() => {
|
|
70
|
-
if (
|
|
71
|
-
!props.options ||
|
|
72
|
-
!mapContext.mapExists(props.mapId) ||
|
|
73
|
-
layerInitializedRef.current
|
|
74
|
-
)
|
|
75
|
-
return;
|
|
76
|
-
|
|
77
|
-
// the MapLibre-gl instance (mapContext.map) is accessible here
|
|
78
|
-
// initialize the layer and add it to the MapLibre-gl instance or do something else with it
|
|
79
|
-
mapRef.current = mapContext.getMap(props.mapId);
|
|
46
|
+
if (!props.options || !mapHook.mapIsReady || layerInitializedRef.current) return;
|
|
80
47
|
|
|
81
48
|
layerInitializedRef.current = true;
|
|
82
49
|
|
|
83
|
-
console.log(props.imgSrc);
|
|
84
50
|
if (props.imgSrc) {
|
|
85
|
-
|
|
51
|
+
mapHook.map.loadImage(props.imgSrc, function (error, image) {
|
|
86
52
|
if (error) throw error;
|
|
87
|
-
|
|
53
|
+
mapHook.map.addImage(imageIdRef.current, image, mapHook.componentId);
|
|
88
54
|
});
|
|
89
55
|
}
|
|
56
|
+
|
|
90
57
|
addLayer();
|
|
91
|
-
}, [
|
|
58
|
+
}, [mapHook.mapIsReady, mapHook.map, addLayer, props]);
|
|
92
59
|
|
|
93
60
|
useEffect(() => {
|
|
94
61
|
if (
|
|
95
|
-
!
|
|
96
|
-
(
|
|
62
|
+
!mapHook.mapIsReady ||
|
|
63
|
+
(mapHook.map && !mapHook.map.getLayer(layerId.current)) ||
|
|
97
64
|
!props.options
|
|
98
65
|
) {
|
|
99
66
|
return;
|
|
100
67
|
}
|
|
101
|
-
// the MapLibre-gl instance (mapContext.map) is accessible here
|
|
102
|
-
// initialize the layer and add it to the MapLibre-gl instance or do something else with it
|
|
103
68
|
|
|
104
|
-
|
|
105
|
-
}, [props.options.source.data,
|
|
69
|
+
mapHook.map.getSource(layerId.current).setData(props.options.source.data);
|
|
70
|
+
}, [props.options.source.data, props]);
|
|
106
71
|
|
|
107
72
|
return <></>;
|
|
108
73
|
};
|
|
@@ -2,16 +2,23 @@ import React, { useRef, useEffect, useContext } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
import { MapContext } from "@mapcomponents/react-core";
|
|
5
|
+
import useMapState from "../../hooks/useMapState";
|
|
5
6
|
|
|
6
7
|
const MlLayer = (props) => {
|
|
7
8
|
// Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
|
|
8
9
|
const mapContext = useContext(MapContext);
|
|
10
|
+
|
|
11
|
+
const mapState = useMapState({
|
|
12
|
+
mapId: props.mapId,
|
|
13
|
+
watch: {
|
|
14
|
+
viewport: false,
|
|
15
|
+
layers: true,
|
|
16
|
+
sources: false,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
9
19
|
const layerInitializedRef = useRef(false);
|
|
10
20
|
const mapRef = useRef(null);
|
|
11
|
-
const componentId = useRef(
|
|
12
|
-
(props.layerId ? props.layerId : "MlLayer-") + uuidv4()
|
|
13
|
-
);
|
|
14
|
-
const idSuffixRef = useRef(props.idSuffix || new Date().getTime());
|
|
21
|
+
const componentId = useRef((props.layerId ? props.layerId : "MlLayer-") + uuidv4());
|
|
15
22
|
const layerId = useRef(props.layerId || componentId.current);
|
|
16
23
|
const layerPaintConfRef = useRef(undefined);
|
|
17
24
|
const layerLayoutConfRef = useRef(undefined);
|
|
@@ -60,6 +67,20 @@ const MlLayer = (props) => {
|
|
|
60
67
|
// the MapLibre-gl instance (mapContext.map) is accessible here
|
|
61
68
|
// initialize the layer and add it to the MapLibre-gl instance or do something else with it
|
|
62
69
|
|
|
70
|
+
//check if insertBeforeLayer exists
|
|
71
|
+
if (props.insertBeforeLayer) {
|
|
72
|
+
let layerFound = false;
|
|
73
|
+
|
|
74
|
+
mapState?.layers?.forEach((layer) => {
|
|
75
|
+
if (layer.id === props.insertBeforeLayer) {
|
|
76
|
+
layerFound = true;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
if (!layerFound) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
63
84
|
mapRef.current = mapContext.getMap(props.mapId);
|
|
64
85
|
if (mapRef.current) {
|
|
65
86
|
layerInitializedRef.current = true;
|
|
@@ -78,7 +99,7 @@ const MlLayer = (props) => {
|
|
|
78
99
|
layerPaintConfRef.current = JSON.stringify(props.options?.paint);
|
|
79
100
|
layerLayoutConfRef.current = JSON.stringify(props.options?.layout);
|
|
80
101
|
}
|
|
81
|
-
}, [mapContext.mapIds, mapContext, props,
|
|
102
|
+
}, [mapContext.mapIds, mapContext, props, mapState.layers]);
|
|
82
103
|
|
|
83
104
|
return <></>;
|
|
84
105
|
};
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import "@fontsource/roboto/300.css";
|
|
3
3
|
import "@fontsource/roboto/400.css";
|
|
4
4
|
import "@fontsource/roboto/500.css";
|
|
5
|
-
import { css, cx } from '@emotion/css'
|
|
6
5
|
import "./MlLayerSwitcher.css";
|
|
7
6
|
//External
|
|
8
7
|
import { useEffect, useContext, useState } from "react";
|
|
@@ -14,7 +13,6 @@ import { MapContext } from "@mapcomponents/react-core";
|
|
|
14
13
|
import LayerBox from "./components/LayerBox";
|
|
15
14
|
import Divider from "@mui/material/Divider";
|
|
16
15
|
import useMapState from "../../hooks/useMapState";
|
|
17
|
-
import LoadingOverlay from "../../ui_components/LoadingOverlay";
|
|
18
16
|
/**
|
|
19
17
|
* @component
|
|
20
18
|
*
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import MlWmsLayer from "../MlWmsLayer/MlWmsLayer";
|
|
3
3
|
import MlLayerSwitcher from "./MlLayerSwitcher";
|
|
4
|
-
import MlGeoJsonLayer from
|
|
4
|
+
import MlGeoJsonLayer from "../MlGeoJsonLayer/MlGeoJsonLayer";
|
|
5
5
|
import mapContextDecorator from "../../decorators/MapContextDecorator";
|
|
6
6
|
import sample_geojson_1 from "./assets/sample_1.json";
|
|
7
7
|
import sample_geojson_2 from "./assets/sample_2.json";
|
|
8
|
-
import { Props } from "@storybook/addon-docs/blocks";
|
|
9
8
|
|
|
10
9
|
const storyoptions = {
|
|
11
10
|
title: "MapComponents/MlLayerSwitcher",
|
|
@@ -17,9 +16,7 @@ const storyoptions = {
|
|
|
17
16
|
decorators: mapContextDecorator,
|
|
18
17
|
};
|
|
19
18
|
export default storyoptions;
|
|
20
|
-
const layerId = "nw_uraufnahme_rw";
|
|
21
19
|
const Template = (args) => {
|
|
22
|
-
const [geojson, setGeojson] = useState(sample_geojson_1);
|
|
23
20
|
return (
|
|
24
21
|
<>
|
|
25
22
|
<MlWmsLayer
|
|
@@ -39,7 +36,7 @@ const Template = (args) => {
|
|
|
39
36
|
<MlGeoJsonLayer
|
|
40
37
|
type="line"
|
|
41
38
|
layout={{ visibility: args.geojsonLayerVisible ? "visible" : "none" }}
|
|
42
|
-
geojson={
|
|
39
|
+
geojson={sample_geojson_1}
|
|
43
40
|
layerId="geojson1"
|
|
44
41
|
/>
|
|
45
42
|
<MlGeoJsonLayer
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { css
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { css } from "@emotion/css";
|
|
3
3
|
import { Box } from "@mui/system";
|
|
4
4
|
import ImageLoader from "../../../ui_components/ImageLoader";
|
|
5
|
-
import { propsToClassKey } from "@mui/styles";
|
|
6
5
|
import useMapState from "../../../hooks/useMapState";
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -10,8 +9,6 @@ import useMapState from "../../../hooks/useMapState";
|
|
|
10
9
|
*
|
|
11
10
|
*/
|
|
12
11
|
const LayerBox = (props) => {
|
|
13
|
-
const [activeClassName, setActiveClassName] = useState("");
|
|
14
|
-
const [className, setClassName] = useState("mllayerswitcher-layer-box ");
|
|
15
12
|
const { layers } = useMapState({
|
|
16
13
|
mapId: props.mapId,
|
|
17
14
|
watch: {
|
|
@@ -23,33 +20,12 @@ const LayerBox = (props) => {
|
|
|
23
20
|
matchLayerIds: props.layerId,
|
|
24
21
|
},
|
|
25
22
|
});
|
|
26
|
-
const hoverBorderColor = "#1C62D7"; //Navy Blue
|
|
27
|
-
const activeBorderColor = "";
|
|
28
23
|
const width = "40px";
|
|
29
24
|
|
|
30
25
|
const defaultClass = css`
|
|
31
26
|
& img:hover {
|
|
32
27
|
}
|
|
33
28
|
`;
|
|
34
|
-
const activeClass =
|
|
35
|
-
defaultClass +
|
|
36
|
-
`& img {
|
|
37
|
-
border-color: rgb(196, 240, 0);
|
|
38
|
-
border-radius: 8px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
`;
|
|
42
|
-
const hoverClass = css``;
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
const isActive = props.activeLayers?.indexOf(props.layerId) !== -1;
|
|
46
|
-
|
|
47
|
-
if (isActive) {
|
|
48
|
-
setClassName(activeClass);
|
|
49
|
-
} else {
|
|
50
|
-
setClassName(defaultClass);
|
|
51
|
-
}
|
|
52
|
-
}, [props.activeLayers]);
|
|
53
29
|
|
|
54
30
|
return (
|
|
55
31
|
<>
|
|
@@ -67,7 +67,6 @@ const MlMarker = (props) => {
|
|
|
67
67
|
useEffect(() => {
|
|
68
68
|
if (mapRef.current && iframe.current?.contentWindow?.document?.body?.scrollHeight) {
|
|
69
69
|
setTimeout(() => {
|
|
70
|
-
let mapWidth = mapRef.current._container.clientWidth;
|
|
71
70
|
let mapHeight = mapRef.current._container.clientHeight;
|
|
72
71
|
|
|
73
72
|
const _pixelPos = mapRef.current.project([props.lng, props.lat]);
|
|
@@ -124,6 +123,7 @@ const MlMarker = (props) => {
|
|
|
124
123
|
ref={iframe}
|
|
125
124
|
sandbox="allow-same-origin allow-popups-to-escape-sandbox"
|
|
126
125
|
frameBorder="0"
|
|
126
|
+
title={componentId.current}
|
|
127
127
|
></iframe>
|
|
128
128
|
</Paper>
|
|
129
129
|
)}
|
|
@@ -29,7 +29,6 @@ const MlNavigationTools = (props) => {
|
|
|
29
29
|
minHeight: "20px",
|
|
30
30
|
width: mediaIsMobile ? "50px" : "30px",
|
|
31
31
|
height: mediaIsMobile ? "50px" : "30px",
|
|
32
|
-
color: "#bbb",
|
|
33
32
|
backgroundColor: "#414141",
|
|
34
33
|
borderRadius: "23%",
|
|
35
34
|
//border: "1px solid #bbb",
|
|
@@ -38,8 +37,8 @@ const MlNavigationTools = (props) => {
|
|
|
38
37
|
fontSize: mediaIsMobile ? "1.5em" : "1.2em",
|
|
39
38
|
":hover": {
|
|
40
39
|
backgroundColor: "#515151",
|
|
41
|
-
color: "#ececec",
|
|
42
40
|
},
|
|
41
|
+
color: "#ececec"
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
useEffect(() => {
|
|
@@ -144,7 +143,7 @@ const MlNavigationTools = (props) => {
|
|
|
144
143
|
<Button sx={buttonStyle} onClick={moveToCurrentLocation} disabled={locationAccessDenied}>
|
|
145
144
|
<GpsFixedIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
|
|
146
145
|
</Button>
|
|
147
|
-
<MlFollowGps style={buttonStyle}/>
|
|
146
|
+
<MlFollowGps style={{...(({color, ...rest}) => rest)(buttonStyle)}} />
|
|
148
147
|
<ButtonGroup
|
|
149
148
|
orientation="vertical"
|
|
150
149
|
sx={{
|
|
@@ -154,10 +153,10 @@ const MlNavigationTools = (props) => {
|
|
|
154
153
|
"Button:hover": {border: "none"},
|
|
155
154
|
}}
|
|
156
155
|
>
|
|
157
|
-
<Button sx={buttonStyle} onClick={zoomIn}>
|
|
156
|
+
<Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomIn}>
|
|
158
157
|
<ControlPointIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
|
|
159
158
|
</Button>
|
|
160
|
-
<Button sx={buttonStyle} onClick={zoomOut}>
|
|
159
|
+
<Button sx={{...buttonStyle, color: "#ececec",}} onClick={zoomOut}>
|
|
161
160
|
<RemoveCircleOutlineIcon sx={{fontSize: mediaIsMobile ? "1.5em" : "1.2em"}}/>
|
|
162
161
|
</Button>
|
|
163
162
|
</ButtonGroup>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {useRef, useEffect, useContext, useState} from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import {MapContext} from "@mapcomponents/react-core";
|
|
5
|
+
import {v4 as uuidv4} from "uuid";
|
|
6
|
+
import useMapState from "../../hooks/useMapState";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* TODO: Add short & useful description
|
|
@@ -15,11 +16,21 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
15
16
|
const MlShareMapState = (props) => {
|
|
16
17
|
// Use a useRef hook to reference the layer object to be able to access it later inside useEffect hooks
|
|
17
18
|
const mapContext = useContext(MapContext);
|
|
18
|
-
|
|
19
19
|
const initializedRef = useRef(false);
|
|
20
20
|
const mapRef = useRef(undefined);
|
|
21
21
|
const [map, setMap] = useState(undefined);
|
|
22
22
|
const componentId = useRef((props.idPrefix ? props.idPrefix : "MlShareMapState-") + uuidv4());
|
|
23
|
+
const [isInitialState, setIsInitialState] = useState(true);
|
|
24
|
+
const mapState = useMapState({
|
|
25
|
+
watch: {
|
|
26
|
+
viewport: false,
|
|
27
|
+
layers: true,
|
|
28
|
+
sources: false
|
|
29
|
+
},
|
|
30
|
+
filter: {
|
|
31
|
+
includeBaseLayers: false
|
|
32
|
+
}
|
|
33
|
+
})
|
|
23
34
|
|
|
24
35
|
const mapStateRef = useRef({});
|
|
25
36
|
|
|
@@ -49,32 +60,59 @@ const MlShareMapState = (props) => {
|
|
|
49
60
|
mapRef.current = mapContext.getMap(props.mapId);
|
|
50
61
|
setMap(mapRef.current);
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
const currentUrlParams = getCurrentUrlParameters();
|
|
53
64
|
if (currentUrlParams.lat && currentUrlParams.lng) {
|
|
54
65
|
mapStateRef.current.lat = currentUrlParams.lat;
|
|
55
66
|
mapStateRef.current.lng = currentUrlParams.lng;
|
|
56
67
|
mapStateRef.current.zoom = currentUrlParams.zoom;
|
|
57
|
-
mapRef.current.setCenter([mapStateRef.current.lng, mapStateRef.current.lat]);
|
|
58
68
|
mapRef.current.setZoom(mapStateRef.current.zoom);
|
|
59
69
|
}
|
|
60
70
|
}, [mapContext.mapIds, mapContext, props.mapId, props.active]);
|
|
61
71
|
|
|
62
72
|
useEffect(() => {
|
|
63
73
|
if (!map) return;
|
|
74
|
+
if(!mapState.layers) return;
|
|
75
|
+
if(!isInitialState) return;
|
|
76
|
+
|
|
77
|
+
const currentUrlParams = getCurrentUrlParameters()
|
|
78
|
+
|
|
79
|
+
if(currentUrlParams.layers) {
|
|
80
|
+
for (let x in currentUrlParams.layers) {
|
|
81
|
+
mapRef.current.getLayer(currentUrlParams.layers[x].id).visibility = currentUrlParams.layers[x].visible ? "visible" : "none"
|
|
82
|
+
mapRef.current.getLayer(currentUrlParams.layers[x].id).type = currentUrlParams.layers[x].type
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}, [mapState.layers, props.mapId, props.active])
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (!map) return;
|
|
90
|
+
if (!mapState.layers) return;
|
|
64
91
|
|
|
65
92
|
if (props.active) {
|
|
93
|
+
setIsInitialState(false)
|
|
66
94
|
map.on(
|
|
67
95
|
"moveend",
|
|
68
96
|
() => {
|
|
97
|
+
let mapLayers = []
|
|
98
|
+
for (let x in mapState.layers) {
|
|
99
|
+
mapLayers.push(new URLSearchParams({
|
|
100
|
+
id: mapState.layers[x].id,
|
|
101
|
+
type: mapState.layers[x].type,
|
|
102
|
+
visible: mapState.layers[x].visible
|
|
103
|
+
}))
|
|
104
|
+
}
|
|
69
105
|
refreshMapState();
|
|
70
106
|
let urlParams = new URLSearchParams({
|
|
71
107
|
...getCurrentUrlParameters(),
|
|
72
108
|
...mapStateRef.current,
|
|
109
|
+
layers : mapLayers
|
|
73
110
|
});
|
|
111
|
+
|
|
74
112
|
let currentParams = new URLSearchParams(window.location.search);
|
|
75
113
|
if (urlParams.toString() !== currentParams.toString()) {
|
|
76
114
|
window.history.pushState(
|
|
77
|
-
{
|
|
115
|
+
{...mapStateRef.current},
|
|
78
116
|
document.title,
|
|
79
117
|
"?" + urlParams.toString()
|
|
80
118
|
);
|
|
@@ -88,7 +126,33 @@ const MlShareMapState = (props) => {
|
|
|
88
126
|
}, [props.active, map]);
|
|
89
127
|
|
|
90
128
|
const getCurrentUrlParameters = () => {
|
|
91
|
-
|
|
129
|
+
let parameterObject = Object.fromEntries(new URLSearchParams(window.location.search))
|
|
130
|
+
|
|
131
|
+
if(window.location.search.indexOf("layers")!==-1) {
|
|
132
|
+
let layerParamString = window.location.search.substring(window.location.search.indexOf("layers"))
|
|
133
|
+
layerParamString = layerParamString.substring(0, (layerParamString.indexOf("&")!==-1) ? layerParamString.indexOf("&") : layerParamString.length)
|
|
134
|
+
parameterObject = Object.fromEntries(new URLSearchParams(window.location.search.replace(layerParamString, "")))
|
|
135
|
+
let layerParams = layerParamString.substring(7)
|
|
136
|
+
layerParams = layerParams.replaceAll("%3D", "=")
|
|
137
|
+
layerParams = layerParams.replaceAll("%26", "&")
|
|
138
|
+
layerParams = layerParams.replaceAll("%2C", ",")
|
|
139
|
+
|
|
140
|
+
if (layerParams.indexOf(",")) {
|
|
141
|
+
layerParams = layerParams.split(",")
|
|
142
|
+
} else {
|
|
143
|
+
layerParams = [layerParams]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (let x in layerParams) {
|
|
147
|
+
let layerState = layerParams[x].split("&")
|
|
148
|
+
layerParams[x] = {}
|
|
149
|
+
for (let y in layerState) {
|
|
150
|
+
layerParams[x][layerState[y].split("=")[0]] = layerState[y].split("=")[1]
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
parameterObject["layers"] = layerParams
|
|
154
|
+
}
|
|
155
|
+
return parameterObject
|
|
92
156
|
};
|
|
93
157
|
|
|
94
158
|
const refreshMapState = () => {
|
|
@@ -99,7 +163,7 @@ const MlShareMapState = (props) => {
|
|
|
99
163
|
|
|
100
164
|
window.onpopstate = (event) => {
|
|
101
165
|
if (event.state && event.state.lng && event.state.lat && event.state.zoom) {
|
|
102
|
-
mapRef.current.easeTo({
|
|
166
|
+
mapRef.current.easeTo({zoom: event.state.zoom, center: [event.state.lng, event.state.lat]});
|
|
103
167
|
}
|
|
104
168
|
};
|
|
105
169
|
|
|
@@ -2,6 +2,7 @@ import React, { useState} from "react";
|
|
|
2
2
|
|
|
3
3
|
import MlShareMapState from "./MlShareMapState";
|
|
4
4
|
import mapContextDecorator from "../../decorators/MapContextDecorator";
|
|
5
|
+
import MlLayer from "../MlLayer/MlLayer";
|
|
5
6
|
|
|
6
7
|
const storyoptions = {
|
|
7
8
|
title: "MapComponents/MlShareMapState",
|
|
@@ -12,7 +13,8 @@ const storyoptions = {
|
|
|
12
13
|
export default storyoptions;
|
|
13
14
|
|
|
14
15
|
const Template = (args) => {
|
|
15
|
-
const [watchState, setWatchState] = useState(
|
|
16
|
+
const [watchState, setWatchState] = useState(false);
|
|
17
|
+
const [testLayerVisible, setTestLayerVisible] = useState(true);
|
|
16
18
|
|
|
17
19
|
return (
|
|
18
20
|
<>
|
|
@@ -20,9 +22,27 @@ const Template = (args) => {
|
|
|
20
22
|
style={{ zIndex: "1000", position: "absolute" }}
|
|
21
23
|
onClick={() => setWatchState(!watchState)}
|
|
22
24
|
>
|
|
23
|
-
watch map state {watchState?1:0}
|
|
25
|
+
watch map state {watchState ? 1 : 0}
|
|
26
|
+
</button>
|
|
27
|
+
<button
|
|
28
|
+
style={{ zIndex: "1000", position: "absolute" }}
|
|
29
|
+
onClick={() => setTestLayerVisible(!testLayerVisible)}
|
|
30
|
+
>
|
|
31
|
+
visibility {testLayerVisible ? 1 : 0}
|
|
24
32
|
</button>
|
|
25
33
|
<MlShareMapState active={watchState} />
|
|
34
|
+
<MlLayer
|
|
35
|
+
layerId={"MlLayer-testLayer"}
|
|
36
|
+
options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
|
|
37
|
+
/>
|
|
38
|
+
<MlLayer
|
|
39
|
+
layerId={"MlLayer-testLayer2"}
|
|
40
|
+
options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
|
|
41
|
+
/>
|
|
42
|
+
<MlLayer
|
|
43
|
+
layerId={"MlLayer-testLayer3"}
|
|
44
|
+
options={{ layout: { visibility: testLayerVisible ? "visible" : "none" } }}
|
|
45
|
+
/>
|
|
26
46
|
</>
|
|
27
47
|
);
|
|
28
48
|
};
|
|
@@ -5,9 +5,7 @@ import MlGPXViewer from "../MlGPXViewer/MlGPXViewer";
|
|
|
5
5
|
|
|
6
6
|
import mapContextDecorator from "../../decorators/MapContextDecorator";
|
|
7
7
|
import GeoJsonProvider from "../MlGPXViewer/util/GeoJsonProvider";
|
|
8
|
-
import
|
|
9
|
-
import FileDownloadIcon from '@mui/icons-material/FileDownload';
|
|
10
|
-
import InfoIcon from "@mui/icons-material/Info";
|
|
8
|
+
import FileDownloadIcon from "@mui/icons-material/FileDownload";
|
|
11
9
|
import IconButton from "@mui/material/IconButton";
|
|
12
10
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
|
13
11
|
|