solid-map-gl 1.7.2 → 1.8.1

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.
@@ -1,5 +1,5 @@
1
1
  import { createEffect, onCleanup } from 'solid-js';
2
- import { useMap } from '../MapGL';
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
@@ -9,16 +9,6 @@ const slerp = (a, b, t) => {
9
9
  return a.map((_, idx) => (Math.sin((1 - t) * theta) / Math.sin(theta)) * a[idx] +
10
10
  (Math.sin(t * theta) / Math.sin(theta)) * b[idx]);
11
11
  };
12
- // const slerp = (a, b, t) => {
13
- // const omega = 0.075
14
- // // TODO: Proper Calculation
15
- // // a.map((_, idx) => a[idx] * b[idx]).reduce((m, n) => m + n)
16
- // return a.map(
17
- // (_, idx) =>
18
- // (Math.sin((1 - t) * omega) / Math.sin(omega)) * a[idx] +
19
- // (Math.sin(t * omega) / Math.sin(omega)) * b[idx]
20
- // )
21
- // }
22
12
  // calculations from: https://easings.net
23
13
  const easeQuad = {
24
14
  in: (x) => x * x,
@@ -26,18 +16,18 @@ const easeQuad = {
26
16
  inOut: (x) => x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2,
27
17
  };
28
18
  export const Camera = props => {
29
- if (!useMap())
30
- return;
31
- const [map, userInteraction] = useMap();
19
+ const [ctx] = useMapContext();
20
+ if (!ctx.map)
21
+ return null;
32
22
  let animationTime = 0.1;
33
23
  let isReverse = false;
34
24
  const updateCameraPosition = async ([lng, lat, alt], target) => {
35
- const camera = map().getFreeCameraOptions();
36
- camera.position = map().mapLib.MercatorCoordinate.fromLngLat([lng, lat], alt);
25
+ const camera = ctx.map.getFreeCameraOptions();
26
+ camera.position = ctx.map.mapLib.MercatorCoordinate.fromLngLat([lng, lat], alt);
37
27
  camera.lookAtPoint(target);
38
- map().setFreeCameraOptions(camera);
28
+ ctx.map.setFreeCameraOptions(camera);
39
29
  };
40
- const frame = (time) => {
30
+ const frame = () => {
41
31
  props.translate && window.requestAnimationFrame(frame);
42
32
  const params = [
43
33
  props.translate.start,
@@ -57,47 +47,47 @@ export const Camera = props => {
57
47
  });
58
48
  const options = { duration: 1000, easing: n => n };
59
49
  const rotateGlobe = () => {
60
- if (userInteraction())
50
+ if (ctx.userInteraction)
61
51
  return;
62
52
  const { secPerRev = 120, maxSpinZoom = 5, slowSpinZoom = 3, } = props.rotateGlobe;
63
- const zoom = map().getZoom();
53
+ const zoom = ctx.map.getZoom();
64
54
  if (zoom > maxSpinZoom)
65
55
  return;
66
56
  let distancePerSecond = 360 / secPerRev;
67
57
  if (zoom > slowSpinZoom)
68
58
  distancePerSecond *= (maxSpinZoom - zoom) / (maxSpinZoom - slowSpinZoom);
69
- const center = map().getCenter();
59
+ const center = ctx.map.getCenter();
70
60
  center.lng = props.reverse
71
61
  ? center.lng + distancePerSecond
72
62
  : center.lng - distancePerSecond;
73
- map().easeTo({ center, ...options }, { rotate: true });
63
+ ctx.map.easeTo({ center, ...options }, { rotate: true });
74
64
  };
75
65
  const rotateViewport = () => {
76
- if (!props.rotateViewport || userInteraction())
66
+ if (!props.rotateViewport || ctx.userInteraction)
77
67
  return;
78
68
  const rotateViewport = props.rotateViewport;
79
69
  const secPerRev = rotateViewport?.secPerRev || 60;
80
70
  const bearing = props.reverse
81
- ? map().getBearing() + 360 / secPerRev
82
- : map().getBearing() - 360 / secPerRev;
71
+ ? ctx.map.getBearing() + 360 / secPerRev
72
+ : ctx.map.getBearing() - 360 / secPerRev;
83
73
  const pitch = rotateViewport?.pitch || 60;
84
74
  const around = rotateViewport?.around;
85
- map().easeTo({ bearing, pitch, around, ...options }, { rotate: true });
75
+ ctx.map.easeTo({ bearing, pitch, around, ...options }, { rotate: true });
86
76
  };
87
77
  const onEnd = () => (props.rotateGlobe ? rotateGlobe() : rotateViewport());
88
- map().on('moveend', onEnd).on('dragend', onEnd);
78
+ ctx.map.on('moveend', onEnd).on('dragend', onEnd);
89
79
  let originalCenter;
90
80
  createEffect(() => {
91
81
  if (props.rotateGlobe == undefined)
92
82
  return;
93
83
  if (props.rotateGlobe) {
94
- originalCenter = map().getCenter();
84
+ originalCenter = ctx.map.getCenter();
95
85
  rotateGlobe();
96
86
  }
97
87
  else {
98
88
  props.resetWhenStopped
99
- ? map().stop().easeTo({ center: originalCenter })
100
- : map().stop();
89
+ ? ctx.map.stop().easeTo({ center: originalCenter })
90
+ : ctx.map.stop();
101
91
  }
102
92
  });
103
93
  createEffect(() => {
@@ -106,9 +96,9 @@ export const Camera = props => {
106
96
  props.rotateViewport
107
97
  ? rotateViewport()
108
98
  : props.resetWhenStopped
109
- ? map().stop().resetNorthPitch()
110
- : map().stop();
99
+ ? ctx.map.stop().resetNorthPitch()
100
+ : ctx.map.stop();
111
101
  });
112
- onCleanup(() => map().off('moveend', onEnd).off('dragend', onEnd));
102
+ onCleanup(() => ctx.map.off('moveend', onEnd).off('dragend', onEnd));
113
103
  return props.children;
114
104
  };
@@ -1,36 +1,22 @@
1
- import { createEffect, onCleanup } from 'solid-js';
2
- import { useMap } from '../MapGL';
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
- if (!useMap())
24
- return;
25
- const [map] = useMap();
26
- let control = null;
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}`);
27
15
  // Add or Update Control
28
16
  createEffect(() => {
29
- control && map().hasControl(control) && map().removeControl(control);
30
- control = getControl(map().mapLib, props.type, props.options, props.custom);
31
- map().addControl(control, props.position);
17
+ const control = new ControlClass(props.options);
18
+ control && ctx.map.hasControl(control) && ctx.map.removeControl(control);
19
+ ctx.map.addControl(control, props.position);
32
20
  });
33
- // Remove Control
34
- onCleanup(() => map()?.removeControl(control));
35
21
  return null;
36
22
  };
@@ -1,13 +1,11 @@
1
1
  import { onCleanup } from 'solid-js';
2
- import { useMap } from '../MapGL';
2
+ import { useMapContext } from '../MapProvider';
3
3
  import { drawEvents } from '../../events';
4
- export const Draw = props => {
5
- if (!useMap())
6
- return;
7
- const [map] = useMap();
4
+ export const Draw = (props) => {
5
+ const [ctx] = useMapContext();
8
6
  // Add Draw Control
9
7
  const draw = new props.lib(props.options);
10
- map().addControl(draw, props.position || 'top-right');
8
+ ctx.map.addControl(draw, props.position || 'top-right');
11
9
  props.getInstance && props.getInstance(draw);
12
10
  // Hook up events
13
11
  const eventList = {};
@@ -16,15 +14,15 @@ export const Draw = props => {
16
14
  const event = `draw.${item.slice(2).toLowerCase()}`;
17
15
  const fn = evt => props[item](evt);
18
16
  eventList[event] = fn;
19
- map().on(event, fn);
17
+ ctx.map.on(event, fn);
20
18
  }
21
19
  });
22
20
  // Remove Draw Control
23
21
  onCleanup(() => {
24
22
  // Remove Events
25
- Object.keys(eventList).forEach(event => map().off(event, eventList[event]));
23
+ Object.keys(eventList).forEach(event => ctx.map.off(event, eventList[event]));
26
24
  // Remove Control
27
- map()?.removeControl(draw);
25
+ ctx.map?.removeControl(draw);
28
26
  });
29
27
  return null;
30
28
  };
@@ -1,5 +1,5 @@
1
1
  import { onCleanup, createSignal, createEffect, untrack, } from 'solid-js';
2
- import { useMap } from '../MapGL';
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,17 +19,15 @@ const PATTERN = {
19
19
  };
20
20
  export const patternList = Object.keys(PATTERN);
21
21
  export const MGL_Image = props => {
22
- if (!useMap())
23
- return;
24
- const [map] = useMap();
22
+ const [ctx] = useMapContext();
25
23
  const [size, setSize] = createSignal({ width: 0, height: 0 });
26
24
  const debug = (text, value) => {
27
- map().debug &&
25
+ ctx.map.debug &&
28
26
  console.debug('%c[MapGL]', 'color: #10b981', text, value || '');
29
27
  };
30
28
  // Remove Image
31
29
  onCleanup(() => {
32
- map()?.hasImage(props.id) && map()?.removeImage(props.id);
30
+ ctx.map?.hasImage(props.id) && ctx.map?.removeImage(props.id);
33
31
  debug('Remove Image:', props.id);
34
32
  });
35
33
  // Add or Update Image
@@ -43,23 +41,23 @@ export const MGL_Image = props => {
43
41
  : props.options;
44
42
  _loadImage(props.source || _createPattern(props.pattern), data => {
45
43
  const { width, height } = data;
46
- if (map() && !map().hasImage(props.id))
47
- map().addImage(props.id, data, ops);
44
+ if (ctx.map && !ctx.map.hasImage(props.id))
45
+ ctx.map.addImage(props.id, data, ops);
48
46
  if (!props.pattern &&
49
47
  untrack(() => width === size().width && height === size().height)) {
50
- map().updateImage(props.id, data);
51
- map().triggerRepaint();
48
+ ctx.map.updateImage(props.id, data);
49
+ ctx.map.triggerRepaint();
52
50
  }
53
51
  else {
54
- map().removeImage(props.id);
55
- map().addImage(props.id, data, ops);
52
+ ctx.map.removeImage(props.id);
53
+ ctx.map.addImage(props.id, data, ops);
56
54
  }
57
55
  setSize({ width, height });
58
56
  debug('Add Image:', props.id);
59
- map().on('style.load', () => {
60
- if (map().hasImage(props.id))
57
+ ctx.map.on('style.load', () => {
58
+ if (ctx.map.hasImage(props.id))
61
59
  return;
62
- map().addImage(props.id, data, ops);
60
+ ctx.map.addImage(props.id, data, ops);
63
61
  debug('Re-Add Image:', props.id);
64
62
  });
65
63
  });
@@ -78,7 +76,7 @@ export const MGL_Image = props => {
78
76
  }
79
77
  if (typeof image !== 'string')
80
78
  return callback(image);
81
- map().loadImage(image, async (error, imageData) => {
79
+ ctx.map.loadImage(image, async (error, imageData) => {
82
80
  if (error) {
83
81
  if (typeof image == 'string' && image?.trimEnd().endsWith('.svg')) {
84
82
  image = await (await fetch(image)).text();
@@ -1,5 +1,5 @@
1
1
  import { onCleanup, createEffect, createUniqueId } from 'solid-js';
2
- import { useMap } from '../MapGL';
2
+ import { useMapContext } from '../MapProvider';
3
3
  import { useSourceId } from '../Source';
4
4
  import { layerEvents } from '../../events';
5
5
  const diff = (newProps = {}, prevProps = {}) => {
@@ -13,17 +13,15 @@ const diff = (newProps = {}, prevProps = {}) => {
13
13
  }, []);
14
14
  };
15
15
  export const Layer = props => {
16
- if (!useMap())
17
- return;
18
- const [map] = useMap();
16
+ const [ctx] = useMapContext();
19
17
  const sourceId = props.style?.source || useSourceId();
20
18
  props.id ??= createUniqueId();
21
19
  const debug = (text, value) => {
22
- map().debug &&
20
+ ctx.map.debug &&
23
21
  console.debug('%c[MapGL]', 'color: #10b981', text, value || '');
24
22
  };
25
23
  // Add Layer
26
- map().addLayer(props.customLayer || {
24
+ ctx.map.addLayer(props.customLayer || {
27
25
  ...props.style,
28
26
  id: props.id,
29
27
  source: sourceId,
@@ -31,17 +29,17 @@ export const Layer = props => {
31
29
  smg: { beforeType: props.beforeType, beforeId: props.beforeId },
32
30
  },
33
31
  }, props.beforeType
34
- ? map()
32
+ ? ctx.map
35
33
  .getStyle()
36
34
  .layers.find(l => l.type === props.beforeType)?.id
37
35
  : props.beforeId);
38
- map().layerIdList.push(props.id);
36
+ ctx.map.layerIdList.push(props.id);
39
37
  debug('Add Layer:', props.id);
40
38
  // Hook up events
41
39
  layerEvents.forEach(item => {
42
40
  if (props[item]) {
43
41
  const event = item.slice(2).toLowerCase();
44
- map().on(event, props.id, evt => {
42
+ ctx.map.on(event, props.id, evt => {
45
43
  props[item](evt);
46
44
  debug(`Layer '${event}' event on '${props.id}':`, evt);
47
45
  });
@@ -53,13 +51,13 @@ export const Layer = props => {
53
51
  if (style === prev)
54
52
  return;
55
53
  if (style.layout !== prev?.layout)
56
- diff(style.layout, prev?.layout).forEach(([key, value]) => map().setLayoutProperty(props.id, key, value, { validate: false }));
54
+ diff(style.layout, prev?.layout).forEach(([key, value]) => ctx.map.setLayoutProperty(props.id, key, value, { validate: false }));
57
55
  if (style.paint !== prev?.paint)
58
- diff(style.paint, prev?.paint).forEach(([key, value]) => map().setPaintProperty(props.id, key, value, { validate: false }));
56
+ diff(style.paint, prev?.paint).forEach(([key, value]) => ctx.map.setPaintProperty(props.id, key, value, { validate: false }));
59
57
  if (style.minzoom !== prev?.minzoom || style.maxzoom !== prev?.maxzoom)
60
- map().setLayerZoomRange(props.id, style.minzoom, style.maxzoom);
58
+ ctx.map.setLayerZoomRange(props.id, style.minzoom, style.maxzoom);
61
59
  if (style.filter !== prev?.filter)
62
- map().setFilter(props.id, style.filter, { validate: false });
60
+ ctx.map.setFilter(props.id, style.filter, { validate: false });
63
61
  debug('Update Layer Style:', props.id);
64
62
  return style;
65
63
  }, props.style);
@@ -67,7 +65,7 @@ export const Layer = props => {
67
65
  createEffect((prev) => {
68
66
  if (props.visible === prev)
69
67
  return;
70
- map().setLayoutProperty(props.id, 'visibility', props.visible ? 'visible' : 'none', { validate: false });
68
+ ctx.map.setLayoutProperty(props.id, 'visibility', props.visible ? 'visible' : 'none', { validate: false });
71
69
  debug(`Update Visibility (${props.id}):`, props.visible);
72
70
  return props.visible;
73
71
  }, props.visible);
@@ -75,26 +73,26 @@ export const Layer = props => {
75
73
  createEffect(async () => {
76
74
  if (!props.filter)
77
75
  return;
78
- !map().isStyleLoaded() && (await map().once('styledata'));
79
- map().setFilter(props.id, props.filter);
76
+ !ctx.map.isStyleLoaded() && (await ctx.map.once('styledata'));
77
+ ctx.map.setFilter(props.id, props.filter);
80
78
  debug(`Update Filter (${props.id}):`, props.filter);
81
79
  });
82
80
  // Update Feature State
83
81
  createEffect(async () => {
84
- if (!props.featureState || !props.featureState.id)
82
+ if (!props.featureState || props.featureState.id === null)
85
83
  return;
86
- !map().isStyleLoaded() && (await map().once('styledata'));
87
- map().removeFeatureState({
84
+ !ctx.map.isStyleLoaded() && (await ctx.map.once('styledata'));
85
+ ctx.map.removeFeatureState({
88
86
  source: sourceId,
89
87
  sourceLayer: props.style['source-layer'],
90
88
  });
91
- map().setFeatureState({
89
+ ctx.map.setFeatureState({
92
90
  source: sourceId,
93
91
  sourceLayer: props.style['source-layer'],
94
92
  id: props.featureState.id,
95
93
  }, props.featureState.state);
96
94
  });
97
95
  //Remove Layer
98
- onCleanup(() => map()?.getLayer(props.id) && map()?.removeLayer(props.id));
96
+ onCleanup(() => ctx.map?.getLayer(props.id) && ctx.map?.removeLayer(props.id));
99
97
  return props.children;
100
98
  };
@@ -1,12 +1,10 @@
1
1
  import { onCleanup, createEffect } from 'solid-js';
2
- import { useMap } from '../MapGL';
3
- export const Light = props => {
4
- if (!useMap())
5
- return;
6
- const [map] = useMap();
2
+ import { useMapContext } from '../MapProvider';
3
+ export const Light = (props) => {
4
+ const [ctx] = useMapContext();
7
5
  // Add or Update Light Layer
8
- createEffect(() => map().setLight(props.style || {}));
6
+ createEffect(() => ctx.map.setLight(props.style || {}));
9
7
  // Remove Light Layer
10
- onCleanup(() => map()?.setLight(null));
8
+ onCleanup(() => ctx.map?.setLight(null));
11
9
  return null;
12
10
  };
@@ -1,9 +1,7 @@
1
- import { createSignal, createEffect, onMount, onCleanup, createContext, useContext, createUniqueId, on, } from 'solid-js';
1
+ import { createSignal, createEffect, onMount, onCleanup, createUniqueId, on, } from 'solid-js';
2
+ import { MapProvider } from '../MapProvider';
2
3
  import { mapEvents } from '../../events';
3
4
  import { vectorStyleList } from '../../mapStyles';
4
- const MapContext = createContext();
5
- /** Provides the Mapbox Map Object */
6
- export const useMap = () => useContext(MapContext);
7
5
  /** Creates a new Map Container */
8
6
  export const MapGL = props => {
9
7
  props.id ??= createUniqueId();
@@ -11,8 +9,7 @@ export const MapGL = props => {
11
9
  let mapRef;
12
10
  let resizeObserver;
13
11
  let mutationObserver;
14
- const [mapLoaded, setMapLoaded] = createSignal(false);
15
- const [mapRoot, setMapRoot] = createSignal();
12
+ const [mapLoaded, setMapLoaded] = createSignal(null);
16
13
  const [darkMode, setDarkMode] = createSignal((typeof window !== 'undefined' &&
17
14
  window.matchMedia('(prefers-color-scheme: dark)').matches) ||
18
15
  (typeof document !== 'undefined' &&
@@ -40,7 +37,7 @@ export const MapGL = props => {
40
37
  let mapLib = props.mapLib || (await import('mapbox-gl'));
41
38
  if (!mapLib.Map)
42
39
  mapLib = window['maplibregl'] || window['mapboxgl'];
43
- if (!mapLib.supported())
40
+ if (!mapLib.supported?.())
44
41
  throw new Error('Mapbox GL not supported');
45
42
  debug(`Map (v${mapLib.version}) loading...`);
46
43
  map = new mapLib.Map({
@@ -60,8 +57,7 @@ export const MapGL = props => {
60
57
  map.sourceIdList = [];
61
58
  map.layerIdList = [];
62
59
  map.once('load', () => {
63
- setMapRoot(map);
64
- setMapLoaded(true);
60
+ setMapLoaded(map);
65
61
  debug('Map loaded');
66
62
  ['mousedown', 'touchstart', 'wheel'].forEach(event => map.on(event, evt => !evt.rotate && setUserInteraction(true)));
67
63
  ['moveend', 'mouseup', 'touchend'].forEach(event => map.on(event, evt => !evt.rotate && setUserInteraction(false)));
@@ -116,7 +112,7 @@ export const MapGL = props => {
116
112
  const viewport = {
117
113
  ...props.viewport,
118
114
  id: props.id,
119
- point: { x: event.originalEvent?.x, y: event.originalEvent?.y },
115
+ // point: { x: event.originalEvent?.x, y: event.originalEvent?.y },
120
116
  center: props.viewport?.center?.lat
121
117
  ? map.getCenter()
122
118
  : [map.getCenter().lng, map.getCenter().lat],
@@ -225,7 +221,7 @@ export const MapGL = props => {
225
221
  map?.remove();
226
222
  debug('Map removed');
227
223
  });
228
- return (<MapContext.Provider value={[mapRoot, userInteraction, debug]}>
224
+ return (<>
229
225
  <div ref={mapRef} id={props.id} class={props?.class} classList={props?.classList} style={props?.class || props?.classList
230
226
  ? null
231
227
  : props.style || {
@@ -233,6 +229,9 @@ export const MapGL = props => {
233
229
  inset: 0,
234
230
  'z-index': -1,
235
231
  }}/>
236
- {mapLoaded() && props.children}
237
- </MapContext.Provider>);
232
+ {mapLoaded() &&
233
+ <MapProvider map={mapLoaded()}>
234
+ {props.children}
235
+ </MapProvider>}
236
+ </>);
238
237
  };
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from "solid-js";
2
+ import { createStore } from "solid-js/store";
3
+ const [state, setState] = createStore({
4
+ map: null,
5
+ userInteraction: false
6
+ });
7
+ export const MapContext = createContext([state]);
8
+ export const useMapContext = () => useContext(MapContext);
9
+ export const MapProvider = props => {
10
+ props.map && setState('map', props.map);
11
+ props.userInteraction && setState('userInteraction', props.userInteraction);
12
+ return (<MapContext.Provider value={[state]}>
13
+ {props.children}
14
+ </MapContext.Provider>);
15
+ };
@@ -1,9 +1,7 @@
1
1
  import { onCleanup, createEffect, untrack } from 'solid-js';
2
- import { useMap } from '../MapGL';
3
- export const Marker = props => {
4
- if (!useMap())
5
- return;
6
- const [map] = useMap();
2
+ import { useMapContext } from '../MapProvider';
3
+ export const Marker = (props) => {
4
+ const [ctx] = useMapContext();
7
5
  let marker = null;
8
6
  let popup = null;
9
7
  if (!props.lngLat)
@@ -12,9 +10,9 @@ export const Marker = props => {
12
10
  createEffect(() => {
13
11
  const ops = { ...props.options };
14
12
  const pops = { ...props.options?.popup };
15
- if (!map())
13
+ if (!ctx.map)
16
14
  return;
17
- const mapboxgl = map().mapLib;
15
+ const mapboxgl = ctx.map.mapLib;
18
16
  untrack(() => {
19
17
  popup?.remove();
20
18
  popup = props.children
@@ -30,7 +28,7 @@ export const Marker = props => {
30
28
  .on('drag', () => props.onLngLatChange?.(marker.getLngLat().toArray()))
31
29
  .setDraggable(props.draggable || props.options?.draggable)
32
30
  .setLngLat(props.lngLat)
33
- .addTo(map());
31
+ .addTo(ctx.map);
34
32
  props.openPopup !== popup?.isOpen() && marker.togglePopup();
35
33
  });
36
34
  });
@@ -1,18 +1,16 @@
1
1
  import { onCleanup, createEffect, untrack } from 'solid-js';
2
- import { useMap } from '../MapGL';
3
- export const Popup = props => {
4
- if (!useMap())
5
- return;
6
- const [map] = useMap();
2
+ import { useMapContext } from '../MapProvider';
3
+ export const Popup = (props) => {
4
+ const [ctx] = useMapContext();
7
5
  let popup = null;
8
6
  if (!props.trackPointer && !props.lngLat)
9
7
  throw new Error('Popup - lngLat or trackPointer is required');
10
8
  // Add or Update Popup
11
9
  createEffect(() => {
12
10
  const ops = { ...props.options };
13
- if (!map())
11
+ if (!ctx.map)
14
12
  return;
15
- const mapboxgl = map().mapLib;
13
+ const mapboxgl = ctx.map.mapLib;
16
14
  untrack(() => {
17
15
  popup?.remove();
18
16
  popup = new mapboxgl.Popup(props.trackPointer
@@ -21,7 +19,7 @@ export const Popup = props => {
21
19
  .setHTML(props.children || '')
22
20
  .setLngLat(props.lngLat)
23
21
  .on('close', () => props.onClose?.())
24
- .addTo(map());
22
+ .addTo(ctx.map);
25
23
  });
26
24
  });
27
25
  // Update Position
@@ -1,15 +1,13 @@
1
1
  import { onCleanup, createEffect, createContext, useContext, createUniqueId, } from 'solid-js';
2
- import { useMap } from '../MapGL';
2
+ import { useMapContext } from '../MapProvider';
3
3
  import { rasterStyleList } from '../../mapStyles';
4
4
  const SourceContext = createContext();
5
5
  export const useSourceId = () => useContext(SourceContext);
6
6
  export const Source = props => {
7
- if (!useMap())
8
- return;
9
- const [map] = useMap();
7
+ const [ctx] = useMapContext();
10
8
  props.id ??= createUniqueId();
11
9
  const debug = (text, value) => {
12
- map().debug &&
10
+ ctx.map.debug &&
13
11
  console.debug('%c[MapGL]', 'color: #ec4899', text, value || '');
14
12
  };
15
13
  const lookup = url => {
@@ -32,16 +30,16 @@ export const Source = props => {
32
30
  return source;
33
31
  };
34
32
  // Add Source
35
- map().addSource(props.id, lookup(props.source.url));
36
- map().sourceIdList.push(props.id);
33
+ ctx.map.addSource(props.id, lookup(props.source.url));
34
+ ctx.map.sourceIdList.push(props.id);
37
35
  debug('Add Source:', props.id);
38
36
  // Update Data
39
- const source = map().getSource(props.id);
37
+ const source = ctx.map.getSource(props.id);
40
38
  switch (props.source.type) {
41
39
  case 'geojson':
42
40
  createEffect(() => {
43
41
  const data = props.source.data;
44
- if (!map().isSourceLoaded(props.id))
42
+ if (!ctx.map.isSourceLoaded(props.id))
45
43
  return;
46
44
  source.setData(data || {});
47
45
  debug('Update GeoJSON Data:', props.id);
@@ -51,7 +49,7 @@ export const Source = props => {
51
49
  createEffect(() => {
52
50
  const url = props.source.url;
53
51
  const coords = props.source.coordinates;
54
- if (!map().isSourceLoaded(props.id))
52
+ if (!ctx.map.isSourceLoaded(props.id))
55
53
  return;
56
54
  source.updateImage(url, coords);
57
55
  debug('Update Image Data:', props.id);
@@ -61,7 +59,7 @@ export const Source = props => {
61
59
  createEffect(() => {
62
60
  const url = props.source.url;
63
61
  const tiles = props.source.tiles;
64
- if (!map().isSourceLoaded(props.id))
62
+ if (!ctx.map.isSourceLoaded(props.id))
65
63
  return;
66
64
  url ? source.setUrl(url) : source.setTiles(tiles);
67
65
  debug('Update Vector Data:', props.id);
@@ -70,7 +68,7 @@ export const Source = props => {
70
68
  case 'raster':
71
69
  createEffect(() => {
72
70
  const src = lookup(props.source.url);
73
- if (!map().isSourceLoaded(props.id))
71
+ if (!ctx.map.isSourceLoaded(props.id))
74
72
  return;
75
73
  src.url ? source.setUrl(src.url) : source.setTiles(src.tiles);
76
74
  debug('Update Raster Data:', props.id);
@@ -79,10 +77,10 @@ export const Source = props => {
79
77
  }
80
78
  // Remove Source
81
79
  onCleanup(() => {
82
- map()
80
+ ctx.map
83
81
  ?.getStyle()
84
- .layers.forEach(layer => layer.source === props.id && map().removeLayer(layer.id));
85
- map()?.getSource(props.id) && map()?.removeSource(props.id);
82
+ .layers.forEach(layer => layer.source === props.id && ctx.map.removeLayer(layer.id));
83
+ ctx.map?.getSource(props.id) && ctx.map?.removeSource(props.id);
86
84
  debug('Remove Source:', props.id);
87
85
  });
88
86
  return (<SourceContext.Provider value={props.id}>