@smartnet360/svelte-components 0.0.54 → 0.0.55
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/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/map-v2/core/controls/MapStyleControl.svelte +289 -0
- package/dist/map-v2/core/controls/MapStyleControl.svelte.d.ts +24 -0
- package/dist/{map → map-v2/core}/hooks/useMapbox.d.ts +1 -1
- package/dist/{map → map-v2/core}/hooks/useMapbox.js +1 -1
- package/dist/map-v2/core/index.d.ts +11 -0
- package/dist/map-v2/core/index.js +14 -0
- package/dist/map-v2/core/providers/MapboxProvider.svelte +140 -0
- package/dist/map-v2/core/providers/MapboxProvider.svelte.d.ts +33 -0
- package/dist/{map → map-v2/core}/stores/mapStore.d.ts +2 -2
- package/dist/{map → map-v2/core}/stores/mapStore.js +2 -2
- package/dist/map-v2/core/types.d.ts +13 -0
- package/dist/map-v2/core/types.js +7 -0
- package/dist/map-v2/demo/DemoMap.svelte +63 -0
- package/dist/{map → map-v2}/demo/DemoMap.svelte.d.ts +3 -4
- package/dist/map-v2/demo/demo-data.d.ts +8 -0
- package/dist/map-v2/demo/demo-data.js +128 -0
- package/dist/map-v2/demo/index.d.ts +7 -0
- package/dist/map-v2/demo/index.js +9 -0
- package/dist/{map → map-v2/features/sites}/controls/SiteFilterControl.svelte +26 -40
- package/dist/{map → map-v2/features/sites}/controls/SiteFilterControl.svelte.d.ts +4 -6
- package/dist/map-v2/features/sites/controls/SiteSizeSlider.svelte +185 -0
- package/dist/map-v2/features/sites/controls/SiteSizeSlider.svelte.d.ts +20 -0
- package/dist/map-v2/features/sites/index.d.ts +14 -0
- package/dist/map-v2/features/sites/index.js +16 -0
- package/dist/map-v2/features/sites/layers/SitesLayer.svelte +277 -0
- package/dist/map-v2/features/sites/layers/SitesLayer.svelte.d.ts +12 -0
- package/dist/map-v2/features/sites/stores/siteStore.d.ts +18 -0
- package/dist/map-v2/features/sites/stores/siteStore.js +36 -0
- package/dist/map-v2/features/sites/stores/siteStoreContext.svelte.d.ts +29 -0
- package/dist/map-v2/features/sites/stores/siteStoreContext.svelte.js +73 -0
- package/dist/map-v2/features/sites/types.d.ts +36 -0
- package/dist/map-v2/features/sites/types.js +4 -0
- package/dist/map-v2/features/sites/utils/siteGeoJSON.d.ts +31 -0
- package/dist/map-v2/features/sites/utils/siteGeoJSON.js +34 -0
- package/dist/map-v2/features/sites/utils/siteTreeUtils.d.ts +14 -0
- package/dist/{map → map-v2/features/sites}/utils/siteTreeUtils.js +3 -50
- package/dist/map-v2/index.d.ts +10 -0
- package/dist/map-v2/index.js +22 -0
- package/dist/{map → map-v2/shared}/controls/MapControl.svelte +1 -1
- package/dist/map-v2/shared/index.d.ts +7 -0
- package/dist/map-v2/shared/index.js +9 -0
- package/package.json +1 -1
- package/dist/map/demo/DemoMap.svelte +0 -98
- package/dist/map/demo/demo-data.d.ts +0 -12
- package/dist/map/demo/demo-data.js +0 -220
- package/dist/map/hooks/useCellData.d.ts +0 -14
- package/dist/map/hooks/useCellData.js +0 -29
- package/dist/map/index.d.ts +0 -27
- package/dist/map/index.js +0 -47
- package/dist/map/layers/CellsLayer.svelte +0 -242
- package/dist/map/layers/CellsLayer.svelte.d.ts +0 -21
- package/dist/map/layers/CoverageLayer.svelte +0 -37
- package/dist/map/layers/CoverageLayer.svelte.d.ts +0 -9
- package/dist/map/layers/LayerBase.d.ts +0 -42
- package/dist/map/layers/LayerBase.js +0 -58
- package/dist/map/layers/SitesLayer.svelte +0 -282
- package/dist/map/layers/SitesLayer.svelte.d.ts +0 -19
- package/dist/map/providers/CellDataProvider.svelte +0 -43
- package/dist/map/providers/CellDataProvider.svelte.d.ts +0 -12
- package/dist/map/providers/MapboxProvider.svelte +0 -38
- package/dist/map/providers/MapboxProvider.svelte.d.ts +0 -9
- package/dist/map/providers/providerHelpers.d.ts +0 -17
- package/dist/map/providers/providerHelpers.js +0 -26
- package/dist/map/stores/cellDataStore.d.ts +0 -21
- package/dist/map/stores/cellDataStore.js +0 -53
- package/dist/map/stores/interactions.d.ts +0 -20
- package/dist/map/stores/interactions.js +0 -33
- package/dist/map/types.d.ts +0 -115
- package/dist/map/types.js +0 -10
- package/dist/map/utils/geojson.d.ts +0 -20
- package/dist/map/utils/geojson.js +0 -78
- package/dist/map/utils/math.d.ts +0 -40
- package/dist/map/utils/math.js +0 -95
- package/dist/map/utils/siteTreeUtils.d.ts +0 -27
- /package/dist/{map → map-v2/shared}/controls/MapControl.svelte.d.ts +0 -0
- /package/dist/{map → map-v2/shared}/utils/mapboxHelpers.d.ts +0 -0
- /package/dist/{map → map-v2/shared}/utils/mapboxHelpers.js +0 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// This approach keeps the main index clean and allows for easy expansion
|
|
3
3
|
// Core components (Desktop orchestration + Charts + TreeView)
|
|
4
4
|
export * from './core/index.js';
|
|
5
|
-
// Map components (Mapbox cellular visualization)
|
|
6
|
-
export * from './map/index.js';
|
|
5
|
+
// Map components (Mapbox cellular visualization - v2)
|
|
6
|
+
export * from './map-v2/index.js';
|
|
7
7
|
// Complete applications
|
|
8
8
|
export * from './apps/index.js';
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* MapStyleControl - Control for switching map styles
|
|
4
|
+
*
|
|
5
|
+
* Self-contained control that displays available map styles and allows switching.
|
|
6
|
+
* Persists selection to localStorage.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* <MapStyleControl position="top-right" namespace="my-app" />
|
|
10
|
+
*/
|
|
11
|
+
import { onMount } from 'svelte';
|
|
12
|
+
import type mapboxgl from 'mapbox-gl';
|
|
13
|
+
import MapControl from '../../shared/controls/MapControl.svelte';
|
|
14
|
+
import { useMapbox } from '../hooks/useMapbox';
|
|
15
|
+
|
|
16
|
+
interface MapStyle {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
url: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
icon?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const DEFAULT_STYLES: MapStyle[] = [
|
|
25
|
+
{
|
|
26
|
+
id: 'streets',
|
|
27
|
+
name: 'Streets',
|
|
28
|
+
url: 'mapbox://styles/mapbox/streets-v12',
|
|
29
|
+
description: 'General purpose street map',
|
|
30
|
+
icon: 'map'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'outdoors',
|
|
34
|
+
name: 'Outdoors',
|
|
35
|
+
url: 'mapbox://styles/mapbox/outdoors-v12',
|
|
36
|
+
description: 'Hiking, biking, and terrain',
|
|
37
|
+
icon: 'tree'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'light',
|
|
41
|
+
name: 'Light',
|
|
42
|
+
url: 'mapbox://styles/mapbox/light-v11',
|
|
43
|
+
description: 'Minimal light background',
|
|
44
|
+
icon: 'sun'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'dark',
|
|
48
|
+
name: 'Dark',
|
|
49
|
+
url: 'mapbox://styles/mapbox/dark-v11',
|
|
50
|
+
description: 'Minimal dark background',
|
|
51
|
+
icon: 'moon-stars'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'satellite',
|
|
55
|
+
name: 'Satellite',
|
|
56
|
+
url: 'mapbox://styles/mapbox/satellite-v9',
|
|
57
|
+
description: 'Satellite imagery',
|
|
58
|
+
icon: 'globe'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'satellite-streets',
|
|
62
|
+
name: 'Satellite Streets',
|
|
63
|
+
url: 'mapbox://styles/mapbox/satellite-streets-v12',
|
|
64
|
+
description: 'Satellite with street overlay',
|
|
65
|
+
icon: 'globe-americas'
|
|
66
|
+
},
|
|
67
|
+
// {
|
|
68
|
+
// id: 'navigation-day',
|
|
69
|
+
// name: 'Navigation Day',
|
|
70
|
+
// url: 'mapbox://styles/mapbox/navigation-day-v1',
|
|
71
|
+
// description: 'Optimized for navigation',
|
|
72
|
+
// icon: 'compass'
|
|
73
|
+
// },
|
|
74
|
+
// {
|
|
75
|
+
// id: 'navigation-night',
|
|
76
|
+
// name: 'Navigation Night',
|
|
77
|
+
// url: 'mapbox://styles/mapbox/navigation-night-v1',
|
|
78
|
+
// description: 'Night mode navigation',
|
|
79
|
+
// icon: 'moon'
|
|
80
|
+
// }
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
interface Props {
|
|
84
|
+
/** Control position on map */
|
|
85
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
86
|
+
/** Control title */
|
|
87
|
+
title?: string;
|
|
88
|
+
/** Initially collapsed? */
|
|
89
|
+
initiallyCollapsed?: boolean;
|
|
90
|
+
/** Storage namespace for persistence */
|
|
91
|
+
namespace?: string;
|
|
92
|
+
/** Custom available styles (default: built-in Mapbox styles) */
|
|
93
|
+
availableStyles?: MapStyle[];
|
|
94
|
+
/** Default style ID */
|
|
95
|
+
defaultStyleId?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let {
|
|
99
|
+
position = 'top-right',
|
|
100
|
+
title = 'Map Style',
|
|
101
|
+
initiallyCollapsed = false,
|
|
102
|
+
namespace = 'map',
|
|
103
|
+
availableStyles = DEFAULT_STYLES,
|
|
104
|
+
defaultStyleId = 'streets'
|
|
105
|
+
}: Props = $props();
|
|
106
|
+
|
|
107
|
+
const mapStore = useMapbox();
|
|
108
|
+
let map: mapboxgl.Map | null = null;
|
|
109
|
+
const storageKey = `${namespace}:mapStyle`;
|
|
110
|
+
|
|
111
|
+
// Load persisted style or use default
|
|
112
|
+
const loadPersistedStyle = (): MapStyle => {
|
|
113
|
+
if (typeof window === 'undefined') {
|
|
114
|
+
return availableStyles.find(s => s.id === defaultStyleId) || availableStyles[0];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const stored = localStorage.getItem(storageKey);
|
|
119
|
+
if (stored) {
|
|
120
|
+
const styleId = JSON.parse(stored);
|
|
121
|
+
const style = availableStyles.find(s => s.id === styleId);
|
|
122
|
+
if (style) return style;
|
|
123
|
+
}
|
|
124
|
+
} catch (e) {
|
|
125
|
+
console.warn('Failed to load persisted map style:', e);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return availableStyles.find(s => s.id === defaultStyleId) || availableStyles[0];
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
let currentStyle = $state<MapStyle>(loadPersistedStyle());
|
|
132
|
+
|
|
133
|
+
onMount(() => {
|
|
134
|
+
const unsub = mapStore.subscribe((m: mapboxgl.Map | null) => {
|
|
135
|
+
if (!m) return;
|
|
136
|
+
map = m;
|
|
137
|
+
|
|
138
|
+
// Apply persisted style when map becomes available if it differs
|
|
139
|
+
// Check if current map style URL matches our persisted style
|
|
140
|
+
if (currentStyle) {
|
|
141
|
+
const mapStyle = map.getStyle();
|
|
142
|
+
// Compare the style URL/source, not the name
|
|
143
|
+
// mapStyle.sprite contains the base URL we can check against
|
|
144
|
+
const currentMapStyleUrl = mapStyle?.sprite || '';
|
|
145
|
+
const needsStyleChange = !currentMapStyleUrl.includes(currentStyle.id);
|
|
146
|
+
|
|
147
|
+
if (needsStyleChange) {
|
|
148
|
+
console.log('Applying persisted style:', currentStyle.id);
|
|
149
|
+
map.setStyle(currentStyle.url);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return unsub;
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
function handleStyleChange(styleId: string): void {
|
|
157
|
+
const style = availableStyles.find(s => s.id === styleId);
|
|
158
|
+
if (!style) {
|
|
159
|
+
console.warn(`Style with id "${styleId}" not found`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Update local state
|
|
164
|
+
currentStyle = style;
|
|
165
|
+
|
|
166
|
+
// Persist to localStorage
|
|
167
|
+
if (typeof window !== 'undefined') {
|
|
168
|
+
try {
|
|
169
|
+
localStorage.setItem(storageKey, JSON.stringify(styleId));
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.warn('Failed to persist map style:', e);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Update map directly
|
|
176
|
+
if (map) {
|
|
177
|
+
map.setStyle(style.url);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
</script>
|
|
181
|
+
|
|
182
|
+
<MapControl {position} {title} collapsible={true} {initiallyCollapsed}>
|
|
183
|
+
<div class="map-style-controls">
|
|
184
|
+
<div class="style-grid">
|
|
185
|
+
{#each availableStyles as style (style.id)}
|
|
186
|
+
<button
|
|
187
|
+
class="style-option"
|
|
188
|
+
class:active={currentStyle.id === style.id}
|
|
189
|
+
onclick={() => handleStyleChange(style.id)}
|
|
190
|
+
title={style.description}
|
|
191
|
+
>
|
|
192
|
+
<i class="bi bi-{style.icon || 'map'}"></i>
|
|
193
|
+
<!-- {#if currentStyle.id === style.id}
|
|
194
|
+
<div class="style-checkmark">
|
|
195
|
+
<i class="bi bi-check-circle-fill"></i>
|
|
196
|
+
</div>
|
|
197
|
+
{/if} -->
|
|
198
|
+
</button>
|
|
199
|
+
{/each}
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{#if currentStyle.description}
|
|
203
|
+
<div class="current-style-info">
|
|
204
|
+
<small class="text-muted">
|
|
205
|
+
<i class="bi bi-info-circle"></i>
|
|
206
|
+
{currentStyle.description}
|
|
207
|
+
</small>
|
|
208
|
+
</div>
|
|
209
|
+
{/if}
|
|
210
|
+
</div>
|
|
211
|
+
</MapControl>
|
|
212
|
+
|
|
213
|
+
<style>
|
|
214
|
+
.map-style-controls {
|
|
215
|
+
min-width: 240px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.style-grid {
|
|
219
|
+
display: grid;
|
|
220
|
+
grid-template-columns: repeat(2, 1fr);
|
|
221
|
+
gap: 4px;
|
|
222
|
+
margin-bottom: 8px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.style-option {
|
|
226
|
+
position: relative;
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
padding: 8px;
|
|
231
|
+
border: 2px solid #ddd;
|
|
232
|
+
border-radius: 6px;
|
|
233
|
+
background: white;
|
|
234
|
+
cursor: pointer;
|
|
235
|
+
transition: all 0.2s;
|
|
236
|
+
font-size: 24px;
|
|
237
|
+
color: #6c757d;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.style-option:hover {
|
|
241
|
+
border-color: #0d6efd;
|
|
242
|
+
box-shadow: 0 2px 8px rgba(13, 110, 253, 0.2);
|
|
243
|
+
transform: translateY(-1px);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.style-option.active {
|
|
247
|
+
border-color: #0d6efd;
|
|
248
|
+
background: #e7f1ff;
|
|
249
|
+
color: #0d6efd;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.style-name {
|
|
253
|
+
font-size: 12px;
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
text-align: center;
|
|
256
|
+
color: #333;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.style-option.active .style-name {
|
|
260
|
+
color: #0d6efd;
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.style-checkmark {
|
|
265
|
+
position: absolute;
|
|
266
|
+
top: 4px;
|
|
267
|
+
right: 4px;
|
|
268
|
+
color: #0d6efd;
|
|
269
|
+
font-size: 18px;
|
|
270
|
+
background: white;
|
|
271
|
+
border-radius: 50%;
|
|
272
|
+
line-height: 1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.current-style-info {
|
|
276
|
+
padding: 8px;
|
|
277
|
+
background: #f8f9fa;
|
|
278
|
+
border-radius: 4px;
|
|
279
|
+
text-align: center;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.current-style-info small {
|
|
283
|
+
display: flex;
|
|
284
|
+
align-items: center;
|
|
285
|
+
justify-content: center;
|
|
286
|
+
gap: 4px;
|
|
287
|
+
font-size: 11px;
|
|
288
|
+
}
|
|
289
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface MapStyle {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
url: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
}
|
|
8
|
+
interface Props {
|
|
9
|
+
/** Control position on map */
|
|
10
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
11
|
+
/** Control title */
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Initially collapsed? */
|
|
14
|
+
initiallyCollapsed?: boolean;
|
|
15
|
+
/** Storage namespace for persistence */
|
|
16
|
+
namespace?: string;
|
|
17
|
+
/** Custom available styles (default: built-in Mapbox styles) */
|
|
18
|
+
availableStyles?: MapStyle[];
|
|
19
|
+
/** Default style ID */
|
|
20
|
+
defaultStyleId?: string;
|
|
21
|
+
}
|
|
22
|
+
declare const MapStyleControl: import("svelte").Component<Props, {}, "">;
|
|
23
|
+
type MapStyleControl = ReturnType<typeof MapStyleControl>;
|
|
24
|
+
export default MapStyleControl;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Infrastructure - Public API
|
|
3
|
+
*
|
|
4
|
+
* Exports core map types, providers, stores, and hooks
|
|
5
|
+
*/
|
|
6
|
+
export type { MapStore } from './types';
|
|
7
|
+
export { MAP_CONTEXT_KEY } from './types';
|
|
8
|
+
export { default as MapboxProvider } from './providers/MapboxProvider.svelte';
|
|
9
|
+
export { default as MapStyleControl } from './controls/MapStyleControl.svelte';
|
|
10
|
+
export { createMapStore } from './stores/mapStore';
|
|
11
|
+
export { useMapbox, tryUseMapbox } from './hooks/useMapbox';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Infrastructure - Public API
|
|
3
|
+
*
|
|
4
|
+
* Exports core map types, providers, stores, and hooks
|
|
5
|
+
*/
|
|
6
|
+
export { MAP_CONTEXT_KEY } from './types';
|
|
7
|
+
// Providers
|
|
8
|
+
export { default as MapboxProvider } from './providers/MapboxProvider.svelte';
|
|
9
|
+
// Controls
|
|
10
|
+
export { default as MapStyleControl } from './controls/MapStyleControl.svelte';
|
|
11
|
+
// Stores
|
|
12
|
+
export { createMapStore } from './stores/mapStore';
|
|
13
|
+
// Hooks
|
|
14
|
+
export { useMapbox, tryUseMapbox } from './hooks/useMapbox';
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* MapboxProvider - Initializes and provides Mapbox GL JS map instance to child components
|
|
4
|
+
*
|
|
5
|
+
* Handles complete map lifecycle:
|
|
6
|
+
* - Map initialization with configuration
|
|
7
|
+
* - Style loading
|
|
8
|
+
* - Optional built-in controls (navigation, scale, etc.)
|
|
9
|
+
* - Context distribution to child components
|
|
10
|
+
* - Cleanup on unmount
|
|
11
|
+
*/
|
|
12
|
+
import { setContext, onMount, onDestroy } from 'svelte';
|
|
13
|
+
import mapboxgl, { type Map as MapboxMap, type StyleSpecification } from 'mapbox-gl';
|
|
14
|
+
import { MAP_CONTEXT_KEY } from '../types';
|
|
15
|
+
import { createMapStore } from '../stores/mapStore';
|
|
16
|
+
import 'mapbox-gl/dist/mapbox-gl.css';
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
/** Mapbox access token */
|
|
20
|
+
accessToken: string;
|
|
21
|
+
/** Map style URL or style object (default: streets-v12) */
|
|
22
|
+
style?: string | StyleSpecification;
|
|
23
|
+
/** Initial map center [lng, lat] */
|
|
24
|
+
center?: [number, number];
|
|
25
|
+
/** Initial zoom level */
|
|
26
|
+
zoom?: number;
|
|
27
|
+
/** Initial bearing (rotation) */
|
|
28
|
+
bearing?: number;
|
|
29
|
+
/** Initial pitch (tilt) */
|
|
30
|
+
pitch?: number;
|
|
31
|
+
/** Minimum zoom level */
|
|
32
|
+
minZoom?: number;
|
|
33
|
+
/** Maximum zoom level */
|
|
34
|
+
maxZoom?: number;
|
|
35
|
+
/** Built-in controls to add */
|
|
36
|
+
controls?: Array<'navigation' | 'scale' | 'fullscreen' | 'geolocate'>;
|
|
37
|
+
/** Position for navigation control */
|
|
38
|
+
navigationPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
39
|
+
/** Position for scale control */
|
|
40
|
+
scalePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
41
|
+
/** Custom CSS class for container */
|
|
42
|
+
class?: string;
|
|
43
|
+
/** Optional child content (layers, controls, etc.) */
|
|
44
|
+
children?: import('svelte').Snippet;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let {
|
|
48
|
+
accessToken,
|
|
49
|
+
style = 'mapbox://styles/mapbox/streets-v12',
|
|
50
|
+
center = [0, 0],
|
|
51
|
+
zoom = 2,
|
|
52
|
+
bearing = 0,
|
|
53
|
+
pitch = 0,
|
|
54
|
+
minZoom,
|
|
55
|
+
maxZoom,
|
|
56
|
+
controls = [],
|
|
57
|
+
navigationPosition = 'top-right',
|
|
58
|
+
scalePosition = 'bottom-left',
|
|
59
|
+
class: className = '',
|
|
60
|
+
children
|
|
61
|
+
}: Props = $props();
|
|
62
|
+
|
|
63
|
+
// Create and set the map store in context
|
|
64
|
+
const mapStore = createMapStore();
|
|
65
|
+
setContext(MAP_CONTEXT_KEY, mapStore);
|
|
66
|
+
|
|
67
|
+
let mapContainer: HTMLDivElement;
|
|
68
|
+
let map: MapboxMap | null = null;
|
|
69
|
+
|
|
70
|
+
onMount(() => {
|
|
71
|
+
// Set access token
|
|
72
|
+
mapboxgl.accessToken = accessToken;
|
|
73
|
+
|
|
74
|
+
// Initialize map
|
|
75
|
+
map = new mapboxgl.Map({
|
|
76
|
+
container: mapContainer,
|
|
77
|
+
style,
|
|
78
|
+
center,
|
|
79
|
+
zoom,
|
|
80
|
+
bearing,
|
|
81
|
+
pitch,
|
|
82
|
+
minZoom,
|
|
83
|
+
maxZoom
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Add built-in controls
|
|
87
|
+
if (controls.includes('navigation')) {
|
|
88
|
+
map.addControl(new mapboxgl.NavigationControl(), navigationPosition);
|
|
89
|
+
}
|
|
90
|
+
if (controls.includes('scale')) {
|
|
91
|
+
map.addControl(new mapboxgl.ScaleControl(), scalePosition);
|
|
92
|
+
}
|
|
93
|
+
if (controls.includes('fullscreen')) {
|
|
94
|
+
map.addControl(new mapboxgl.FullscreenControl());
|
|
95
|
+
}
|
|
96
|
+
if (controls.includes('geolocate')) {
|
|
97
|
+
map.addControl(
|
|
98
|
+
new mapboxgl.GeolocateControl({
|
|
99
|
+
positionOptions: {
|
|
100
|
+
enableHighAccuracy: true
|
|
101
|
+
},
|
|
102
|
+
trackUserLocation: true
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Wait for style to load before distributing map
|
|
108
|
+
const onStyleLoad = () => {
|
|
109
|
+
mapStore.set(map);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (map.isStyleLoaded()) {
|
|
113
|
+
mapStore.set(map);
|
|
114
|
+
} else {
|
|
115
|
+
map.once('style.load', onStyleLoad);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
onDestroy(() => {
|
|
120
|
+
if (map) {
|
|
121
|
+
map.remove();
|
|
122
|
+
map = null;
|
|
123
|
+
}
|
|
124
|
+
mapStore.set(null);
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
|
|
128
|
+
<div bind:this={mapContainer} class="mapbox-container {className}"></div>
|
|
129
|
+
|
|
130
|
+
{#if children}
|
|
131
|
+
{@render children()}
|
|
132
|
+
{/if}
|
|
133
|
+
|
|
134
|
+
<style>
|
|
135
|
+
.mapbox-container {
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 100%;
|
|
138
|
+
position: relative;
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type StyleSpecification } from 'mapbox-gl';
|
|
2
|
+
import 'mapbox-gl/dist/mapbox-gl.css';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Mapbox access token */
|
|
5
|
+
accessToken: string;
|
|
6
|
+
/** Map style URL or style object (default: streets-v12) */
|
|
7
|
+
style?: string | StyleSpecification;
|
|
8
|
+
/** Initial map center [lng, lat] */
|
|
9
|
+
center?: [number, number];
|
|
10
|
+
/** Initial zoom level */
|
|
11
|
+
zoom?: number;
|
|
12
|
+
/** Initial bearing (rotation) */
|
|
13
|
+
bearing?: number;
|
|
14
|
+
/** Initial pitch (tilt) */
|
|
15
|
+
pitch?: number;
|
|
16
|
+
/** Minimum zoom level */
|
|
17
|
+
minZoom?: number;
|
|
18
|
+
/** Maximum zoom level */
|
|
19
|
+
maxZoom?: number;
|
|
20
|
+
/** Built-in controls to add */
|
|
21
|
+
controls?: Array<'navigation' | 'scale' | 'fullscreen' | 'geolocate'>;
|
|
22
|
+
/** Position for navigation control */
|
|
23
|
+
navigationPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
24
|
+
/** Position for scale control */
|
|
25
|
+
scalePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
26
|
+
/** Custom CSS class for container */
|
|
27
|
+
class?: string;
|
|
28
|
+
/** Optional child content (layers, controls, etc.) */
|
|
29
|
+
children?: import('svelte').Snippet;
|
|
30
|
+
}
|
|
31
|
+
declare const MapboxProvider: import("svelte").Component<Props, {}, "">;
|
|
32
|
+
type MapboxProvider = ReturnType<typeof MapboxProvider>;
|
|
33
|
+
export default MapboxProvider;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Map store - Writable store for Mapbox map instance
|
|
3
3
|
*/
|
|
4
4
|
import type { MapStore } from '../types';
|
|
5
5
|
/**
|
|
6
|
-
* Creates a writable store for the Mapbox instance
|
|
6
|
+
* Creates a writable store for the Mapbox map instance
|
|
7
7
|
*/
|
|
8
8
|
export declare function createMapStore(): MapStore;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Map store - Writable store for Mapbox map instance
|
|
3
3
|
*/
|
|
4
4
|
import { writable } from 'svelte/store';
|
|
5
5
|
/**
|
|
6
|
-
* Creates a writable store for the Mapbox instance
|
|
6
|
+
* Creates a writable store for the Mapbox map instance
|
|
7
7
|
*/
|
|
8
8
|
export function createMapStore() {
|
|
9
9
|
return writable(null);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core map types
|
|
3
|
+
*/
|
|
4
|
+
import type { Map as MapboxMap } from 'mapbox-gl';
|
|
5
|
+
import type { Writable } from 'svelte/store';
|
|
6
|
+
/**
|
|
7
|
+
* Map store type - writable store containing the Mapbox instance
|
|
8
|
+
*/
|
|
9
|
+
export type MapStore = Writable<MapboxMap | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Context key for MapboxProvider
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAP_CONTEXT_KEY: unique symbol;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* DemoMap - Complete demo of map-v2 site feature
|
|
4
|
+
*
|
|
5
|
+
* Demonstrates:
|
|
6
|
+
* - Simplified MapboxProvider with automatic initialization
|
|
7
|
+
* - Dynamic map style switching with persistence
|
|
8
|
+
* - SitesLayer rendering sites from store
|
|
9
|
+
* - SiteFilterControl for hierarchical filtering
|
|
10
|
+
* - SiteSizeSlider for visual property adjustment
|
|
11
|
+
*/
|
|
12
|
+
import MapboxProvider from '../core/providers/MapboxProvider.svelte';
|
|
13
|
+
import MapStyleControl from '../core/controls/MapStyleControl.svelte';
|
|
14
|
+
import SitesLayer from '../features/sites/layers/SitesLayer.svelte';
|
|
15
|
+
import SiteFilterControl from '../features/sites/controls/SiteFilterControl.svelte';
|
|
16
|
+
import SiteSizeSlider from '../features/sites/controls/SiteSizeSlider.svelte';
|
|
17
|
+
import { createSiteStoreContext } from '../features/sites/stores/siteStoreContext.svelte';
|
|
18
|
+
import { demoSites } from './demo-data';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
/** Mapbox access token */
|
|
22
|
+
accessToken: string;
|
|
23
|
+
/** Initial map center [lng, lat] (default: San Francisco) */
|
|
24
|
+
center?: [number, number];
|
|
25
|
+
/** Initial zoom level (default: 12) */
|
|
26
|
+
zoom?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
accessToken,
|
|
31
|
+
center = [-122.4194, 37.7749],
|
|
32
|
+
zoom = 12
|
|
33
|
+
}: Props = $props();
|
|
34
|
+
|
|
35
|
+
// Create site store with demo data
|
|
36
|
+
const siteStore = createSiteStoreContext(demoSites);
|
|
37
|
+
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<!-- // controls={['navigation', 'scale']} -->
|
|
41
|
+
<div class="demo-map-container">
|
|
42
|
+
<MapboxProvider {accessToken} {center} {zoom}>
|
|
43
|
+
<!-- Site layer - renders circles from store -->
|
|
44
|
+
<SitesLayer store={siteStore} namespace="demo-sites" />
|
|
45
|
+
|
|
46
|
+
<!-- Map style control - switch between map styles -->
|
|
47
|
+
<MapStyleControl position="top-right" initiallyCollapsed={true} namespace="demo-map" />
|
|
48
|
+
|
|
49
|
+
<!-- Site filter control - updates store.filteredSites -->
|
|
50
|
+
<SiteFilterControl store={siteStore} position="top-left" title="Site Filter" />
|
|
51
|
+
|
|
52
|
+
<!-- Site size control - updates store visual properties -->
|
|
53
|
+
<SiteSizeSlider store={siteStore} position="bottom-right" title="Site Display" />
|
|
54
|
+
</MapboxProvider>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<style>
|
|
58
|
+
.demo-map-container {
|
|
59
|
+
position: relative;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import 'mapbox-gl/dist/mapbox-gl.css';
|
|
2
1
|
interface Props {
|
|
3
2
|
/** Mapbox access token */
|
|
4
|
-
accessToken
|
|
5
|
-
/** Initial center
|
|
3
|
+
accessToken: string;
|
|
4
|
+
/** Initial map center [lng, lat] (default: San Francisco) */
|
|
6
5
|
center?: [number, number];
|
|
7
|
-
/** Initial zoom level */
|
|
6
|
+
/** Initial zoom level (default: 12) */
|
|
8
7
|
zoom?: number;
|
|
9
8
|
}
|
|
10
9
|
declare const DemoMap: import("svelte").Component<Props, {}, "">;
|