solid-map-gl 1.0.0
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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/esm/index.js +386 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/source/components/Control/index.jsx +43 -0
- package/dist/source/components/Fog/index.jsx +21 -0
- package/dist/source/components/Image/index.jsx +38 -0
- package/dist/source/components/Layer/index.jsx +75 -0
- package/dist/source/components/MapGL/index.jsx +69 -0
- package/dist/source/components/Marker/index.jsx +22 -0
- package/dist/source/components/Popup/index.jsx +22 -0
- package/dist/source/components/Sky/index.jsx +22 -0
- package/dist/source/components/Source/index.jsx +31 -0
- package/dist/source/components/Terrain/index.jsx +23 -0
- package/dist/source/index.jsx +10 -0
- package/dist/types/components/Control/index.d.ts +12 -0
- package/dist/types/components/Fog/index.d.ts +7 -0
- package/dist/types/components/Image/index.d.ts +13 -0
- package/dist/types/components/Layer/index.d.ts +18 -0
- package/dist/types/components/MapGL/index.d.ts +23 -0
- package/dist/types/components/Marker/index.d.ts +7 -0
- package/dist/types/components/Popup/index.d.ts +8 -0
- package/dist/types/components/Sky/index.d.ts +7 -0
- package/dist/types/components/Source/index.d.ts +8 -0
- package/dist/types/components/Terrain/index.d.ts +7 -0
- package/dist/types/index.d.ts +11 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 GIShub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# GIShub - Solid Mapbox GL JS
|
|
4
|
+
|
|
5
|
+
<!-- [](https://github.com/urbica/react-map-gl/actions)
|
|
6
|
+
[](https://codecov.io/gh/urbica/react-map-gl)
|
|
7
|
+
[](https://www.npmjs.com/package/@urbica/react-map-gl)
|
|
8
|
+
[](https://www.npmjs.com/package/@urbica/react-map-gl)
|
|
9
|
+
 -->
|
|
10
|
+
|
|
11
|
+
[Solid](https://www.solidjs.com/) Component Library for [Mapbox GL JS.](https://github.com/mapbox/mapbox-gl-js) Mapbox GL JS is a JavaScript library that renders interactive maps from vector tiles and Mapbox styles using WebGL. This project is intended to be as close as possible to the [Mapbox GL JS API.](https://docs.mapbox.com/mapbox-gl-js/api/)
|
|
12
|
+
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Components](#components)
|
|
15
|
+
- [Usage](#usage)
|
|
16
|
+
- [Static Map](#static-map)
|
|
17
|
+
- [Interactive Map](#interactive-map)
|
|
18
|
+
- [Map with Source and Layer](#map-with-source-and-layer)
|
|
19
|
+
- [Map with GeoJSON Source](#map-with-geojson-source)
|
|
20
|
+
|
|
21
|
+
<br>
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
yarn add gishub/solid-map-gl
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```shell
|
|
32
|
+
npm install --save gishub/solid-map-gl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Optional Dependencies
|
|
36
|
+
|
|
37
|
+
If you want to use `LanguageControl` and `TrafficControl`:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
yarn add @mapbox/mapbox-gl-language @mapbox/mapbox-gl-traffic
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
npm install --save @mapbox/mapbox-gl-language @mapbox/mapbox-gl-traffic
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Components
|
|
48
|
+
|
|
49
|
+
| Component | Description |
|
|
50
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| [MapGL](src/components/MapGL) | Represents map on the page |
|
|
52
|
+
| [Source](src/components/Source) | [Sources](https://docs.mapbox.com/mapbox-gl-js/api/#sources) specify the geographic features to be rendered on the map |
|
|
53
|
+
| [Layer](src/components/Layer) | [Layers](https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers) specify the `Sources` style |
|
|
54
|
+
| [Sky](src/components/Sky) | Specify the Sky Layer |
|
|
55
|
+
| [Fog](src/components/Fog) | Specify the Fog Layer |
|
|
56
|
+
| [Terrain](src/components/Terrain) | Specify the Terrain Layer |
|
|
57
|
+
| [Image](src/components/Image) | Adds an image to the map style |
|
|
58
|
+
| [Popup](src/components/Popup) | Component for [Mapbox GL JS Popup](https://docs.mapbox.com/mapbox-gl-js/api/#popup) |
|
|
59
|
+
| [Marker](src/components/Marker) | Component for [Mapbox GL JS Marker](https://docs.mapbox.com/mapbox-gl-js/api/#marker) |
|
|
60
|
+
| [Control](src/components/Control) | Represents the map's control |
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
|
|
64
|
+
To use any of Mapbox’s tools, APIs, or SDKs, you’ll need a Mapbox [access token](https://www.mapbox.com/help/define-access-token/). Mapbox uses access tokens to associate requests to API resources with your account. You can find all your access tokens, create new ones, or delete existing ones on your [API access tokens page](https://www.mapbox.com/studio/account/tokens/).
|
|
65
|
+
|
|
66
|
+
### Static Map
|
|
67
|
+
|
|
68
|
+
By default, `MapGL` component renders in a static mode. That means that the user cannot interact with the map.
|
|
69
|
+
|
|
70
|
+
```jsx
|
|
71
|
+
import MapGL from '../solid-map-gl'
|
|
72
|
+
|
|
73
|
+
<MapGL
|
|
74
|
+
options={{
|
|
75
|
+
accessToken: { MAPBOX_ACCESS_TOKEN },
|
|
76
|
+
style: 'mapbox://styles/mapbox/light-v10',
|
|
77
|
+
}}
|
|
78
|
+
viewport={{
|
|
79
|
+
center: [-122.41, 37.78]
|
|
80
|
+
zoom: 11,
|
|
81
|
+
}}>
|
|
82
|
+
</MapGL>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Interactive Map
|
|
86
|
+
|
|
87
|
+
In most cases, you will want the user to interact with the map. To do this, you need to provide `onViewportChange` handler, that will update the map's viewport state.
|
|
88
|
+
|
|
89
|
+
```jsx
|
|
90
|
+
import { createSignal } from 'solid-js'
|
|
91
|
+
import MapGL, { Viewport } from '../solid-map-gl'
|
|
92
|
+
|
|
93
|
+
const [viewport, setViewport] = createSignal({
|
|
94
|
+
center: [-122.41, 37.78]
|
|
95
|
+
zoom: 11,
|
|
96
|
+
} as Viewport)
|
|
97
|
+
|
|
98
|
+
<MapGL
|
|
99
|
+
options={{
|
|
100
|
+
accessToken: { MAPBOX_ACCESS_TOKEN },
|
|
101
|
+
style: 'mapbox://styles/mapbox/light-v10',
|
|
102
|
+
}}
|
|
103
|
+
viewport={viewport()}
|
|
104
|
+
onViewportChange={evt => setViewport(evt)}>
|
|
105
|
+
</MapGL>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Map with Source and Layer
|
|
109
|
+
|
|
110
|
+
[Sources](https://docs.mapbox.com/mapbox-gl-js/api/sources/) specify the geographic features to be rendered on the map.
|
|
111
|
+
|
|
112
|
+
[Layers](https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/) specify the Sources styles. The type of layer is specified by the `"type"` property in the layers style object, and must be one of `background`, `fill`, `line`, `symbol`, `raster`, `circle`, `fill-extrusion`, `heatmap`, `hillshade`.
|
|
113
|
+
|
|
114
|
+
Except for layers of the `background` type, each layer needs to refer to a source. Either buy referencing the `id` in `sourceId` or by nesting the layer within the source component. Layers take the data that they get from a source, optionally filter features, and then define how those features are styled.
|
|
115
|
+
|
|
116
|
+
```jsx
|
|
117
|
+
import MapGL, { Source, Layer } from '../solid-map-gl'
|
|
118
|
+
|
|
119
|
+
<MapGL
|
|
120
|
+
options={{
|
|
121
|
+
accessToken: { MAPBOX_ACCESS_TOKEN },
|
|
122
|
+
style: 'mapbox://styles/mapbox/light-v10',
|
|
123
|
+
}}>
|
|
124
|
+
<Source
|
|
125
|
+
source={{
|
|
126
|
+
type: 'vector',
|
|
127
|
+
url: 'mapbox://mapbox.mapbox-terrain-v2'
|
|
128
|
+
}}>
|
|
129
|
+
<Layer style={{
|
|
130
|
+
type: 'line',
|
|
131
|
+
'source-layer': 'contour'
|
|
132
|
+
paint: {
|
|
133
|
+
'line-color': '#877b59',
|
|
134
|
+
'line-width': 1,
|
|
135
|
+
}
|
|
136
|
+
}} />
|
|
137
|
+
</Source>
|
|
138
|
+
</MapGL>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Map with GeoJSON Source
|
|
142
|
+
|
|
143
|
+
To draw a GeoJSON on a map, add `Source` with the `type` property set to `geojson` and `data` property set to a URL or inline [GeoJSON](http://geojson.org/).
|
|
144
|
+
|
|
145
|
+
```jsx
|
|
146
|
+
import { createSignal } from 'solid-js'
|
|
147
|
+
import MapGL, { Source, Layer } from '../solid-map-gl'
|
|
148
|
+
|
|
149
|
+
const [viewport, setViewport] = createSignal({
|
|
150
|
+
center: [-122.486052, 37.830348],
|
|
151
|
+
zoom: 15,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const data = {
|
|
155
|
+
type: 'Feature',
|
|
156
|
+
geometry: {
|
|
157
|
+
type: 'LineString',
|
|
158
|
+
coordinates: [
|
|
159
|
+
[-122.48369693756104, 37.83381888486939],
|
|
160
|
+
[-122.48348236083984, 37.83317489144141],
|
|
161
|
+
[-122.48339653015138, 37.83270036637107],
|
|
162
|
+
[-122.48356819152832, 37.832056363179625],
|
|
163
|
+
[-122.48404026031496, 37.83114119107971],
|
|
164
|
+
[-122.48404026031496, 37.83049717427869],
|
|
165
|
+
[-122.48348236083984, 37.829920943955045],
|
|
166
|
+
[-122.48356819152832, 37.82954808664175],
|
|
167
|
+
[-122.48507022857666, 37.82944639795659],
|
|
168
|
+
[-122.48610019683838, 37.82880236636284],
|
|
169
|
+
[-122.48695850372314, 37.82931081282506],
|
|
170
|
+
[-122.48700141906738, 37.83080223556934],
|
|
171
|
+
[-122.48751640319824, 37.83168351665737],
|
|
172
|
+
[-122.48803138732912, 37.832158048267786],
|
|
173
|
+
[-122.48888969421387, 37.83297152392784],
|
|
174
|
+
[-122.48987674713133, 37.83263257682617],
|
|
175
|
+
[-122.49043464660643, 37.832937629287755],
|
|
176
|
+
[-122.49125003814696, 37.832429207817725],
|
|
177
|
+
[-122.49163627624512, 37.832564787218985],
|
|
178
|
+
[-122.49223709106445, 37.83337825839438],
|
|
179
|
+
[-122.49378204345702, 37.83368330777276],
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
<MapGL
|
|
185
|
+
options={{
|
|
186
|
+
accessToken: { MAPBOX_ACCESS_TOKEN },
|
|
187
|
+
style: 'mapbox://styles/mapbox/light-v10',
|
|
188
|
+
}}
|
|
189
|
+
viewport={viewport()}
|
|
190
|
+
onViewportChange={evt => setViewport(evt)}>
|
|
191
|
+
<Source
|
|
192
|
+
source={{
|
|
193
|
+
type: 'geojson',
|
|
194
|
+
data: {data}
|
|
195
|
+
}}>
|
|
196
|
+
<Layer style={{
|
|
197
|
+
type: 'line',
|
|
198
|
+
layout: {
|
|
199
|
+
'line-join': 'round',
|
|
200
|
+
'line-cap': 'round',
|
|
201
|
+
}
|
|
202
|
+
paint: {
|
|
203
|
+
'line-color': '#888',
|
|
204
|
+
'line-width': 8,
|
|
205
|
+
}
|
|
206
|
+
}} />
|
|
207
|
+
</Source>
|
|
208
|
+
</MapGL>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Custom Layers support
|
|
212
|
+
|
|
213
|
+
[Custom layers](https://docs.mapbox.com/mapbox-gl-js/api/properties/#customlayerinterface) allow a user to render directly into the Map's GL context using the map's camera.
|
|
214
|
+
|
|
215
|
+
Here is an example using [deck.gl.](https://github.com/uber/deck.gl)
|
|
216
|
+
|
|
217
|
+
```jsx
|
|
218
|
+
import { createSignal } from 'solid-js'
|
|
219
|
+
import MapGL, { Source, Layer } from '../solid-map-gl'
|
|
220
|
+
import { MapboxLayer } from '@deck.gl/mapbox'
|
|
221
|
+
import { ScatterplotLayer } from '@deck.gl/layers'
|
|
222
|
+
|
|
223
|
+
const [viewport, setViewport] = createSignal({
|
|
224
|
+
center: [-74.5, 40],
|
|
225
|
+
zoom: 9,
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
const myDeckLayer = new MapboxLayer({
|
|
229
|
+
id: 'my-scatterplot',
|
|
230
|
+
type: ScatterplotLayer,
|
|
231
|
+
data: [{ position: [-74.5, 40], size: 1000 }],
|
|
232
|
+
getPosition: d => d.position,
|
|
233
|
+
getRadius: d => d.size,
|
|
234
|
+
getColor: [255, 0, 0],
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
<MapGL
|
|
238
|
+
options={{
|
|
239
|
+
accessToken: { MAPBOX_ACCESS_TOKEN },
|
|
240
|
+
style: 'mapbox://styles/mapbox/light-v10',
|
|
241
|
+
}}
|
|
242
|
+
viewport={viewport()}
|
|
243
|
+
onViewportChange={evt => setViewport(evt)}>
|
|
244
|
+
<Layer customLayer={myDeckLayer} />
|
|
245
|
+
</MapGL>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Changelog
|
|
249
|
+
|
|
250
|
+
- 1.0.0 - Initial release
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { template, createComponent, insert, effect, classList } from 'solid-js/web';
|
|
2
|
+
import { useTransition, createContext, onCleanup, onMount, createEffect, useContext, createUniqueId, createSignal } from 'solid-js';
|
|
3
|
+
import mapboxgl from 'mapbox-gl';
|
|
4
|
+
|
|
5
|
+
const _tmpl$$2 = template(`<main></main>`, 2);
|
|
6
|
+
const [pending, start] = useTransition();
|
|
7
|
+
const MapContext = createContext();
|
|
8
|
+
|
|
9
|
+
const useMap = () => useContext(MapContext);
|
|
10
|
+
|
|
11
|
+
const MapGL = props => {
|
|
12
|
+
let map;
|
|
13
|
+
let mapRef;
|
|
14
|
+
onCleanup(() => map.remove());
|
|
15
|
+
onMount(() => {
|
|
16
|
+
map = new mapboxgl.Map({ ...props.options,
|
|
17
|
+
container: mapRef,
|
|
18
|
+
bounds: props.viewport.bounds,
|
|
19
|
+
center: props.viewport.center,
|
|
20
|
+
zoom: props.viewport.zoom || null,
|
|
21
|
+
pitch: props.viewport.pitch || null,
|
|
22
|
+
bearing: props.viewport.bearing || null,
|
|
23
|
+
fitBoundsOptions: {
|
|
24
|
+
padding: props.viewport.padding
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
createEffect(() => props.onMouseMove && map.on('mousemove', event => props.onMouseMove(event.lngLat)));
|
|
29
|
+
|
|
30
|
+
const _onViewportChange = () => {
|
|
31
|
+
const viewport = {
|
|
32
|
+
center: map.getCenter(),
|
|
33
|
+
zoom: map.getZoom(),
|
|
34
|
+
pitch: map.getPitch(),
|
|
35
|
+
bearing: map.getBearing(),
|
|
36
|
+
padding: props.viewport.padding
|
|
37
|
+
};
|
|
38
|
+
props.onViewportChange(viewport);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
createEffect(() => props.onViewportChange && map.on('dragend', _onViewportChange).on('moveend', _onViewportChange).on('zoomend', _onViewportChange).on('rotateend', _onViewportChange).on('pitchend', _onViewportChange).on('boxzoomend', _onViewportChange));
|
|
42
|
+
createEffect(async () => {
|
|
43
|
+
if (!props.viewport.bounds) return; // await map.once('idle')
|
|
44
|
+
|
|
45
|
+
map.fitBounds(props.viewport.bounds, {
|
|
46
|
+
padding: props.viewport.padding
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
let index = 0;
|
|
50
|
+
createEffect(() => {
|
|
51
|
+
if (props.triggerResize) {
|
|
52
|
+
index = 0;
|
|
53
|
+
window.requestAnimationFrame(function loop() {
|
|
54
|
+
if (index < 15) {
|
|
55
|
+
index++;
|
|
56
|
+
window.requestAnimationFrame(loop);
|
|
57
|
+
start(() => map.resize());
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return createComponent(MapContext.Provider, {
|
|
63
|
+
value: () => map,
|
|
64
|
+
|
|
65
|
+
get children() {
|
|
66
|
+
const _el$ = _tmpl$$2.cloneNode(true);
|
|
67
|
+
|
|
68
|
+
const _ref$ = mapRef;
|
|
69
|
+
typeof _ref$ === "function" ? _ref$(_el$) : mapRef = _el$;
|
|
70
|
+
|
|
71
|
+
_el$.style.setProperty("height", "100%");
|
|
72
|
+
|
|
73
|
+
_el$.style.setProperty("width", "100%");
|
|
74
|
+
|
|
75
|
+
insert(_el$, () => props.children);
|
|
76
|
+
|
|
77
|
+
effect(_p$ => {
|
|
78
|
+
const _v$ = props.class || '',
|
|
79
|
+
_v$2 = props.classList;
|
|
80
|
+
|
|
81
|
+
_v$ !== _p$._v$ && (_el$.className = _p$._v$ = _v$);
|
|
82
|
+
_p$._v$2 = classList(_el$, _v$2, _p$._v$2);
|
|
83
|
+
return _p$;
|
|
84
|
+
}, {
|
|
85
|
+
_v$: undefined,
|
|
86
|
+
_v$2: undefined
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return _el$;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const SourceContext = createContext();
|
|
96
|
+
|
|
97
|
+
const useSource = () => useContext(SourceContext);
|
|
98
|
+
|
|
99
|
+
const SourceComponent = props => {
|
|
100
|
+
const map = useMap();
|
|
101
|
+
props.id = props.id || createUniqueId(); // Add Source
|
|
102
|
+
|
|
103
|
+
onMount(async () => {
|
|
104
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
105
|
+
!map().getSource(props.id) && map().addSource(props.id, props.source);
|
|
106
|
+
}); // Remove Source
|
|
107
|
+
|
|
108
|
+
onCleanup(() => {
|
|
109
|
+
map().getStyle().layers.forEach(layer => layer.source === props.id && map().removeLayer(layer.id));
|
|
110
|
+
map().getSource(props.id) && map().removeSource(props.id);
|
|
111
|
+
}); // Update GeoJSON Data
|
|
112
|
+
|
|
113
|
+
createEffect(async () => {
|
|
114
|
+
if (props.source.type !== 'geojson' && !props.source.data) return;
|
|
115
|
+
map().getSource(props.id) && map().getSource(props.id).setData(props.source.data);
|
|
116
|
+
});
|
|
117
|
+
return createComponent(SourceContext.Provider, {
|
|
118
|
+
get value() {
|
|
119
|
+
return {
|
|
120
|
+
source: props.id
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
get children() {
|
|
125
|
+
return props.children;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const diff = (newProps = {}, prevProps = {}) => {
|
|
132
|
+
const keys = new Set([...Object.keys(newProps), ...Object.keys(prevProps)]);
|
|
133
|
+
return [...keys].reduce((acc, key) => {
|
|
134
|
+
const value = newProps[key];
|
|
135
|
+
|
|
136
|
+
if (value !== prevProps[key]) {
|
|
137
|
+
acc.push([key, value]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return acc;
|
|
141
|
+
}, []);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const Layer = props => {
|
|
145
|
+
const map = useMap();
|
|
146
|
+
const source = useSource();
|
|
147
|
+
props.id = props.id || createUniqueId(); // Add Layer
|
|
148
|
+
|
|
149
|
+
onMount(async () => {
|
|
150
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
151
|
+
if (map().getLayer(props.id)) return;
|
|
152
|
+
map().addLayer(props.layer || { ...props.style,
|
|
153
|
+
id: props.id,
|
|
154
|
+
source: source.source
|
|
155
|
+
}, props.beforeType ? map().getStyle().layers.find(l => l.type === props.beforeType).id : props.beforeId);
|
|
156
|
+
}); // Update Style
|
|
157
|
+
|
|
158
|
+
createEffect(prev => {
|
|
159
|
+
if (!props.style && map().getLayer(props.id)) return;
|
|
160
|
+
diff(props.style.paint, prev.paint).forEach(([key, value]) => map().setPaintProperty(props.id, key, value));
|
|
161
|
+
diff(props.style.layout, prev.layout).forEach(([key, value]) => map().setLayoutProperty(props.id, key, value));
|
|
162
|
+
if (props.style.minzoom !== prev.minzoom || props.style.maxzoom !== prev.max) map().setLayerZoomRange(props.id, props.style.minzoom, props.style.maxzoom);
|
|
163
|
+
return props.style;
|
|
164
|
+
}, props.style); // Update Visibility
|
|
165
|
+
|
|
166
|
+
createEffect(async () => {
|
|
167
|
+
if (!props.visible) return;
|
|
168
|
+
!map().loaded() && (await map().once('styledata'));
|
|
169
|
+
map().setLayoutProperty(props.id, 'visibility', props.visible ? 'visible' : 'none', {
|
|
170
|
+
validate: false
|
|
171
|
+
});
|
|
172
|
+
}); // Update Filter
|
|
173
|
+
|
|
174
|
+
createEffect(async () => {
|
|
175
|
+
if (!props.filter) return;
|
|
176
|
+
!map().loaded() && (await map().once('styledata'));
|
|
177
|
+
map().setFilter(props.id, props.filter);
|
|
178
|
+
}); // Update Feature State
|
|
179
|
+
|
|
180
|
+
createEffect(async () => {
|
|
181
|
+
if (!props.featureState?.id) return;
|
|
182
|
+
map().loaded() ? null : await map().once('render');
|
|
183
|
+
map().removeFeatureState({
|
|
184
|
+
source: source.source,
|
|
185
|
+
sourceLayer: props.style['source-layer']
|
|
186
|
+
});
|
|
187
|
+
map().setFeatureState({
|
|
188
|
+
source: source.source,
|
|
189
|
+
sourceLayer: props.style['source-layer'],
|
|
190
|
+
id: props.featureState.id
|
|
191
|
+
}, props.featureState.state);
|
|
192
|
+
});
|
|
193
|
+
return props.children;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const Fog = props => {
|
|
197
|
+
const map = useMap(); // Add Fog Layer
|
|
198
|
+
|
|
199
|
+
onMount(async () => {
|
|
200
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
201
|
+
map().setFog(props.style);
|
|
202
|
+
}); // Remove Fog Layer
|
|
203
|
+
|
|
204
|
+
onCleanup(() => map().setFog(null)); // Update Visibility
|
|
205
|
+
|
|
206
|
+
createEffect(async () => {
|
|
207
|
+
if (props.visible === undefined) return;
|
|
208
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
209
|
+
map().setFog(props.visible ? props.style : null);
|
|
210
|
+
});
|
|
211
|
+
return props.children;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const Sky = props => {
|
|
215
|
+
const map = useMap();
|
|
216
|
+
const layerId = '_sky'; // Add Sky Layer
|
|
217
|
+
|
|
218
|
+
onMount(async () => {
|
|
219
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
220
|
+
!map().getLayer(layerId) && map().addLayer({ ...props.style,
|
|
221
|
+
id: layerId
|
|
222
|
+
});
|
|
223
|
+
}); // Remove Sky Layer
|
|
224
|
+
|
|
225
|
+
onCleanup(() => map().getLayer(layerId) && map().removeLayer(layerId)); // Update Visibility
|
|
226
|
+
|
|
227
|
+
createEffect(async () => {
|
|
228
|
+
if (props.visible === undefined) return;
|
|
229
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
230
|
+
map().setLayoutProperty(layerId, 'visibility', props.visible ? 'visible' : 'none');
|
|
231
|
+
});
|
|
232
|
+
return props.children;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const Terrain = props => {
|
|
236
|
+
const map = useMap();
|
|
237
|
+
const source = useSource(); // Add Terrain Layer
|
|
238
|
+
|
|
239
|
+
onMount(async () => {
|
|
240
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
241
|
+
map().setTerrain({ ...props.style,
|
|
242
|
+
source: source.source
|
|
243
|
+
});
|
|
244
|
+
}); // Remove Terrain Layer
|
|
245
|
+
|
|
246
|
+
onCleanup(() => map().setTerrain(null)); // Update Visibility
|
|
247
|
+
|
|
248
|
+
createEffect(async () => {
|
|
249
|
+
if (props.visible === undefined) return;
|
|
250
|
+
!map().isStyleLoaded() && (await map().once('styledata'));
|
|
251
|
+
map().setTerrain(props.visible ? props.style : null);
|
|
252
|
+
});
|
|
253
|
+
return props.children;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const Control = props => {
|
|
257
|
+
const map = useMap();
|
|
258
|
+
const [control, setControl] = createSignal(null); // Add Control
|
|
259
|
+
|
|
260
|
+
onMount(async () => {
|
|
261
|
+
let control;
|
|
262
|
+
|
|
263
|
+
switch (props.type) {
|
|
264
|
+
case 'scale':
|
|
265
|
+
control = new mapboxgl.ScaleControl(props.options);
|
|
266
|
+
break;
|
|
267
|
+
|
|
268
|
+
case 'attribution':
|
|
269
|
+
control = new mapboxgl.AttributionControl(props.options);
|
|
270
|
+
break;
|
|
271
|
+
|
|
272
|
+
case 'fullscreen':
|
|
273
|
+
control = new mapboxgl.FullscreenControl(props.options);
|
|
274
|
+
break;
|
|
275
|
+
|
|
276
|
+
case 'geolocate':
|
|
277
|
+
control = new mapboxgl.GeolocateControl(props.options);
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
default:
|
|
281
|
+
control = new mapboxgl.NavigationControl(props.options);
|
|
282
|
+
// case 'language':
|
|
283
|
+
// const MapboxLanguage = (await import('@mapbox/mapbox-gl-language'))
|
|
284
|
+
// .default
|
|
285
|
+
// control = new MapboxLanguage(props.options)
|
|
286
|
+
// break
|
|
287
|
+
// case 'traffic':
|
|
288
|
+
// const MapboxTraffic = (await import('@mapbox/mapbox-gl-traffic'))
|
|
289
|
+
// .default
|
|
290
|
+
// await import('@mapbox/mapbox-gl-traffic/mapbox-gl-traffic.css')
|
|
291
|
+
// control = new MapboxTraffic(props.options)
|
|
292
|
+
// break
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
map().addControl(control, props.position);
|
|
296
|
+
setControl(control);
|
|
297
|
+
});
|
|
298
|
+
onCleanup(() => map().removeControl(control()));
|
|
299
|
+
return props.children;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const _tmpl$$1 = template(`<div></div>`, 2);
|
|
303
|
+
|
|
304
|
+
const Marker = props => {
|
|
305
|
+
const map = useMap();
|
|
306
|
+
let marker = null; // Add Marker
|
|
307
|
+
|
|
308
|
+
onMount(async () => {
|
|
309
|
+
marker = new mapboxgl.Marker(props.options).setLngLat(props.lnglat).setPopup(props.children ? new mapboxgl.Popup().setDOMContent((() => {
|
|
310
|
+
const _el$ = _tmpl$$1.cloneNode(true);
|
|
311
|
+
|
|
312
|
+
insert(_el$, () => props.children);
|
|
313
|
+
|
|
314
|
+
return _el$;
|
|
315
|
+
})()) : null).addTo(map());
|
|
316
|
+
}); // Remove Marker
|
|
317
|
+
|
|
318
|
+
onCleanup(() => marker.remove()); // Update Position
|
|
319
|
+
|
|
320
|
+
createEffect(() => marker.setLngLat(props.lnglat));
|
|
321
|
+
return [];
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const _tmpl$ = template(`<div></div>`, 2);
|
|
325
|
+
|
|
326
|
+
const Popup = props => {
|
|
327
|
+
const map = useMap();
|
|
328
|
+
let popup = null; // Add Popup
|
|
329
|
+
|
|
330
|
+
onMount(async () => {
|
|
331
|
+
popup = new mapboxgl.Popup(props.options).setLngLat(props.lnglat).setDOMContent((() => {
|
|
332
|
+
const _el$ = _tmpl$.cloneNode(true);
|
|
333
|
+
|
|
334
|
+
insert(_el$, () => props.children);
|
|
335
|
+
|
|
336
|
+
return _el$;
|
|
337
|
+
})()).addTo(map());
|
|
338
|
+
}); // Remove Popup
|
|
339
|
+
|
|
340
|
+
onCleanup(() => popup.remove()); // Update Position
|
|
341
|
+
|
|
342
|
+
createEffect(() => popup.setLngLat(props.lnglat)); // Update Content
|
|
343
|
+
|
|
344
|
+
createEffect(() => popup.setDOMContent((() => {
|
|
345
|
+
const _el$2 = _tmpl$.cloneNode(true);
|
|
346
|
+
|
|
347
|
+
insert(_el$2, () => props.children);
|
|
348
|
+
|
|
349
|
+
return _el$2;
|
|
350
|
+
})()));
|
|
351
|
+
return [];
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const Image = props => {
|
|
355
|
+
const map = useMap(); // Add Image
|
|
356
|
+
|
|
357
|
+
onMount(() => {
|
|
358
|
+
if (props.url) {
|
|
359
|
+
map().loadImage(props.url, (error, image) => {
|
|
360
|
+
if (error) throw error;
|
|
361
|
+
!map().hasImage(props.id) && map().addImage(props.id, image);
|
|
362
|
+
});
|
|
363
|
+
} else {
|
|
364
|
+
!map().hasImage(props.id) && map().addImage(props.id, props.image, props.options);
|
|
365
|
+
}
|
|
366
|
+
}); // Remove Image
|
|
367
|
+
|
|
368
|
+
onCleanup(() => map().hasImage(props.id) && map().removeImage(props.id)); // Update Image
|
|
369
|
+
|
|
370
|
+
createEffect(async () => {
|
|
371
|
+
if (props.image && props.url) return;
|
|
372
|
+
|
|
373
|
+
if (props.url) {
|
|
374
|
+
map().loadImage(props.url, (error, image) => {
|
|
375
|
+
if (error) throw error;
|
|
376
|
+
!map().hasImage(props.id) && map().updateImage(props.id, image);
|
|
377
|
+
});
|
|
378
|
+
} else {
|
|
379
|
+
map().hasImage(props.id) && map().updateImage(props.id, props.image);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
return [];
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
export { Control, Fog, Image, Layer, Marker, Popup, Sky, SourceComponent as Source, Terrain, MapGL as default };
|
|
386
|
+
//# sourceMappingURL=index.js.map
|