@smartnet360/svelte-components 0.0.54 → 0.0.56
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-v2/features/sites/controls/SiteFilterControl.svelte +147 -0
- package/dist/{map → map-v2/features/sites}/controls/SiteFilterControl.svelte.d.ts +4 -6
- package/dist/map-v2/features/sites/controls/SiteSizeSlider.svelte +236 -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 +294 -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 +36 -0
- package/dist/map-v2/features/sites/stores/siteStoreContext.svelte.js +155 -0
- package/dist/map-v2/features/sites/types.d.ts +39 -0
- package/dist/map-v2/features/sites/types.js +4 -0
- package/dist/map-v2/features/sites/utils/siteGeoJSON.d.ts +33 -0
- package/dist/map-v2/features/sites/utils/siteGeoJSON.js +43 -0
- package/dist/map-v2/features/sites/utils/siteTreeUtils.d.ts +16 -0
- package/dist/{map → map-v2/features/sites}/utils/siteTreeUtils.js +9 -52
- 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/controls/SiteFilterControl.svelte +0 -126
- 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
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utilities for building and managing site filter tree
|
|
3
3
|
*/
|
|
4
|
-
const STORAGE_PREFIX = 'cellular:siteFilter';
|
|
5
4
|
/**
|
|
6
5
|
* Builds a hierarchical tree from flat site array
|
|
7
6
|
* Structure: All Sites -> Provider -> Feature Group
|
|
7
|
+
* @param sites - Array of sites to build tree from
|
|
8
|
+
* @param colorMap - Optional map of group keys (provider:featureGroup) to colors
|
|
8
9
|
*/
|
|
9
|
-
export function buildSiteTree(sites) {
|
|
10
|
+
export function buildSiteTree(sites, colorMap) {
|
|
10
11
|
// Group sites by provider, then by feature group
|
|
11
12
|
const providerGroups = new Map();
|
|
12
13
|
sites.forEach((site) => {
|
|
@@ -19,8 +20,6 @@ export function buildSiteTree(sites) {
|
|
|
19
20
|
}
|
|
20
21
|
featureGroups.get(site.featureGroup).push(site);
|
|
21
22
|
});
|
|
22
|
-
// Load saved state from localStorage
|
|
23
|
-
const savedState = loadTreeState();
|
|
24
23
|
// Build tree structure
|
|
25
24
|
const children = [];
|
|
26
25
|
// Sort providers alphabetically
|
|
@@ -33,16 +32,18 @@ export function buildSiteTree(sites) {
|
|
|
33
32
|
sortedFeatureGroups.forEach((featureGroup) => {
|
|
34
33
|
const groupSites = featureGroups.get(featureGroup);
|
|
35
34
|
const nodeId = `${provider}:${featureGroup}`;
|
|
35
|
+
const groupKey = nodeId; // Use same key format for color lookup
|
|
36
36
|
providerChildren.push({
|
|
37
37
|
id: nodeId,
|
|
38
38
|
label: `${featureGroup} (${groupSites.length})`,
|
|
39
|
-
defaultChecked:
|
|
39
|
+
defaultChecked: true,
|
|
40
40
|
children: [],
|
|
41
41
|
metadata: {
|
|
42
42
|
type: 'featureGroup',
|
|
43
43
|
provider,
|
|
44
44
|
featureGroup,
|
|
45
|
-
siteIds: groupSites.map((s) => s.id)
|
|
45
|
+
siteIds: groupSites.map((s) => s.id),
|
|
46
|
+
color: colorMap?.get(groupKey) // Add color from map if available
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
});
|
|
@@ -50,7 +51,7 @@ export function buildSiteTree(sites) {
|
|
|
50
51
|
children.push({
|
|
51
52
|
id: providerId,
|
|
52
53
|
label: `${provider} (${Array.from(featureGroups.values()).flat().length})`,
|
|
53
|
-
defaultChecked:
|
|
54
|
+
defaultChecked: true,
|
|
54
55
|
children: providerChildren,
|
|
55
56
|
metadata: {
|
|
56
57
|
type: 'provider',
|
|
@@ -62,7 +63,7 @@ export function buildSiteTree(sites) {
|
|
|
62
63
|
return {
|
|
63
64
|
id: 'all-sites',
|
|
64
65
|
label: `All Sites (${sites.length})`,
|
|
65
|
-
defaultChecked:
|
|
66
|
+
defaultChecked: true,
|
|
66
67
|
children,
|
|
67
68
|
metadata: {
|
|
68
69
|
type: 'root'
|
|
@@ -118,47 +119,3 @@ export function getFilteredSites(checkedPaths, allSites) {
|
|
|
118
119
|
console.log('Filtered:', filtered.length, 'of', allSites.length, 'sites');
|
|
119
120
|
return filtered;
|
|
120
121
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Saves tree checked paths to localStorage
|
|
123
|
-
*/
|
|
124
|
-
export function saveTreeState(checkedPaths) {
|
|
125
|
-
try {
|
|
126
|
-
localStorage.setItem(STORAGE_PREFIX, JSON.stringify(checkedPaths));
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
console.warn('Failed to save tree state to localStorage:', error);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Loads tree state from localStorage
|
|
134
|
-
* Returns map of node IDs to checked state
|
|
135
|
-
*/
|
|
136
|
-
export function loadTreeState() {
|
|
137
|
-
try {
|
|
138
|
-
const saved = localStorage.getItem(STORAGE_PREFIX);
|
|
139
|
-
if (saved) {
|
|
140
|
-
const paths = JSON.parse(saved);
|
|
141
|
-
// Convert paths to map for easier lookup during tree building
|
|
142
|
-
const stateMap = {};
|
|
143
|
-
paths.forEach((path) => {
|
|
144
|
-
stateMap[path] = true;
|
|
145
|
-
});
|
|
146
|
-
return stateMap;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
console.warn('Failed to load tree state from localStorage:', error);
|
|
151
|
-
}
|
|
152
|
-
return {};
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Clears saved tree state
|
|
156
|
-
*/
|
|
157
|
-
export function clearTreeState() {
|
|
158
|
-
try {
|
|
159
|
-
localStorage.removeItem(STORAGE_PREFIX);
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
console.warn('Failed to clear tree state from localStorage:', error);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map V2 - Feature-Based Cellular Visualization Library
|
|
3
|
+
*
|
|
4
|
+
* A decoupled, feature-based architecture for Mapbox cellular network visualization.
|
|
5
|
+
* Each feature (sites, cells) is completely independent with its own store, layers, and controls.
|
|
6
|
+
*/
|
|
7
|
+
export { type MapStore, MAP_CONTEXT_KEY, MapboxProvider, MapStyleControl, createMapStore, useMapbox, tryUseMapbox } from './core';
|
|
8
|
+
export { MapControl, addSourceIfMissing, removeSourceIfExists, addLayerIfMissing, removeLayerIfExists, updateGeoJSONSource, removeLayerAndSource, isStyleLoaded, waitForStyleLoad, setFeatureState, removeFeatureState, generateLayerId, generateSourceId } from './shared';
|
|
9
|
+
export { type Site, type SiteStoreValue, createSiteStore, SitesLayer, SiteFilterControl, SiteSizeSlider, sitesToGeoJSON, siteToFeature, buildSiteTree, getFilteredSites } from './features/sites';
|
|
10
|
+
export { DemoMap, demoSites } from './demo';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map V2 - Feature-Based Cellular Visualization Library
|
|
3
|
+
*
|
|
4
|
+
* A decoupled, feature-based architecture for Mapbox cellular network visualization.
|
|
5
|
+
* Each feature (sites, cells) is completely independent with its own store, layers, and controls.
|
|
6
|
+
*/
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// CORE INFRASTRUCTURE
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export { MAP_CONTEXT_KEY, MapboxProvider, MapStyleControl, createMapStore, useMapbox, tryUseMapbox } from './core';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// SHARED UTILITIES
|
|
13
|
+
// ============================================================================
|
|
14
|
+
export { MapControl, addSourceIfMissing, removeSourceIfExists, addLayerIfMissing, removeLayerIfExists, updateGeoJSONSource, removeLayerAndSource, isStyleLoaded, waitForStyleLoad, setFeatureState, removeFeatureState, generateLayerId, generateSourceId } from './shared';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// SITE FEATURE
|
|
17
|
+
// ============================================================================
|
|
18
|
+
export { createSiteStore, SitesLayer, SiteFilterControl, SiteSizeSlider, sitesToGeoJSON, siteToFeature, buildSiteTree, getFilteredSites } from './features/sites';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// DEMO
|
|
21
|
+
// ============================================================================
|
|
22
|
+
export { DemoMap, demoSites } from './demo';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { onMount, onDestroy } from 'svelte';
|
|
14
14
|
import mapboxgl from 'mapbox-gl';
|
|
15
|
-
import { tryUseMapbox } from '
|
|
15
|
+
import { tryUseMapbox } from '../../core/hooks/useMapbox';
|
|
16
16
|
|
|
17
17
|
interface Props {
|
|
18
18
|
/** Position on the map */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Utilities - Public API
|
|
3
|
+
*
|
|
4
|
+
* Exports shared controls and utilities used across features
|
|
5
|
+
*/
|
|
6
|
+
export { default as MapControl } from './controls/MapControl.svelte';
|
|
7
|
+
export { addSourceIfMissing, removeSourceIfExists, addLayerIfMissing, removeLayerIfExists, updateGeoJSONSource, removeLayerAndSource, isStyleLoaded, waitForStyleLoad, setFeatureState, removeFeatureState, generateLayerId, generateSourceId } from './utils/mapboxHelpers';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Utilities - Public API
|
|
3
|
+
*
|
|
4
|
+
* Exports shared controls and utilities used across features
|
|
5
|
+
*/
|
|
6
|
+
// Controls
|
|
7
|
+
export { default as MapControl } from './controls/MapControl.svelte';
|
|
8
|
+
// Mapbox Helpers
|
|
9
|
+
export { addSourceIfMissing, removeSourceIfExists, addLayerIfMissing, removeLayerIfExists, updateGeoJSONSource, removeLayerAndSource, isStyleLoaded, waitForStyleLoad, setFeatureState, removeFeatureState, generateLayerId, generateSourceId } from './utils/mapboxHelpers';
|
package/package.json
CHANGED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* SiteFilterControl - TreeView-based site filtering control for Mapbox
|
|
4
|
-
*
|
|
5
|
-
* Displays a hierarchical tree: All Sites -> Provider -> Feature Group
|
|
6
|
-
* Filters sites based on checked state and persists to localStorage
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* <SiteFilterControl
|
|
10
|
-
* {sites}
|
|
11
|
-
* bind:filteredSites
|
|
12
|
-
* position="top-left"
|
|
13
|
-
* />
|
|
14
|
-
*/
|
|
15
|
-
import { onMount } from 'svelte';
|
|
16
|
-
import type { Writable } from 'svelte/store';
|
|
17
|
-
import MapControl from './MapControl.svelte';
|
|
18
|
-
import TreeView from '../../core/TreeView/TreeView.svelte';
|
|
19
|
-
import { createTreeStore } from '../../core/TreeView/tree.store';
|
|
20
|
-
import { buildSiteTree, getFilteredSites, saveTreeState } from '../utils/siteTreeUtils';
|
|
21
|
-
import type { Site } from '../types';
|
|
22
|
-
import type { TreeStoreValue } from '../../core/TreeView/tree.model';
|
|
23
|
-
|
|
24
|
-
interface Props {
|
|
25
|
-
/** All sites to filter */
|
|
26
|
-
sites: Site[];
|
|
27
|
-
/** Filtered sites output */
|
|
28
|
-
filteredSites?: Site[];
|
|
29
|
-
/** Control position on map */
|
|
30
|
-
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
31
|
-
/** Control title */
|
|
32
|
-
title?: string;
|
|
33
|
-
/** Initially collapsed? */
|
|
34
|
-
initiallyCollapsed?: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let {
|
|
38
|
-
sites,
|
|
39
|
-
filteredSites = $bindable([]),
|
|
40
|
-
position = 'top-left',
|
|
41
|
-
title = 'Site Filter',
|
|
42
|
-
initiallyCollapsed = false
|
|
43
|
-
}: Props = $props();
|
|
44
|
-
|
|
45
|
-
let treeStore = $state<Writable<TreeStoreValue> | null>(null);
|
|
46
|
-
|
|
47
|
-
// Initialize filteredSites with all sites immediately
|
|
48
|
-
if (filteredSites.length === 0 && sites.length > 0) {
|
|
49
|
-
filteredSites = [...sites];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Build tree and create store when sites change (run only once on mount)
|
|
53
|
-
onMount(() => {
|
|
54
|
-
console.log('SiteFilterControl: Mounted with', sites.length, 'sites');
|
|
55
|
-
|
|
56
|
-
if (sites.length > 0) {
|
|
57
|
-
console.log('SiteFilterControl: Building tree...');
|
|
58
|
-
const treeNodes = buildSiteTree(sites);
|
|
59
|
-
|
|
60
|
-
treeStore = createTreeStore({
|
|
61
|
-
nodes: [treeNodes],
|
|
62
|
-
namespace: 'cellular-site-filter',
|
|
63
|
-
persistState: true,
|
|
64
|
-
defaultExpandAll: false
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
console.log('SiteFilterControl: Tree store created');
|
|
68
|
-
|
|
69
|
-
// Subscribe to tree changes and update filtered sites
|
|
70
|
-
if (treeStore) {
|
|
71
|
-
const unsub = treeStore.subscribe((store: TreeStoreValue) => {
|
|
72
|
-
const checkedPaths = store.getCheckedPaths();
|
|
73
|
-
console.log('TreeStore updated, checked paths:', checkedPaths);
|
|
74
|
-
|
|
75
|
-
const newFilteredSites = getFilteredSites(checkedPaths, sites);
|
|
76
|
-
console.log('Filtered sites count:', newFilteredSites.length, 'of', sites.length);
|
|
77
|
-
|
|
78
|
-
filteredSites = newFilteredSites;
|
|
79
|
-
|
|
80
|
-
// Save state to our custom storage
|
|
81
|
-
saveTreeState(checkedPaths);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
return () => unsub();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
</script>
|
|
89
|
-
|
|
90
|
-
<MapControl {position} {title} collapsible={true} {initiallyCollapsed}>
|
|
91
|
-
{#if treeStore && $treeStore}
|
|
92
|
-
<div class="site-filter-tree">
|
|
93
|
-
<TreeView store={$treeStore} showControls={false} />
|
|
94
|
-
|
|
95
|
-
<!-- <div class="site-filter-stats">
|
|
96
|
-
<small class="text-muted">
|
|
97
|
-
Showing {filteredSites.length} of {sites.length} sites
|
|
98
|
-
</small>
|
|
99
|
-
</div> -->
|
|
100
|
-
</div>
|
|
101
|
-
{:else}
|
|
102
|
-
<div class="text-muted small">Loading sites...</div>
|
|
103
|
-
{/if}
|
|
104
|
-
</MapControl>
|
|
105
|
-
|
|
106
|
-
<style>
|
|
107
|
-
.site-filter-tree {
|
|
108
|
-
min-width: 250px;
|
|
109
|
-
max-width: 300px;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.site-filter-stats {
|
|
113
|
-
margin-top: 8px;
|
|
114
|
-
padding-top: 8px;
|
|
115
|
-
border-top: 1px solid #dee2e6;
|
|
116
|
-
text-align: center;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
:global(.site-filter-tree .tree-node-label) {
|
|
120
|
-
font-size: 13px;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
:global(.site-filter-tree .tree-node-checkbox) {
|
|
124
|
-
margin-right: 6px;
|
|
125
|
-
}
|
|
126
|
-
</style>
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* DemoMap - Complete demo component with map initialization and sample data
|
|
4
|
-
*/
|
|
5
|
-
import { onMount } from 'svelte';
|
|
6
|
-
import mapboxgl from 'mapbox-gl';
|
|
7
|
-
import 'mapbox-gl/dist/mapbox-gl.css';
|
|
8
|
-
|
|
9
|
-
import MapboxProvider from '../providers/MapboxProvider.svelte';
|
|
10
|
-
import CellDataProvider from '../providers/CellDataProvider.svelte';
|
|
11
|
-
import SitesLayer from '../layers/SitesLayer.svelte';
|
|
12
|
-
import CellsLayer from '../layers/CellsLayer.svelte';
|
|
13
|
-
import SiteFilterControl from '../controls/SiteFilterControl.svelte';
|
|
14
|
-
import { demoSites, demoCells } from './demo-data';
|
|
15
|
-
import type { Site, Cell } from '../types';
|
|
16
|
-
|
|
17
|
-
interface Props {
|
|
18
|
-
/** Mapbox access token */
|
|
19
|
-
accessToken?: string;
|
|
20
|
-
/** Initial center coordinates [lng, lat] */
|
|
21
|
-
center?: [number, number];
|
|
22
|
-
/** Initial zoom level */
|
|
23
|
-
zoom?: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let {
|
|
27
|
-
accessToken = '',
|
|
28
|
-
center = [-122.4194, 37.7749], // San Francisco
|
|
29
|
-
zoom = 12
|
|
30
|
-
}: Props = $props();
|
|
31
|
-
|
|
32
|
-
let mapContainer: HTMLDivElement;
|
|
33
|
-
let map = $state<mapboxgl.Map | null>(null);
|
|
34
|
-
let mapReady = $state(false);
|
|
35
|
-
|
|
36
|
-
// Data
|
|
37
|
-
let sites = $state<Site[]>(demoSites);
|
|
38
|
-
let cells = $state<Cell[]>(demoCells);
|
|
39
|
-
let filteredSites = $state<Site[]>(sites);
|
|
40
|
-
|
|
41
|
-
onMount(() => {
|
|
42
|
-
// Initialize Mapbox map
|
|
43
|
-
map = new mapboxgl.Map({
|
|
44
|
-
container: mapContainer,
|
|
45
|
-
style: 'mapbox://styles/mapbox/streets-v12',
|
|
46
|
-
center,
|
|
47
|
-
zoom,
|
|
48
|
-
accessToken
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Add navigation controls
|
|
52
|
-
map.addControl(new mapboxgl.NavigationControl(), 'top-right');
|
|
53
|
-
|
|
54
|
-
// Wait for map to load
|
|
55
|
-
map.on('load', () => {
|
|
56
|
-
mapReady = true;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
return () => {
|
|
60
|
-
map?.remove();
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
</script>
|
|
64
|
-
|
|
65
|
-
<div class="demo-map-container">
|
|
66
|
-
<div bind:this={mapContainer} class="w-100 h-100"></div>
|
|
67
|
-
|
|
68
|
-
{#if !mapReady}
|
|
69
|
-
<div class="position-absolute top-50 start-50 translate-middle bg-white p-4 rounded shadow">
|
|
70
|
-
<div class="spinner-border text-primary me-2" role="status">
|
|
71
|
-
<span class="visually-hidden">Loading...</span>
|
|
72
|
-
</div>
|
|
73
|
-
<span>Loading map...</span>
|
|
74
|
-
</div>
|
|
75
|
-
{/if}
|
|
76
|
-
|
|
77
|
-
{#if mapReady && map}
|
|
78
|
-
<MapboxProvider mapInstance={map}>
|
|
79
|
-
<CellDataProvider sites={filteredSites} {cells}>
|
|
80
|
-
<SitesLayer />
|
|
81
|
-
<!-- <CellsLayer /> -->
|
|
82
|
-
<SiteFilterControl {sites} bind:filteredSites position="top-left" />
|
|
83
|
-
</CellDataProvider>
|
|
84
|
-
</MapboxProvider>
|
|
85
|
-
{/if}
|
|
86
|
-
</div>
|
|
87
|
-
|
|
88
|
-
<style>
|
|
89
|
-
.demo-map-container {
|
|
90
|
-
position: absolute;
|
|
91
|
-
top: 0;
|
|
92
|
-
left: 0;
|
|
93
|
-
right: 0;
|
|
94
|
-
bottom: 0;
|
|
95
|
-
width: 100%;
|
|
96
|
-
height: 100%;
|
|
97
|
-
}
|
|
98
|
-
</style>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Demo cellular data for testing and examples
|
|
3
|
-
*/
|
|
4
|
-
import type { Site, Cell } from '../types';
|
|
5
|
-
/**
|
|
6
|
-
* Sample cellular sites (San Francisco area)
|
|
7
|
-
*/
|
|
8
|
-
export declare const demoSites: Site[];
|
|
9
|
-
/**
|
|
10
|
-
* Sample cellular cells/sectors
|
|
11
|
-
*/
|
|
12
|
-
export declare const demoCells: Cell[];
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Demo cellular data for testing and examples
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Sample cellular sites (San Francisco area)
|
|
6
|
-
*/
|
|
7
|
-
export const demoSites = [
|
|
8
|
-
{
|
|
9
|
-
id: 'site-001',
|
|
10
|
-
name: 'Downtown Tower',
|
|
11
|
-
longitude: -122.4194,
|
|
12
|
-
latitude: 37.7749,
|
|
13
|
-
fbands: ['2100', '1800'],
|
|
14
|
-
technology: '5G',
|
|
15
|
-
properties: {
|
|
16
|
-
height: 45,
|
|
17
|
-
type: 'macro'
|
|
18
|
-
},
|
|
19
|
-
cellNames: ['cell-001-1', 'cell-001-2', 'cell-001-3'],
|
|
20
|
-
provider: 'Verizon',
|
|
21
|
-
featureGroup: 'Urban Macro'
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: 'site-002',
|
|
25
|
-
name: 'Financial District',
|
|
26
|
-
longitude: -122.4008,
|
|
27
|
-
latitude: 37.7946,
|
|
28
|
-
fbands: ['1800', '850'],
|
|
29
|
-
technology: 'LTE',
|
|
30
|
-
properties: {
|
|
31
|
-
height: 60,
|
|
32
|
-
type: 'macro'
|
|
33
|
-
},
|
|
34
|
-
cellNames: ['cell-002-1', 'cell-002-2', 'cell-002-3'],
|
|
35
|
-
provider: 'AT&T',
|
|
36
|
-
featureGroup: 'Urban Macro'
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
id: 'site-003',
|
|
40
|
-
name: 'Mission Bay',
|
|
41
|
-
longitude: -122.3912,
|
|
42
|
-
latitude: 37.7699,
|
|
43
|
-
fbands: ['2600'],
|
|
44
|
-
technology: '5G',
|
|
45
|
-
properties: {
|
|
46
|
-
height: 30,
|
|
47
|
-
type: 'micro'
|
|
48
|
-
},
|
|
49
|
-
cellNames: ['cell-003-1', 'cell-003-2'],
|
|
50
|
-
provider: 'T-Mobile',
|
|
51
|
-
featureGroup: 'Small Cell'
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
id: 'site-004',
|
|
55
|
-
name: 'Golden Gate Park',
|
|
56
|
-
longitude: -122.4862,
|
|
57
|
-
latitude: 37.7694,
|
|
58
|
-
fbands: ['850', '700'],
|
|
59
|
-
technology: 'LTE',
|
|
60
|
-
properties: {
|
|
61
|
-
height: 40,
|
|
62
|
-
type: 'macro'
|
|
63
|
-
},
|
|
64
|
-
cellNames: ['cell-004-1', 'cell-004-2', 'cell-004-3'],
|
|
65
|
-
provider: 'Verizon',
|
|
66
|
-
featureGroup: 'Rural Macro'
|
|
67
|
-
}
|
|
68
|
-
];
|
|
69
|
-
/**
|
|
70
|
-
* Sample cellular cells/sectors
|
|
71
|
-
*/
|
|
72
|
-
export const demoCells = [
|
|
73
|
-
// Site 001 - Downtown Tower (3 sectors)
|
|
74
|
-
{
|
|
75
|
-
id: 'cell-001-1',
|
|
76
|
-
siteId: 'site-001',
|
|
77
|
-
sector: 1,
|
|
78
|
-
azimuth: 0,
|
|
79
|
-
beamwidth: 65,
|
|
80
|
-
radius: 800,
|
|
81
|
-
properties: {
|
|
82
|
-
band: '2100MHz',
|
|
83
|
-
technology: '5G',
|
|
84
|
-
power: 40
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
id: 'cell-001-2',
|
|
89
|
-
siteId: 'site-001',
|
|
90
|
-
sector: 2,
|
|
91
|
-
azimuth: 120,
|
|
92
|
-
beamwidth: 65,
|
|
93
|
-
radius: 800,
|
|
94
|
-
properties: {
|
|
95
|
-
band: '2100MHz',
|
|
96
|
-
technology: '5G',
|
|
97
|
-
power: 40
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: 'cell-001-3',
|
|
102
|
-
siteId: 'site-001',
|
|
103
|
-
sector: 3,
|
|
104
|
-
azimuth: 240,
|
|
105
|
-
beamwidth: 65,
|
|
106
|
-
radius: 800,
|
|
107
|
-
properties: {
|
|
108
|
-
band: '2100MHz',
|
|
109
|
-
technology: '5G',
|
|
110
|
-
power: 40
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
// Site 002 - Financial District (3 sectors)
|
|
114
|
-
{
|
|
115
|
-
id: 'cell-002-1',
|
|
116
|
-
siteId: 'site-002',
|
|
117
|
-
sector: 1,
|
|
118
|
-
azimuth: 30,
|
|
119
|
-
beamwidth: 65,
|
|
120
|
-
radius: 700,
|
|
121
|
-
properties: {
|
|
122
|
-
band: '1800MHz',
|
|
123
|
-
technology: 'LTE',
|
|
124
|
-
power: 38
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
id: 'cell-002-2',
|
|
129
|
-
siteId: 'site-002',
|
|
130
|
-
sector: 2,
|
|
131
|
-
azimuth: 150,
|
|
132
|
-
beamwidth: 65,
|
|
133
|
-
radius: 700,
|
|
134
|
-
properties: {
|
|
135
|
-
band: '1800MHz',
|
|
136
|
-
technology: 'LTE',
|
|
137
|
-
power: 38
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
id: 'cell-002-3',
|
|
142
|
-
siteId: 'site-002',
|
|
143
|
-
sector: 3,
|
|
144
|
-
azimuth: 270,
|
|
145
|
-
beamwidth: 65,
|
|
146
|
-
radius: 700,
|
|
147
|
-
properties: {
|
|
148
|
-
band: '1800MHz',
|
|
149
|
-
technology: 'LTE',
|
|
150
|
-
power: 38
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
// Site 003 - Mission Bay (2 sectors, smaller coverage)
|
|
154
|
-
{
|
|
155
|
-
id: 'cell-003-1',
|
|
156
|
-
siteId: 'site-003',
|
|
157
|
-
sector: 1,
|
|
158
|
-
azimuth: 90,
|
|
159
|
-
beamwidth: 90,
|
|
160
|
-
radius: 400,
|
|
161
|
-
properties: {
|
|
162
|
-
band: '2600MHz',
|
|
163
|
-
technology: '5G',
|
|
164
|
-
power: 30
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
id: 'cell-003-2',
|
|
169
|
-
siteId: 'site-003',
|
|
170
|
-
sector: 2,
|
|
171
|
-
azimuth: 270,
|
|
172
|
-
beamwidth: 90,
|
|
173
|
-
radius: 400,
|
|
174
|
-
properties: {
|
|
175
|
-
band: '2600MHz',
|
|
176
|
-
technology: '5G',
|
|
177
|
-
power: 30
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
// Site 004 - Golden Gate Park (3 sectors)
|
|
181
|
-
{
|
|
182
|
-
id: 'cell-004-1',
|
|
183
|
-
siteId: 'site-004',
|
|
184
|
-
sector: 1,
|
|
185
|
-
azimuth: 0,
|
|
186
|
-
beamwidth: 120,
|
|
187
|
-
radius: 900,
|
|
188
|
-
properties: {
|
|
189
|
-
band: '850MHz',
|
|
190
|
-
technology: 'LTE',
|
|
191
|
-
power: 43
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
id: 'cell-004-2',
|
|
196
|
-
siteId: 'site-004',
|
|
197
|
-
sector: 2,
|
|
198
|
-
azimuth: 120,
|
|
199
|
-
beamwidth: 120,
|
|
200
|
-
radius: 900,
|
|
201
|
-
properties: {
|
|
202
|
-
band: '850MHz',
|
|
203
|
-
technology: 'LTE',
|
|
204
|
-
power: 43
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
id: 'cell-004-3',
|
|
209
|
-
siteId: 'site-004',
|
|
210
|
-
sector: 3,
|
|
211
|
-
azimuth: 240,
|
|
212
|
-
beamwidth: 120,
|
|
213
|
-
radius: 900,
|
|
214
|
-
properties: {
|
|
215
|
-
band: '850MHz',
|
|
216
|
-
technology: 'LTE',
|
|
217
|
-
power: 43
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
];
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook to safely access cell data stores from context
|
|
3
|
-
*/
|
|
4
|
-
import type { CellDataContext } from '../types';
|
|
5
|
-
/**
|
|
6
|
-
* Retrieves the cell data context stores
|
|
7
|
-
* @throws Error if called outside of CellDataProvider
|
|
8
|
-
*/
|
|
9
|
-
export declare function useCellData(): CellDataContext;
|
|
10
|
-
/**
|
|
11
|
-
* Tries to retrieve the cell data context stores
|
|
12
|
-
* Returns null if not available (safe version)
|
|
13
|
-
*/
|
|
14
|
-
export declare function tryUseCellData(): CellDataContext | null;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook to safely access cell data stores from context
|
|
3
|
-
*/
|
|
4
|
-
import { getContext } from 'svelte';
|
|
5
|
-
import { CELL_DATA_CONTEXT_KEY } from '../types';
|
|
6
|
-
/**
|
|
7
|
-
* Retrieves the cell data context stores
|
|
8
|
-
* @throws Error if called outside of CellDataProvider
|
|
9
|
-
*/
|
|
10
|
-
export function useCellData() {
|
|
11
|
-
const cellDataContext = getContext(CELL_DATA_CONTEXT_KEY);
|
|
12
|
-
if (!cellDataContext) {
|
|
13
|
-
throw new Error('useCellData() must be called within a <CellDataProvider> component. ' +
|
|
14
|
-
'Make sure your component is wrapped in <CellDataProvider>.');
|
|
15
|
-
}
|
|
16
|
-
return cellDataContext;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Tries to retrieve the cell data context stores
|
|
20
|
-
* Returns null if not available (safe version)
|
|
21
|
-
*/
|
|
22
|
-
export function tryUseCellData() {
|
|
23
|
-
try {
|
|
24
|
-
return getContext(CELL_DATA_CONTEXT_KEY);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|