solid-map-gl 1.8.0 → 1.8.2
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/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/source/components/Atmosphere/index.jsx +4 -4
- package/dist/source/components/Camera/index.jsx +27 -25
- package/dist/source/components/Control/index.jsx +16 -28
- package/dist/source/components/Draw/index.jsx +6 -6
- package/dist/source/components/Image/index.jsx +14 -14
- package/dist/source/components/Layer/index.jsx +19 -19
- package/dist/source/components/Light/index.jsx +4 -4
- package/dist/source/components/MapGL/index.jsx +18 -24
- package/dist/source/components/MapProvider/index.jsx +8 -11
- package/dist/source/components/Marker/index.jsx +5 -5
- package/dist/source/components/Popup/index.jsx +5 -5
- package/dist/source/components/Source/index.jsx +13 -13
- package/dist/source/components/Terrain/index.jsx +8 -8
- package/dist/source/index.jsx +1 -1
- package/dist/types/components/Control/index.d.ts +2 -1
- package/dist/types/components/MapProvider/index.d.ts +7 -4
- package/dist/types/index.d.ts +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createEffect, onCleanup } from 'solid-js';
|
|
2
|
-
import {
|
|
1
|
+
import { createEffect, onCleanup, createSignal } from 'solid-js';
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
// linearly interpolate between two positions [x,y,z] based on time
|
|
4
4
|
const lerp = (a, b, t) => a.map((_, idx) => (1.0 - t) * a[idx] + t * b[idx]);
|
|
5
5
|
// sphericaly interpolate between two positions [x,y,z] based on time
|
|
@@ -15,17 +15,19 @@ const easeQuad = {
|
|
|
15
15
|
out: (x) => 1 - (1 - x) * (1 - x),
|
|
16
16
|
inOut: (x) => x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2,
|
|
17
17
|
};
|
|
18
|
-
export const Camera = props => {
|
|
19
|
-
const [
|
|
20
|
-
if (!map())
|
|
21
|
-
return null;
|
|
18
|
+
export const Camera = (props) => {
|
|
19
|
+
const [ctx] = useMapContext();
|
|
22
20
|
let animationTime = 0.1;
|
|
23
21
|
let isReverse = false;
|
|
22
|
+
// Handle User Interaction
|
|
23
|
+
const [userInteraction, setUserInteraction] = createSignal(false);
|
|
24
|
+
['mousedown', 'touchstart', 'wheel'].forEach((event) => ctx.map.on(event, (evt) => !evt.rotate && setUserInteraction(true)));
|
|
25
|
+
['moveend', 'mouseup', 'touchend'].forEach((event) => ctx.map.on(event, (evt) => !evt.rotate && setUserInteraction(false)));
|
|
24
26
|
const updateCameraPosition = async ([lng, lat, alt], target) => {
|
|
25
|
-
const camera = map
|
|
26
|
-
camera.position = map
|
|
27
|
+
const camera = ctx.map.getFreeCameraOptions();
|
|
28
|
+
camera.position = ctx.map.mapLib.MercatorCoordinate.fromLngLat([lng, lat], alt);
|
|
27
29
|
camera.lookAtPoint(target);
|
|
28
|
-
map
|
|
30
|
+
ctx.map.setFreeCameraOptions(camera);
|
|
29
31
|
};
|
|
30
32
|
const frame = () => {
|
|
31
33
|
props.translate && window.requestAnimationFrame(frame);
|
|
@@ -45,49 +47,49 @@ export const Camera = props => {
|
|
|
45
47
|
createEffect(() => {
|
|
46
48
|
props.translate && window.requestAnimationFrame(frame);
|
|
47
49
|
});
|
|
48
|
-
const options = { duration: 1000, easing: n => n };
|
|
50
|
+
const options = { duration: 1000, easing: (n) => n };
|
|
49
51
|
const rotateGlobe = () => {
|
|
50
|
-
if (userInteraction)
|
|
52
|
+
if (userInteraction())
|
|
51
53
|
return;
|
|
52
54
|
const { secPerRev = 120, maxSpinZoom = 5, slowSpinZoom = 3, } = props.rotateGlobe;
|
|
53
|
-
const zoom = map
|
|
55
|
+
const zoom = ctx.map.getZoom();
|
|
54
56
|
if (zoom > maxSpinZoom)
|
|
55
57
|
return;
|
|
56
58
|
let distancePerSecond = 360 / secPerRev;
|
|
57
59
|
if (zoom > slowSpinZoom)
|
|
58
60
|
distancePerSecond *= (maxSpinZoom - zoom) / (maxSpinZoom - slowSpinZoom);
|
|
59
|
-
const center = map
|
|
61
|
+
const center = ctx.map.getCenter();
|
|
60
62
|
center.lng = props.reverse
|
|
61
63
|
? center.lng + distancePerSecond
|
|
62
64
|
: center.lng - distancePerSecond;
|
|
63
|
-
map
|
|
65
|
+
ctx.map.easeTo({ center, ...options }, { rotate: true });
|
|
64
66
|
};
|
|
65
67
|
const rotateViewport = () => {
|
|
66
|
-
if (!props.rotateViewport || userInteraction)
|
|
68
|
+
if (!props.rotateViewport || userInteraction())
|
|
67
69
|
return;
|
|
68
70
|
const rotateViewport = props.rotateViewport;
|
|
69
71
|
const secPerRev = rotateViewport?.secPerRev || 60;
|
|
70
72
|
const bearing = props.reverse
|
|
71
|
-
? map
|
|
72
|
-
: map
|
|
73
|
+
? ctx.map.getBearing() + 360 / secPerRev
|
|
74
|
+
: ctx.map.getBearing() - 360 / secPerRev;
|
|
73
75
|
const pitch = rotateViewport?.pitch || 60;
|
|
74
76
|
const around = rotateViewport?.around;
|
|
75
|
-
map
|
|
77
|
+
ctx.map.easeTo({ bearing, pitch, around, ...options }, { rotate: true });
|
|
76
78
|
};
|
|
77
79
|
const onEnd = () => (props.rotateGlobe ? rotateGlobe() : rotateViewport());
|
|
78
|
-
map
|
|
80
|
+
ctx.map.on('moveend', onEnd).on('dragend', onEnd);
|
|
79
81
|
let originalCenter;
|
|
80
82
|
createEffect(() => {
|
|
81
83
|
if (props.rotateGlobe == undefined)
|
|
82
84
|
return;
|
|
83
85
|
if (props.rotateGlobe) {
|
|
84
|
-
originalCenter = map
|
|
86
|
+
originalCenter = ctx.map.getCenter();
|
|
85
87
|
rotateGlobe();
|
|
86
88
|
}
|
|
87
89
|
else {
|
|
88
90
|
props.resetWhenStopped
|
|
89
|
-
? map
|
|
90
|
-
: map
|
|
91
|
+
? ctx.map.stop().easeTo({ center: originalCenter })
|
|
92
|
+
: ctx.map.stop();
|
|
91
93
|
}
|
|
92
94
|
});
|
|
93
95
|
createEffect(() => {
|
|
@@ -96,9 +98,9 @@ export const Camera = props => {
|
|
|
96
98
|
props.rotateViewport
|
|
97
99
|
? rotateViewport()
|
|
98
100
|
: props.resetWhenStopped
|
|
99
|
-
? map
|
|
100
|
-
: map
|
|
101
|
+
? ctx.map.stop().resetNorthPitch()
|
|
102
|
+
: ctx.map.stop();
|
|
101
103
|
});
|
|
102
|
-
onCleanup(() => map
|
|
104
|
+
onCleanup(() => ctx.map.off('moveend', onEnd).off('dragend', onEnd));
|
|
103
105
|
return props.children;
|
|
104
106
|
};
|
|
@@ -1,34 +1,22 @@
|
|
|
1
|
-
import { createEffect
|
|
2
|
-
import {
|
|
3
|
-
const getControl = (lib, type, options, custom) => {
|
|
4
|
-
if (custom)
|
|
5
|
-
return new custom(options);
|
|
6
|
-
switch (type) {
|
|
7
|
-
case 'navigation':
|
|
8
|
-
return new lib.NavigationControl(options);
|
|
9
|
-
case 'scale':
|
|
10
|
-
return new lib.ScaleControl(options);
|
|
11
|
-
case 'attribution':
|
|
12
|
-
return new lib.AttributionControl(options);
|
|
13
|
-
case 'geolocate':
|
|
14
|
-
return new lib.GeolocateControl(options);
|
|
15
|
-
case 'fullscreen':
|
|
16
|
-
return new lib.FullscreenControl();
|
|
17
|
-
// options || { container: map().container }
|
|
18
|
-
default:
|
|
19
|
-
throw new Error(`Unknown control type: ${type}`);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
1
|
+
import { createEffect } from 'solid-js';
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
22
3
|
export const Control = props => {
|
|
23
|
-
const [
|
|
24
|
-
|
|
4
|
+
const [ctx] = useMapContext();
|
|
5
|
+
const controlClasses = new Map([
|
|
6
|
+
['navigation', ctx.map.mapLib.NavigationControl],
|
|
7
|
+
['scale', ctx.map.mapLib.ScaleControl],
|
|
8
|
+
['attribution', ctx.map.mapLib.AttributionControl],
|
|
9
|
+
['geolocate', ctx.map.mapLib.GeolocateControl],
|
|
10
|
+
['fullscreen', ctx.map.mapLib.FullscreenControl],
|
|
11
|
+
]);
|
|
12
|
+
const ControlClass = props.custom || controlClasses.get(props.type || 'navigation');
|
|
13
|
+
if (!ControlClass)
|
|
14
|
+
throw new Error(`Unknown control type: ${props.type}`);
|
|
25
15
|
// Add or Update Control
|
|
26
16
|
createEffect(() => {
|
|
27
|
-
control
|
|
28
|
-
control
|
|
29
|
-
map
|
|
17
|
+
const control = new ControlClass(props.options);
|
|
18
|
+
control && ctx.map.hasControl(control) && ctx.map.removeControl(control);
|
|
19
|
+
ctx.map.addControl(control, props.position);
|
|
30
20
|
});
|
|
31
|
-
// Remove Control
|
|
32
|
-
onCleanup(() => map()?.removeControl(control));
|
|
33
21
|
return null;
|
|
34
22
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { onCleanup } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
import { drawEvents } from '../../events';
|
|
4
4
|
export const Draw = (props) => {
|
|
5
|
-
const [
|
|
5
|
+
const [ctx] = useMapContext();
|
|
6
6
|
// Add Draw Control
|
|
7
7
|
const draw = new props.lib(props.options);
|
|
8
|
-
map
|
|
8
|
+
ctx.map.addControl(draw, props.position || 'top-right');
|
|
9
9
|
props.getInstance && props.getInstance(draw);
|
|
10
10
|
// Hook up events
|
|
11
11
|
const eventList = {};
|
|
@@ -14,15 +14,15 @@ export const Draw = (props) => {
|
|
|
14
14
|
const event = `draw.${item.slice(2).toLowerCase()}`;
|
|
15
15
|
const fn = evt => props[item](evt);
|
|
16
16
|
eventList[event] = fn;
|
|
17
|
-
map
|
|
17
|
+
ctx.map.on(event, fn);
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
// Remove Draw Control
|
|
21
21
|
onCleanup(() => {
|
|
22
22
|
// Remove Events
|
|
23
|
-
Object.keys(eventList).forEach(event => map
|
|
23
|
+
Object.keys(eventList).forEach(event => ctx.map.off(event, eventList[event]));
|
|
24
24
|
// Remove Control
|
|
25
|
-
map
|
|
25
|
+
ctx.map?.removeControl(draw);
|
|
26
26
|
});
|
|
27
27
|
return null;
|
|
28
28
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { onCleanup, createSignal, createEffect, untrack, } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
const PATTERN = {
|
|
4
4
|
diagonal_l: { size: 20, path: 'M20 0 0 20M-10 10 10-10M10 30 30 10' },
|
|
5
5
|
diagonal_r: { size: 20, path: 'M0 0 20 20M30 10 10-10M10 30-10 10' },
|
|
@@ -19,15 +19,15 @@ const PATTERN = {
|
|
|
19
19
|
};
|
|
20
20
|
export const patternList = Object.keys(PATTERN);
|
|
21
21
|
export const MGL_Image = props => {
|
|
22
|
-
const [
|
|
22
|
+
const [ctx] = useMapContext();
|
|
23
23
|
const [size, setSize] = createSignal({ width: 0, height: 0 });
|
|
24
24
|
const debug = (text, value) => {
|
|
25
|
-
map
|
|
25
|
+
ctx.map.debug &&
|
|
26
26
|
console.debug('%c[MapGL]', 'color: #10b981', text, value || '');
|
|
27
27
|
};
|
|
28
28
|
// Remove Image
|
|
29
29
|
onCleanup(() => {
|
|
30
|
-
map
|
|
30
|
+
ctx.map?.hasImage(props.id) && ctx.map?.removeImage(props.id);
|
|
31
31
|
debug('Remove Image:', props.id);
|
|
32
32
|
});
|
|
33
33
|
// Add or Update Image
|
|
@@ -41,23 +41,23 @@ export const MGL_Image = props => {
|
|
|
41
41
|
: props.options;
|
|
42
42
|
_loadImage(props.source || _createPattern(props.pattern), data => {
|
|
43
43
|
const { width, height } = data;
|
|
44
|
-
if (map
|
|
45
|
-
map
|
|
44
|
+
if (ctx.map && !ctx.map.hasImage(props.id))
|
|
45
|
+
ctx.map.addImage(props.id, data, ops);
|
|
46
46
|
if (!props.pattern &&
|
|
47
47
|
untrack(() => width === size().width && height === size().height)) {
|
|
48
|
-
map
|
|
49
|
-
map
|
|
48
|
+
ctx.map.updateImage(props.id, data);
|
|
49
|
+
ctx.map.triggerRepaint();
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
|
-
map
|
|
53
|
-
map
|
|
52
|
+
ctx.map.removeImage(props.id);
|
|
53
|
+
ctx.map.addImage(props.id, data, ops);
|
|
54
54
|
}
|
|
55
55
|
setSize({ width, height });
|
|
56
56
|
debug('Add Image:', props.id);
|
|
57
|
-
map
|
|
58
|
-
if (map
|
|
57
|
+
ctx.map.on('style.load', () => {
|
|
58
|
+
if (ctx.map.hasImage(props.id))
|
|
59
59
|
return;
|
|
60
|
-
map
|
|
60
|
+
ctx.map.addImage(props.id, data, ops);
|
|
61
61
|
debug('Re-Add Image:', props.id);
|
|
62
62
|
});
|
|
63
63
|
});
|
|
@@ -76,7 +76,7 @@ export const MGL_Image = props => {
|
|
|
76
76
|
}
|
|
77
77
|
if (typeof image !== 'string')
|
|
78
78
|
return callback(image);
|
|
79
|
-
map
|
|
79
|
+
ctx.map.loadImage(image, async (error, imageData) => {
|
|
80
80
|
if (error) {
|
|
81
81
|
if (typeof image == 'string' && image?.trimEnd().endsWith('.svg')) {
|
|
82
82
|
image = await (await fetch(image)).text();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { onCleanup, createEffect, createUniqueId } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
import { useSourceId } from '../Source';
|
|
4
4
|
import { layerEvents } from '../../events';
|
|
5
5
|
const diff = (newProps = {}, prevProps = {}) => {
|
|
@@ -13,15 +13,15 @@ const diff = (newProps = {}, prevProps = {}) => {
|
|
|
13
13
|
}, []);
|
|
14
14
|
};
|
|
15
15
|
export const Layer = props => {
|
|
16
|
-
const [
|
|
16
|
+
const [ctx] = useMapContext();
|
|
17
17
|
const sourceId = props.style?.source || useSourceId();
|
|
18
18
|
props.id ??= createUniqueId();
|
|
19
19
|
const debug = (text, value) => {
|
|
20
|
-
map
|
|
20
|
+
ctx.map.debug &&
|
|
21
21
|
console.debug('%c[MapGL]', 'color: #10b981', text, value || '');
|
|
22
22
|
};
|
|
23
23
|
// Add Layer
|
|
24
|
-
map
|
|
24
|
+
ctx.map.addLayer(props.customLayer || {
|
|
25
25
|
...props.style,
|
|
26
26
|
id: props.id,
|
|
27
27
|
source: sourceId,
|
|
@@ -29,17 +29,17 @@ export const Layer = props => {
|
|
|
29
29
|
smg: { beforeType: props.beforeType, beforeId: props.beforeId },
|
|
30
30
|
},
|
|
31
31
|
}, props.beforeType
|
|
32
|
-
? map
|
|
32
|
+
? ctx.map
|
|
33
33
|
.getStyle()
|
|
34
34
|
.layers.find(l => l.type === props.beforeType)?.id
|
|
35
35
|
: props.beforeId);
|
|
36
|
-
map
|
|
36
|
+
ctx.map.layerIdList.push(props.id);
|
|
37
37
|
debug('Add Layer:', props.id);
|
|
38
38
|
// Hook up events
|
|
39
39
|
layerEvents.forEach(item => {
|
|
40
40
|
if (props[item]) {
|
|
41
41
|
const event = item.slice(2).toLowerCase();
|
|
42
|
-
map
|
|
42
|
+
ctx.map.on(event, props.id, evt => {
|
|
43
43
|
props[item](evt);
|
|
44
44
|
debug(`Layer '${event}' event on '${props.id}':`, evt);
|
|
45
45
|
});
|
|
@@ -51,13 +51,13 @@ export const Layer = props => {
|
|
|
51
51
|
if (style === prev)
|
|
52
52
|
return;
|
|
53
53
|
if (style.layout !== prev?.layout)
|
|
54
|
-
diff(style.layout, prev?.layout).forEach(([key, value]) => map
|
|
54
|
+
diff(style.layout, prev?.layout).forEach(([key, value]) => ctx.map.setLayoutProperty(props.id, key, value, { validate: false }));
|
|
55
55
|
if (style.paint !== prev?.paint)
|
|
56
|
-
diff(style.paint, prev?.paint).forEach(([key, value]) => map
|
|
56
|
+
diff(style.paint, prev?.paint).forEach(([key, value]) => ctx.map.setPaintProperty(props.id, key, value, { validate: false }));
|
|
57
57
|
if (style.minzoom !== prev?.minzoom || style.maxzoom !== prev?.maxzoom)
|
|
58
|
-
map
|
|
58
|
+
ctx.map.setLayerZoomRange(props.id, style.minzoom, style.maxzoom);
|
|
59
59
|
if (style.filter !== prev?.filter)
|
|
60
|
-
map
|
|
60
|
+
ctx.map.setFilter(props.id, style.filter, { validate: false });
|
|
61
61
|
debug('Update Layer Style:', props.id);
|
|
62
62
|
return style;
|
|
63
63
|
}, props.style);
|
|
@@ -65,7 +65,7 @@ export const Layer = props => {
|
|
|
65
65
|
createEffect((prev) => {
|
|
66
66
|
if (props.visible === prev)
|
|
67
67
|
return;
|
|
68
|
-
map
|
|
68
|
+
ctx.map.setLayoutProperty(props.id, 'visibility', props.visible ? 'visible' : 'none', { validate: false });
|
|
69
69
|
debug(`Update Visibility (${props.id}):`, props.visible);
|
|
70
70
|
return props.visible;
|
|
71
71
|
}, props.visible);
|
|
@@ -73,26 +73,26 @@ export const Layer = props => {
|
|
|
73
73
|
createEffect(async () => {
|
|
74
74
|
if (!props.filter)
|
|
75
75
|
return;
|
|
76
|
-
!map
|
|
77
|
-
map
|
|
76
|
+
!ctx.map.isStyleLoaded() && (await ctx.map.once('styledata'));
|
|
77
|
+
ctx.map.setFilter(props.id, props.filter);
|
|
78
78
|
debug(`Update Filter (${props.id}):`, props.filter);
|
|
79
79
|
});
|
|
80
80
|
// Update Feature State
|
|
81
81
|
createEffect(async () => {
|
|
82
|
-
if (!props.featureState ||
|
|
82
|
+
if (!props.featureState || props.featureState.id === null)
|
|
83
83
|
return;
|
|
84
|
-
!map
|
|
85
|
-
map
|
|
84
|
+
!ctx.map.isStyleLoaded() && (await ctx.map.once('styledata'));
|
|
85
|
+
ctx.map.removeFeatureState({
|
|
86
86
|
source: sourceId,
|
|
87
87
|
sourceLayer: props.style['source-layer'],
|
|
88
88
|
});
|
|
89
|
-
map
|
|
89
|
+
ctx.map.setFeatureState({
|
|
90
90
|
source: sourceId,
|
|
91
91
|
sourceLayer: props.style['source-layer'],
|
|
92
92
|
id: props.featureState.id,
|
|
93
93
|
}, props.featureState.state);
|
|
94
94
|
});
|
|
95
95
|
//Remove Layer
|
|
96
|
-
onCleanup(() => map
|
|
96
|
+
onCleanup(() => ctx.map?.getLayer(props.id) && ctx.map?.removeLayer(props.id));
|
|
97
97
|
return props.children;
|
|
98
98
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { onCleanup, createEffect } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
export const Light = (props) => {
|
|
4
|
-
const [
|
|
4
|
+
const [ctx] = useMapContext();
|
|
5
5
|
// Add or Update Light Layer
|
|
6
|
-
createEffect(() => map
|
|
6
|
+
createEffect(() => ctx.map.setLight(props.style || {}));
|
|
7
7
|
// Remove Light Layer
|
|
8
|
-
onCleanup(() => map
|
|
8
|
+
onCleanup(() => ctx.map?.setLight(null));
|
|
9
9
|
return null;
|
|
10
10
|
};
|
|
@@ -3,7 +3,7 @@ import { MapProvider } from '../MapProvider';
|
|
|
3
3
|
import { mapEvents } from '../../events';
|
|
4
4
|
import { vectorStyleList } from '../../mapStyles';
|
|
5
5
|
/** Creates a new Map Container */
|
|
6
|
-
export const MapGL = props => {
|
|
6
|
+
export const MapGL = (props) => {
|
|
7
7
|
props.id ??= createUniqueId();
|
|
8
8
|
let map;
|
|
9
9
|
let mapRef;
|
|
@@ -14,10 +14,7 @@ export const MapGL = props => {
|
|
|
14
14
|
window.matchMedia('(prefers-color-scheme: dark)').matches) ||
|
|
15
15
|
(typeof document !== 'undefined' &&
|
|
16
16
|
document.body.classList.contains('dark')));
|
|
17
|
-
const [userInteraction, setUserInteraction] = createSignal(false);
|
|
18
17
|
const [internal, setInternal] = createSignal(false);
|
|
19
|
-
// debounce user interactions
|
|
20
|
-
createEffect(() => props.onUserInteraction?.(userInteraction()));
|
|
21
18
|
const debug = (text, value) => {
|
|
22
19
|
props.debug &&
|
|
23
20
|
console.debug('%c[MapGL]', 'color: #0ea5e9', text, value || '');
|
|
@@ -37,7 +34,7 @@ export const MapGL = props => {
|
|
|
37
34
|
let mapLib = props.mapLib || (await import('mapbox-gl'));
|
|
38
35
|
if (!mapLib.Map)
|
|
39
36
|
mapLib = window['maplibregl'] || window['mapboxgl'];
|
|
40
|
-
if (!mapLib.supported())
|
|
37
|
+
if (!mapLib.supported?.())
|
|
41
38
|
throw new Error('Mapbox GL not supported');
|
|
42
39
|
debug(`Map (v${mapLib.version}) loading...`);
|
|
43
40
|
map = new mapLib.Map({
|
|
@@ -59,8 +56,8 @@ export const MapGL = props => {
|
|
|
59
56
|
map.once('load', () => {
|
|
60
57
|
setMapLoaded(map);
|
|
61
58
|
debug('Map loaded');
|
|
62
|
-
['mousedown', 'touchstart', 'wheel'].forEach(event => map.on(event, evt => !evt.rotate &&
|
|
63
|
-
['moveend', 'mouseup', 'touchend'].forEach(event => map.on(event, evt => !evt.rotate &&
|
|
59
|
+
['mousedown', 'touchstart', 'wheel'].forEach((event) => map.on(event, (evt) => !evt.rotate && props.onUserInteraction(true)));
|
|
60
|
+
['moveend', 'mouseup', 'touchend'].forEach((event) => map.on(event, (evt) => !evt.rotate && props.onUserInteraction(false)));
|
|
64
61
|
// Listen to dark theme changes
|
|
65
62
|
const darkTheme = typeof window !== 'undefined' &&
|
|
66
63
|
window?.matchMedia('(prefers-color-scheme: dark)');
|
|
@@ -83,21 +80,21 @@ export const MapGL = props => {
|
|
|
83
80
|
// resizeObserver.observe(mapRef as Element)
|
|
84
81
|
// }
|
|
85
82
|
// Hook up events
|
|
86
|
-
mapEvents.forEach(item => {
|
|
83
|
+
mapEvents.forEach((item) => {
|
|
87
84
|
const prop = props[item];
|
|
88
85
|
let isFirstMessage = true;
|
|
89
86
|
if (prop) {
|
|
90
87
|
const event = item.slice(2).toLowerCase();
|
|
91
88
|
if (typeof prop === 'function') {
|
|
92
|
-
map.on(event, e => {
|
|
89
|
+
map.on(event, (e) => {
|
|
93
90
|
prop(e);
|
|
94
91
|
isFirstMessage && debug(`Map '${event}' event:`, e);
|
|
95
92
|
isFirstMessage = false;
|
|
96
93
|
});
|
|
97
94
|
}
|
|
98
95
|
else {
|
|
99
|
-
Object.keys(prop).forEach(layerId => {
|
|
100
|
-
map.on(event, layerId, e => {
|
|
96
|
+
Object.keys(prop).forEach((layerId) => {
|
|
97
|
+
map.on(event, layerId, (e) => {
|
|
101
98
|
prop[layerId](e);
|
|
102
99
|
isFirstMessage &&
|
|
103
100
|
debug(`Map '${event}' event on '${layerId}':`, e);
|
|
@@ -108,7 +105,7 @@ export const MapGL = props => {
|
|
|
108
105
|
}
|
|
109
106
|
});
|
|
110
107
|
// Update Viewport
|
|
111
|
-
map.on('move', event => {
|
|
108
|
+
map.on('move', (event) => {
|
|
112
109
|
const viewport = {
|
|
113
110
|
...props.viewport,
|
|
114
111
|
id: props.id,
|
|
@@ -124,7 +121,7 @@ export const MapGL = props => {
|
|
|
124
121
|
setInternal(true);
|
|
125
122
|
!event.viewport && props.onViewportChange?.(viewport);
|
|
126
123
|
});
|
|
127
|
-
map.on('moveend', event => {
|
|
124
|
+
map.on('moveend', (event) => {
|
|
128
125
|
!event.rotate &&
|
|
129
126
|
props.onViewportChange?.({ ...props.viewport, inTransit: false });
|
|
130
127
|
setInternal(false);
|
|
@@ -132,7 +129,7 @@ export const MapGL = props => {
|
|
|
132
129
|
});
|
|
133
130
|
});
|
|
134
131
|
// Hook up viewport event
|
|
135
|
-
createEffect(on(() => props.viewport, vp => {
|
|
132
|
+
createEffect(on(() => props.viewport, (vp) => {
|
|
136
133
|
if (props.id !== vp?.id || internal())
|
|
137
134
|
return;
|
|
138
135
|
const viewport = {
|
|
@@ -163,8 +160,8 @@ export const MapGL = props => {
|
|
|
163
160
|
debug('Set Cursor to:', cur);
|
|
164
161
|
});
|
|
165
162
|
const insertLayers = (list, layers) => {
|
|
166
|
-
layers.forEach(layer => {
|
|
167
|
-
const index = list.findIndex(i => layer.metadata.smg.beforeType
|
|
163
|
+
layers.forEach((layer) => {
|
|
164
|
+
const index = list.findIndex((i) => layer.metadata.smg.beforeType
|
|
168
165
|
? i.type === layer.metadata.smg.beforeType
|
|
169
166
|
: i.id === layer.metadata.smg.beforeId);
|
|
170
167
|
list =
|
|
@@ -175,13 +172,13 @@ export const MapGL = props => {
|
|
|
175
172
|
return list;
|
|
176
173
|
};
|
|
177
174
|
// Update map style
|
|
178
|
-
createEffect(prev => {
|
|
175
|
+
createEffect((prev) => {
|
|
179
176
|
const style = getStyle(props.options?.style, props.darkStyle);
|
|
180
177
|
if (map?.isStyleLoaded() && prev !== style) {
|
|
181
178
|
const oldStyle = map.getStyle();
|
|
182
|
-
const oldLayers = oldStyle.layers.filter(l => map.layerIdList.includes(l.id));
|
|
179
|
+
const oldLayers = oldStyle.layers.filter((l) => map.layerIdList.includes(l.id));
|
|
183
180
|
const oldSources = Object.keys(oldStyle.sources)
|
|
184
|
-
.filter(s => map.sourceIdList.includes(s))
|
|
181
|
+
.filter((s) => map.sourceIdList.includes(s))
|
|
185
182
|
.reduce((obj, key) => ({ ...obj, [key]: oldStyle.sources[key] }), {});
|
|
186
183
|
map.setStyle(style);
|
|
187
184
|
map.once('styledata', () => {
|
|
@@ -206,7 +203,7 @@ export const MapGL = props => {
|
|
|
206
203
|
'showCollisionBoxes',
|
|
207
204
|
'showPadding',
|
|
208
205
|
'showOverdrawInspector',
|
|
209
|
-
].forEach(item => {
|
|
206
|
+
].forEach((item) => {
|
|
210
207
|
createEffect(() => {
|
|
211
208
|
const prop = props[item];
|
|
212
209
|
if (!map || !prop)
|
|
@@ -229,9 +226,6 @@ export const MapGL = props => {
|
|
|
229
226
|
inset: 0,
|
|
230
227
|
'z-index': -1,
|
|
231
228
|
}}/>
|
|
232
|
-
{mapLoaded() &&
|
|
233
|
-
<MapProvider map={mapLoaded()}>
|
|
234
|
-
{props.children}
|
|
235
|
-
</MapProvider>}
|
|
229
|
+
{mapLoaded() && (<MapProvider map={mapLoaded()}>{props.children}</MapProvider>)}
|
|
236
230
|
</>);
|
|
237
231
|
};
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { createContext, useContext
|
|
2
|
-
|
|
3
|
-
const [
|
|
4
|
-
export const MapContext = createContext([
|
|
5
|
-
export const
|
|
6
|
-
export const MapProvider = props => {
|
|
7
|
-
props.map &&
|
|
8
|
-
|
|
9
|
-
return (<MapContext.Provider value={[map, userInteraction]}>
|
|
10
|
-
{props.children}
|
|
11
|
-
</MapContext.Provider>);
|
|
1
|
+
import { createContext, useContext } from 'solid-js';
|
|
2
|
+
import { createStore } from 'solid-js/store';
|
|
3
|
+
const [state, setState] = createStore({ map: null });
|
|
4
|
+
export const MapContext = createContext([state]);
|
|
5
|
+
export const useMapContext = () => useContext(MapContext);
|
|
6
|
+
export const MapProvider = (props) => {
|
|
7
|
+
props.map && setState('map', props.map);
|
|
8
|
+
return (<MapContext.Provider value={[state]}>{props.children}</MapContext.Provider>);
|
|
12
9
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { onCleanup, createEffect, untrack } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
export const Marker = (props) => {
|
|
4
|
-
const [
|
|
4
|
+
const [ctx] = useMapContext();
|
|
5
5
|
let marker = null;
|
|
6
6
|
let popup = null;
|
|
7
7
|
if (!props.lngLat)
|
|
@@ -10,9 +10,9 @@ export const Marker = (props) => {
|
|
|
10
10
|
createEffect(() => {
|
|
11
11
|
const ops = { ...props.options };
|
|
12
12
|
const pops = { ...props.options?.popup };
|
|
13
|
-
if (!map
|
|
13
|
+
if (!ctx.map)
|
|
14
14
|
return;
|
|
15
|
-
const mapboxgl = map
|
|
15
|
+
const mapboxgl = ctx.map.mapLib;
|
|
16
16
|
untrack(() => {
|
|
17
17
|
popup?.remove();
|
|
18
18
|
popup = props.children
|
|
@@ -28,7 +28,7 @@ export const Marker = (props) => {
|
|
|
28
28
|
.on('drag', () => props.onLngLatChange?.(marker.getLngLat().toArray()))
|
|
29
29
|
.setDraggable(props.draggable || props.options?.draggable)
|
|
30
30
|
.setLngLat(props.lngLat)
|
|
31
|
-
.addTo(map
|
|
31
|
+
.addTo(ctx.map);
|
|
32
32
|
props.openPopup !== popup?.isOpen() && marker.togglePopup();
|
|
33
33
|
});
|
|
34
34
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { onCleanup, createEffect, untrack } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { useMapContext } from '../MapProvider';
|
|
3
3
|
export const Popup = (props) => {
|
|
4
|
-
const [
|
|
4
|
+
const [ctx] = useMapContext();
|
|
5
5
|
let popup = null;
|
|
6
6
|
if (!props.trackPointer && !props.lngLat)
|
|
7
7
|
throw new Error('Popup - lngLat or trackPointer is required');
|
|
8
8
|
// Add or Update Popup
|
|
9
9
|
createEffect(() => {
|
|
10
10
|
const ops = { ...props.options };
|
|
11
|
-
if (!map
|
|
11
|
+
if (!ctx.map)
|
|
12
12
|
return;
|
|
13
|
-
const mapboxgl = map
|
|
13
|
+
const mapboxgl = ctx.map.mapLib;
|
|
14
14
|
untrack(() => {
|
|
15
15
|
popup?.remove();
|
|
16
16
|
popup = new mapboxgl.Popup(props.trackPointer
|
|
@@ -19,7 +19,7 @@ export const Popup = (props) => {
|
|
|
19
19
|
.setHTML(props.children || '')
|
|
20
20
|
.setLngLat(props.lngLat)
|
|
21
21
|
.on('close', () => props.onClose?.())
|
|
22
|
-
.addTo(map
|
|
22
|
+
.addTo(ctx.map);
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
// Update Position
|