@smartnet360/svelte-components 0.0.101 → 0.0.103

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.
Files changed (81) hide show
  1. package/dist/apps/antenna-pattern/index.d.ts +1 -0
  2. package/dist/apps/antenna-pattern/index.js +1 -0
  3. package/dist/apps/antenna-pattern/utils/load-static-antennas.d.ts +17 -0
  4. package/dist/apps/antenna-pattern/utils/load-static-antennas.js +83 -0
  5. package/dist/apps/site-check/SiteCheck.svelte +4 -6
  6. package/dist/core/Charts/ChartCard.svelte +122 -12
  7. package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
  8. package/dist/core/Charts/ChartComponent.svelte +8 -6
  9. package/dist/core/CoverageMap/ai/AITools.d.ts +117 -0
  10. package/dist/core/CoverageMap/ai/AITools.js +380 -0
  11. package/dist/core/CoverageMap/core/CoverageCalculator.d.ts +138 -0
  12. package/dist/core/CoverageMap/core/CoverageCalculator.js +375 -0
  13. package/dist/core/CoverageMap/core/GridCalculator.d.ts +115 -0
  14. package/dist/core/CoverageMap/core/GridCalculator.js +484 -0
  15. package/dist/core/CoverageMap/core/PathLossModels.d.ts +253 -0
  16. package/dist/core/CoverageMap/core/PathLossModels.js +380 -0
  17. package/dist/core/CoverageMap/core/SignalProcessor.d.ts +288 -0
  18. package/dist/core/CoverageMap/core/SignalProcessor.js +424 -0
  19. package/dist/core/CoverageMap/data/AntennaStore.d.ts +165 -0
  20. package/dist/core/CoverageMap/data/AntennaStore.js +327 -0
  21. package/dist/core/CoverageMap/data/SiteStore.d.ts +155 -0
  22. package/dist/core/CoverageMap/data/SiteStore.js +355 -0
  23. package/dist/core/CoverageMap/index.d.ts +74 -0
  24. package/dist/core/CoverageMap/index.js +103 -0
  25. package/dist/core/CoverageMap/types.d.ts +252 -0
  26. package/dist/core/CoverageMap/types.js +7 -0
  27. package/dist/core/CoverageMap/utils/geoUtils.d.ts +223 -0
  28. package/dist/core/CoverageMap/utils/geoUtils.js +374 -0
  29. package/dist/core/CoverageMap/utils/rfUtils.d.ts +329 -0
  30. package/dist/core/CoverageMap/utils/rfUtils.js +434 -0
  31. package/dist/core/CoverageMap/visualization/ColorSchemes.d.ts +149 -0
  32. package/dist/core/CoverageMap/visualization/ColorSchemes.js +377 -0
  33. package/dist/core/TreeView/index.d.ts +4 -4
  34. package/dist/core/TreeView/index.js +5 -5
  35. package/dist/core/TreeView/tree-utils.d.ts +12 -0
  36. package/dist/core/TreeView/tree-utils.js +115 -6
  37. package/dist/core/TreeView/tree.store.svelte.d.ts +94 -0
  38. package/dist/core/TreeView/tree.store.svelte.js +274 -0
  39. package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +16 -27
  40. package/dist/map-v2/features/cells/utils/cellGeoJSON.js +1 -0
  41. package/dist/map-v2/features/repeaters/controls/RepeaterFilterControl.svelte +33 -42
  42. package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +12 -19
  43. package/dist/map-v3/core/components/Map.svelte +4 -0
  44. package/dist/map-v3/core/stores/map.store.svelte.js +2 -0
  45. package/dist/map-v3/demo/DemoMap.svelte +31 -5
  46. package/dist/map-v3/demo/demo-cells.js +51 -22
  47. package/dist/map-v3/features/cells/components/CellFilterControl.svelte +24 -30
  48. package/dist/map-v3/features/cells/layers/CellsLayer.svelte +29 -9
  49. package/dist/map-v3/features/cells/logic/geometry.js +3 -0
  50. package/dist/map-v3/features/cells/stores/cell.data.svelte.d.ts +27 -0
  51. package/dist/map-v3/features/cells/stores/cell.data.svelte.js +65 -0
  52. package/dist/map-v3/features/coverage/index.d.ts +12 -0
  53. package/dist/map-v3/features/coverage/index.js +16 -0
  54. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte +198 -0
  55. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte.d.ts +10 -0
  56. package/dist/map-v3/features/coverage/logic/coloring.d.ts +28 -0
  57. package/dist/map-v3/features/coverage/logic/coloring.js +77 -0
  58. package/dist/map-v3/features/coverage/logic/geometry.d.ts +33 -0
  59. package/dist/map-v3/features/coverage/logic/geometry.js +112 -0
  60. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.d.ts +46 -0
  61. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.js +95 -0
  62. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.d.ts +33 -0
  63. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.js +90 -0
  64. package/dist/map-v3/features/coverage/types.d.ts +52 -0
  65. package/dist/map-v3/features/coverage/types.js +7 -0
  66. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +14 -20
  67. package/dist/map-v3/features/selection/components/FeatureSelectionControl.svelte +82 -65
  68. package/dist/map-v3/features/selection/components/FeatureSelectionControl.svelte.d.ts +5 -9
  69. package/dist/map-v3/features/selection/index.d.ts +1 -2
  70. package/dist/map-v3/features/selection/index.js +0 -1
  71. package/dist/map-v3/features/selection/stores/selection.store.svelte.d.ts +44 -15
  72. package/dist/map-v3/features/selection/stores/selection.store.svelte.js +163 -40
  73. package/dist/map-v3/features/selection/types.d.ts +4 -2
  74. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +23 -33
  75. package/dist/map-v3/index.d.ts +4 -0
  76. package/dist/map-v3/index.js +5 -0
  77. package/package.json +2 -2
  78. package/dist/core/TreeView/tree.store.d.ts +0 -10
  79. package/dist/core/TreeView/tree.store.js +0 -320
  80. package/dist/map-v3/features/selection/layers/SelectionHighlightLayers.svelte +0 -209
  81. package/dist/map-v3/features/selection/layers/SelectionHighlightLayers.svelte.d.ts +0 -13
@@ -0,0 +1,10 @@
1
+ import type { CoverageDataStore } from '../stores/coverage.data.svelte';
2
+ import type { CoverageDisplayStore } from '../stores/coverage.display.svelte';
3
+ interface Props {
4
+ dataStore: CoverageDataStore;
5
+ displayStore: CoverageDisplayStore;
6
+ autoFitBounds?: boolean;
7
+ }
8
+ declare const CoverageLayer: import("svelte").Component<Props, {}, "">;
9
+ type CoverageLayer = ReturnType<typeof CoverageLayer>;
10
+ export default CoverageLayer;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Color Scheme Utilities
3
+ *
4
+ * Wraps CoverageMap color scheme functions for coverage layer use.
5
+ */
6
+ import type { SignalThresholds } from '../../../../core/CoverageMap';
7
+ import type { CoverageColorScheme } from '../types';
8
+ /**
9
+ * Get color for signal strength using specified color scheme
10
+ *
11
+ * @param signalDbm - Signal strength in dBm
12
+ * @param colorScheme - Color scheme name
13
+ * @param thresholds - Optional signal thresholds
14
+ * @returns Hex color string
15
+ */
16
+ export declare function getColorForSignal(signalDbm: number, colorScheme: CoverageColorScheme, thresholds?: SignalThresholds): string;
17
+ /**
18
+ * Get legend items for a color scheme
19
+ *
20
+ * @param colorScheme - Color scheme name
21
+ * @param thresholds - Signal thresholds
22
+ * @returns Array of legend items with color and label
23
+ */
24
+ export declare function getLegendItems(colorScheme: CoverageColorScheme, thresholds?: SignalThresholds): Array<{
25
+ color: string;
26
+ label: string;
27
+ range: string;
28
+ }>;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Color Scheme Utilities
3
+ *
4
+ * Wraps CoverageMap color scheme functions for coverage layer use.
5
+ */
6
+ import { getColorForSignal as getCoverageColor, HEATMAP_RED_BLUE, VIRIDIS, PLASMA, CATEGORICAL } from '../../../../core/CoverageMap';
7
+ /**
8
+ * Default signal thresholds for coloring
9
+ */
10
+ const DEFAULT_THRESHOLDS = {
11
+ excellent: -70,
12
+ good: -85,
13
+ fair: -95,
14
+ edge: -105
15
+ };
16
+ /**
17
+ * Map coverage color scheme names to CoverageMap ColorScheme objects
18
+ */
19
+ const SCHEME_MAP = {
20
+ 'heatmap': HEATMAP_RED_BLUE,
21
+ 'quality': CATEGORICAL,
22
+ 'viridis': VIRIDIS,
23
+ 'plasma': PLASMA,
24
+ 'categorical': CATEGORICAL
25
+ };
26
+ /**
27
+ * Get color for signal strength using specified color scheme
28
+ *
29
+ * @param signalDbm - Signal strength in dBm
30
+ * @param colorScheme - Color scheme name
31
+ * @param thresholds - Optional signal thresholds
32
+ * @returns Hex color string
33
+ */
34
+ export function getColorForSignal(signalDbm, colorScheme, thresholds = DEFAULT_THRESHOLDS) {
35
+ const scheme = SCHEME_MAP[colorScheme];
36
+ if (!scheme) {
37
+ console.warn(`[ColorSchemes] Unknown scheme: ${colorScheme}, using heatmap`);
38
+ return getCoverageColor(signalDbm, thresholds, HEATMAP_RED_BLUE);
39
+ }
40
+ return getCoverageColor(signalDbm, thresholds, scheme);
41
+ }
42
+ /**
43
+ * Get legend items for a color scheme
44
+ *
45
+ * @param colorScheme - Color scheme name
46
+ * @param thresholds - Signal thresholds
47
+ * @returns Array of legend items with color and label
48
+ */
49
+ export function getLegendItems(colorScheme, thresholds = DEFAULT_THRESHOLDS) {
50
+ return [
51
+ {
52
+ color: getColorForSignal(thresholds.excellent, colorScheme, thresholds),
53
+ label: 'Excellent',
54
+ range: `> ${thresholds.excellent} dBm`
55
+ },
56
+ {
57
+ color: getColorForSignal((thresholds.excellent + thresholds.good) / 2, colorScheme, thresholds),
58
+ label: 'Good',
59
+ range: `${thresholds.good} to ${thresholds.excellent} dBm`
60
+ },
61
+ {
62
+ color: getColorForSignal((thresholds.good + thresholds.fair) / 2, colorScheme, thresholds),
63
+ label: 'Fair',
64
+ range: `${thresholds.fair} to ${thresholds.good} dBm`
65
+ },
66
+ {
67
+ color: getColorForSignal((thresholds.fair + thresholds.edge) / 2, colorScheme, thresholds),
68
+ label: 'Poor',
69
+ range: `${thresholds.edge} to ${thresholds.fair} dBm`
70
+ },
71
+ {
72
+ color: getColorForSignal(thresholds.edge - 5, colorScheme, thresholds),
73
+ label: 'Edge',
74
+ range: `< ${thresholds.edge} dBm`
75
+ }
76
+ ];
77
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Grid Geometry Utilities
3
+ *
4
+ * Convert coverage grid cells to GeoJSON for Mapbox rendering.
5
+ * Applies color schemes and filtering.
6
+ */
7
+ import type { CoverageGrid, SignalThresholds } from '../types';
8
+ import type { CoverageColorScheme } from '../types';
9
+ import type { FeatureCollection, Polygon } from 'geojson';
10
+ /**
11
+ * Convert coverage grid to GeoJSON FeatureCollection
12
+ *
13
+ * @param grid - Coverage grid from calculation
14
+ * @param colorScheme - Color scheme to apply
15
+ * @param minSignal - Minimum signal threshold (dBm)
16
+ * @param maxSignal - Maximum signal threshold (dBm)
17
+ * @returns GeoJSON FeatureCollection ready for Mapbox
18
+ */
19
+ export declare function gridToGeoJSON(grid: CoverageGrid, colorScheme: CoverageColorScheme, minSignal?: number, maxSignal?: number, thresholds?: SignalThresholds): FeatureCollection<Polygon>;
20
+ /**
21
+ * Calculate grid bounds for initial map view
22
+ *
23
+ * @param grid - Coverage grid
24
+ * @returns Mapbox-compatible bounds [[west, south], [east, north]]
25
+ */
26
+ export declare function getGridBounds(grid: CoverageGrid): [[number, number], [number, number]];
27
+ /**
28
+ * Get signal strength range from grid
29
+ *
30
+ * @param grid - Coverage grid
31
+ * @returns [min, max] signal strength in dBm
32
+ */
33
+ export declare function getSignalRange(grid: CoverageGrid): [number, number];
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Grid Geometry Utilities
3
+ *
4
+ * Convert coverage grid cells to GeoJSON for Mapbox rendering.
5
+ * Applies color schemes and filtering.
6
+ */
7
+ import { getColorForSignal } from './coloring';
8
+ /**
9
+ * Convert coverage grid to GeoJSON FeatureCollection
10
+ *
11
+ * @param grid - Coverage grid from calculation
12
+ * @param colorScheme - Color scheme to apply
13
+ * @param minSignal - Minimum signal threshold (dBm)
14
+ * @param maxSignal - Maximum signal threshold (dBm)
15
+ * @returns GeoJSON FeatureCollection ready for Mapbox
16
+ */
17
+ export function gridToGeoJSON(grid, colorScheme, minSignal = -115, maxSignal = -40, thresholds) {
18
+ const features = [];
19
+ const cellSizeMeters = grid.cellSizeMeters;
20
+ // Flatten 2D grid to 1D for processing
21
+ for (const row of grid.cells) {
22
+ for (const cell of row) {
23
+ // Filter by signal strength
24
+ if (cell.signalStrength < minSignal || cell.signalStrength > maxSignal) {
25
+ continue;
26
+ }
27
+ // Skip no-signal cells
28
+ if (cell.quality === 'no-signal') {
29
+ continue;
30
+ }
31
+ // Get color for this cell
32
+ const color = getColorForSignal(cell.signalStrength, colorScheme, thresholds);
33
+ // Create polygon feature
34
+ const feature = createCellPolygon(cell, cellSizeMeters, color);
35
+ features.push(feature);
36
+ }
37
+ }
38
+ return {
39
+ type: 'FeatureCollection',
40
+ features
41
+ };
42
+ }
43
+ /**
44
+ * Create a GeoJSON polygon for a single grid cell
45
+ *
46
+ * @param cell - Grid cell data
47
+ * @param cellSizeMeters - Size of cell in meters
48
+ * @param color - Hex color for this cell
49
+ * @returns GeoJSON Feature
50
+ */
51
+ function createCellPolygon(cell, cellSizeMeters, color) {
52
+ // Calculate cell corners (approximate, good enough for visualization)
53
+ const latOffset = (cellSizeMeters / 111320); // ~111,320 meters per degree lat
54
+ const lngOffset = (cellSizeMeters / (111320 * Math.cos(cell.position.lat * Math.PI / 180)));
55
+ const lat = cell.position.lat;
56
+ const lng = cell.position.lng;
57
+ // Cell corners (clockwise from bottom-left)
58
+ const coordinates = [[
59
+ [lng - lngOffset / 2, lat - latOffset / 2], // SW
60
+ [lng + lngOffset / 2, lat - latOffset / 2], // SE
61
+ [lng + lngOffset / 2, lat + latOffset / 2], // NE
62
+ [lng - lngOffset / 2, lat + latOffset / 2], // NW
63
+ [lng - lngOffset / 2, lat - latOffset / 2] // Close polygon
64
+ ]];
65
+ return {
66
+ type: 'Feature',
67
+ geometry: {
68
+ type: 'Polygon',
69
+ coordinates
70
+ },
71
+ properties: {
72
+ signal: cell.signalStrength,
73
+ quality: cell.quality,
74
+ color: color,
75
+ lat: cell.position.lat,
76
+ lon: cell.position.lng,
77
+ dominantSector: cell.dominantSector
78
+ }
79
+ };
80
+ }
81
+ /**
82
+ * Calculate grid bounds for initial map view
83
+ *
84
+ * @param grid - Coverage grid
85
+ * @returns Mapbox-compatible bounds [[west, south], [east, north]]
86
+ */
87
+ export function getGridBounds(grid) {
88
+ const bounds = grid.bounds;
89
+ return [
90
+ [bounds.west, bounds.south],
91
+ [bounds.east, bounds.north]
92
+ ];
93
+ }
94
+ /**
95
+ * Get signal strength range from grid
96
+ *
97
+ * @param grid - Coverage grid
98
+ * @returns [min, max] signal strength in dBm
99
+ */
100
+ export function getSignalRange(grid) {
101
+ let min = 0;
102
+ let max = -120;
103
+ for (const row of grid.cells) {
104
+ for (const cell of row) {
105
+ if (cell.quality !== 'no-signal') {
106
+ min = Math.min(min, cell.signalStrength);
107
+ max = Math.max(max, cell.signalStrength);
108
+ }
109
+ }
110
+ }
111
+ return [min, max];
112
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Coverage Data Store
3
+ *
4
+ * Self-contained store for coverage calculation data and state.
5
+ * Zero dependencies on cells/sites features - fully encapsulated.
6
+ */
7
+ import type { CoverageResult, CoverageConfig } from '../types';
8
+ export declare class CoverageDataStore {
9
+ result: CoverageResult | null;
10
+ calculating: boolean;
11
+ progress: number;
12
+ progressStage: string;
13
+ error: string | null;
14
+ private calculator;
15
+ constructor();
16
+ /**
17
+ * Calculate coverage prediction
18
+ * @param config - Complete RF configuration
19
+ */
20
+ calculateCoverage(config: CoverageConfig): Promise<void>;
21
+ /**
22
+ * Clear current coverage data
23
+ */
24
+ clearCoverage(): void;
25
+ /**
26
+ * Get grid cells for rendering
27
+ * Returns null if no result available
28
+ */
29
+ get gridCells(): import("../../../../core/CoverageMap").GridCell[][] | null;
30
+ /**
31
+ * Get coverage statistics
32
+ */
33
+ get stats(): import("../../../../core/CoverageMap").CoverageStats | null;
34
+ /**
35
+ * Get coverage configuration used
36
+ */
37
+ get config(): CoverageConfig | null;
38
+ /**
39
+ * Check if results are available
40
+ */
41
+ get hasResults(): boolean;
42
+ }
43
+ /**
44
+ * Factory function to create coverage data store
45
+ */
46
+ export declare function createCoverageDataStore(): CoverageDataStore;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Coverage Data Store
3
+ *
4
+ * Self-contained store for coverage calculation data and state.
5
+ * Zero dependencies on cells/sites features - fully encapsulated.
6
+ */
7
+ import { CoverageCalculator } from '../../../../core/CoverageMap';
8
+ export class CoverageDataStore {
9
+ // State
10
+ result = $state(null);
11
+ calculating = $state(false);
12
+ progress = $state(0);
13
+ progressStage = $state('');
14
+ error = $state(null);
15
+ // Calculator instance (reusable)
16
+ calculator;
17
+ constructor() {
18
+ this.calculator = new CoverageCalculator();
19
+ }
20
+ /**
21
+ * Calculate coverage prediction
22
+ * @param config - Complete RF configuration
23
+ */
24
+ async calculateCoverage(config) {
25
+ this.calculating = true;
26
+ this.progress = 0;
27
+ this.progressStage = 'Initializing';
28
+ this.error = null;
29
+ this.result = null;
30
+ try {
31
+ // Progress callback to update UI
32
+ const progressCallback = (update) => {
33
+ const cellsProcessed = update.cellsProcessed ?? 0;
34
+ const totalCells = update.totalCells ?? 1;
35
+ this.progress = Math.round((cellsProcessed / totalCells) * 100);
36
+ this.progressStage = update.stage;
37
+ console.log(`[CoverageDataStore] ${update.stage}: ${this.progress}%`);
38
+ };
39
+ // Calculate
40
+ console.log('[CoverageDataStore] Starting calculation with config:', config);
41
+ this.result = await this.calculator.calculate(config, progressCallback);
42
+ console.log('[CoverageDataStore] Calculation complete:', this.result);
43
+ this.progress = 100;
44
+ this.progressStage = 'Complete';
45
+ }
46
+ catch (err) {
47
+ console.error('[CoverageDataStore] Calculation failed:', err);
48
+ this.error = err instanceof Error ? err.message : 'Unknown calculation error';
49
+ this.result = null;
50
+ }
51
+ finally {
52
+ this.calculating = false;
53
+ }
54
+ }
55
+ /**
56
+ * Clear current coverage data
57
+ */
58
+ clearCoverage() {
59
+ this.result = null;
60
+ this.progress = 0;
61
+ this.progressStage = '';
62
+ this.error = null;
63
+ }
64
+ /**
65
+ * Get grid cells for rendering
66
+ * Returns null if no result available
67
+ */
68
+ get gridCells() {
69
+ return this.result?.grid.cells ?? null;
70
+ }
71
+ /**
72
+ * Get coverage statistics
73
+ */
74
+ get stats() {
75
+ return this.result?.grid.stats ?? null;
76
+ }
77
+ /**
78
+ * Get coverage configuration used
79
+ */
80
+ get config() {
81
+ return this.result?.config ?? null;
82
+ }
83
+ /**
84
+ * Check if results are available
85
+ */
86
+ get hasResults() {
87
+ return this.result !== null && this.result.grid.cells.length > 0;
88
+ }
89
+ }
90
+ /**
91
+ * Factory function to create coverage data store
92
+ */
93
+ export function createCoverageDataStore() {
94
+ return new CoverageDataStore();
95
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Coverage Display Store
3
+ *
4
+ * Controls visualization settings for coverage layer.
5
+ * Follows Map V3 pattern with localStorage persistence.
6
+ */
7
+ import type { CoverageColorScheme } from '../types';
8
+ export declare class CoverageDisplayStore {
9
+ key: string;
10
+ visible: boolean;
11
+ opacity: number;
12
+ colorScheme: CoverageColorScheme;
13
+ showLegend: boolean;
14
+ showLabels: boolean;
15
+ minSignalThreshold: number;
16
+ maxSignalThreshold: number;
17
+ zIndex: number;
18
+ constructor();
19
+ private loadFromStorage;
20
+ private saveToStorage;
21
+ /**
22
+ * Reset to defaults
23
+ */
24
+ reset(): void;
25
+ /**
26
+ * Toggle visibility
27
+ */
28
+ toggle(): void;
29
+ }
30
+ /**
31
+ * Factory function to create coverage display store
32
+ */
33
+ export declare function createCoverageDisplayStore(): CoverageDisplayStore;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Coverage Display Store
3
+ *
4
+ * Controls visualization settings for coverage layer.
5
+ * Follows Map V3 pattern with localStorage persistence.
6
+ */
7
+ import { browser } from '$app/environment';
8
+ export class CoverageDisplayStore {
9
+ key = 'map-v3-coverage-display';
10
+ // Visibility
11
+ visible = $state(true);
12
+ // Visual styling
13
+ opacity = $state(0.6);
14
+ colorScheme = $state('heatmap');
15
+ showLegend = $state(true);
16
+ showLabels = $state(false);
17
+ // Signal filtering (dBm)
18
+ minSignalThreshold = $state(-115); // Don't render below this
19
+ maxSignalThreshold = $state(-40); // Cap display at this
20
+ // Layer order
21
+ zIndex = $state(100); // Below cells/sites typically
22
+ constructor() {
23
+ if (browser) {
24
+ this.loadFromStorage();
25
+ // Auto-save on changes
26
+ $effect(() => {
27
+ this.saveToStorage();
28
+ });
29
+ }
30
+ }
31
+ loadFromStorage() {
32
+ const saved = localStorage.getItem(this.key);
33
+ if (saved) {
34
+ try {
35
+ const parsed = JSON.parse(saved);
36
+ this.visible = parsed.visible ?? true;
37
+ this.opacity = parsed.opacity ?? 0.6;
38
+ this.colorScheme = parsed.colorScheme ?? 'heatmap';
39
+ this.showLegend = parsed.showLegend ?? true;
40
+ this.showLabels = parsed.showLabels ?? false;
41
+ this.minSignalThreshold = parsed.minSignalThreshold ?? -115;
42
+ this.maxSignalThreshold = parsed.maxSignalThreshold ?? -40;
43
+ this.zIndex = parsed.zIndex ?? 100;
44
+ }
45
+ catch (e) {
46
+ console.error('[CoverageDisplayStore] Failed to load settings', e);
47
+ }
48
+ }
49
+ }
50
+ saveToStorage() {
51
+ if (!browser)
52
+ return;
53
+ const data = {
54
+ visible: this.visible,
55
+ opacity: this.opacity,
56
+ colorScheme: this.colorScheme,
57
+ showLegend: this.showLegend,
58
+ showLabels: this.showLabels,
59
+ minSignalThreshold: this.minSignalThreshold,
60
+ maxSignalThreshold: this.maxSignalThreshold,
61
+ zIndex: this.zIndex
62
+ };
63
+ localStorage.setItem(this.key, JSON.stringify(data));
64
+ }
65
+ /**
66
+ * Reset to defaults
67
+ */
68
+ reset() {
69
+ this.visible = true;
70
+ this.opacity = 0.6;
71
+ this.colorScheme = 'heatmap';
72
+ this.showLegend = true;
73
+ this.showLabels = false;
74
+ this.minSignalThreshold = -115;
75
+ this.maxSignalThreshold = -40;
76
+ this.zIndex = 100;
77
+ }
78
+ /**
79
+ * Toggle visibility
80
+ */
81
+ toggle() {
82
+ this.visible = !this.visible;
83
+ }
84
+ }
85
+ /**
86
+ * Factory function to create coverage display store
87
+ */
88
+ export function createCoverageDisplayStore() {
89
+ return new CoverageDisplayStore();
90
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Coverage Feature - Type Definitions
3
+ *
4
+ * Fully encapsulated coverage prediction and visualization types.
5
+ * Zero dependencies on cells/sites features - works standalone.
6
+ */
7
+ export type { CoverageResult, GridCell, CoverageGrid, CoverageStats, SignalQuality, SiteConfiguration, SectorConfig, PathLossModel, ProgressCallback, CoverageConfig, RFParameters, GridSettings, SignalThresholds, AntennaPattern } from '../../../core/CoverageMap';
8
+ /**
9
+ * Color scheme options for coverage visualization
10
+ */
11
+ export type CoverageColorScheme = 'heatmap' | 'quality' | 'viridis' | 'plasma' | 'categorical';
12
+ /**
13
+ * Signal strength range for filtering/coloring
14
+ */
15
+ export interface SignalRange {
16
+ min: number;
17
+ max: number;
18
+ label: string;
19
+ color: string;
20
+ }
21
+ /**
22
+ * Coverage layer display configuration
23
+ */
24
+ export interface CoverageDisplayConfig {
25
+ visible: boolean;
26
+ opacity: number;
27
+ colorScheme: CoverageColorScheme;
28
+ showLegend: boolean;
29
+ showLabels: boolean;
30
+ minSignalThreshold: number;
31
+ maxSignalThreshold: number;
32
+ }
33
+ /**
34
+ * GeoJSON feature properties for grid cells
35
+ */
36
+ export interface CoverageFeatureProperties {
37
+ signal: number;
38
+ quality: string;
39
+ color: string;
40
+ lat: number;
41
+ lon: number;
42
+ distance: number;
43
+ }
44
+ /**
45
+ * Optional helper to convert Cell to RFConfiguration
46
+ * Only needed if integrating with cells feature
47
+ */
48
+ export interface CellToRFConfigOptions {
49
+ defaultTxPower?: number;
50
+ defaultFrequency?: number;
51
+ defaultHeight?: number;
52
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Coverage Feature - Type Definitions
3
+ *
4
+ * Fully encapsulated coverage prediction and visualization types.
5
+ * Zero dependencies on cells/sites features - works standalone.
6
+ */
7
+ export {};
@@ -1,8 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { onDestroy, untrack } from 'svelte';
3
3
  import { MapControl } from '../../../shared';
4
- import { createTreeStore } from '../../../../core/TreeView/tree.store';
5
- import TreeView from '../../../../core/TreeView/TreeView.svelte';
4
+ import { createTreeStore, TreeView } from '../../../../core/TreeView';
6
5
  import type { RepeaterDataStore } from '../stores/repeater.data.svelte';
7
6
  import type { RepeaterRegistry } from '../stores/repeater.registry.svelte';
8
7
  import type { RepeaterDisplayStore } from '../stores/repeater.display.svelte';
@@ -38,25 +37,20 @@
38
37
  });
39
38
 
40
39
  $effect(() => {
41
- const unsubscribe = treeStore.subscribe((val) => {
42
- let changes = 0;
43
- val.state.nodes.forEach((nodeState) => {
44
- if (nodeState.node.children && nodeState.node.children.length > 0) return;
40
+ const val = treeStore;
41
+ let changes = 0;
42
+ val.state.nodes.forEach((nodeState) => {
43
+ if (nodeState.node.children && nodeState.node.children.length > 0) return;
45
44
 
46
- const groupId = nodeState.node.id;
47
- const isVisible = val.state.checkedPaths.has(nodeState.path);
48
-
49
- const currentStyle = registry.getStyle(groupId, '#000');
50
- if (currentStyle.visible !== isVisible) {
51
- registry.toggleVisibility(groupId);
52
- changes++;
53
- }
54
- });
45
+ const groupId = nodeState.node.id;
46
+ const isVisible = val.state.checkedPaths.has(nodeState.path);
47
+
48
+ const currentStyle = registry.getStyle(groupId, '#000');
49
+ if (currentStyle.visible !== isVisible) {
50
+ registry.toggleVisibility(groupId);
51
+ changes++;
52
+ }
55
53
  });
56
-
57
- return () => {
58
- unsubscribe();
59
- };
60
54
  });
61
55
 
62
56
  function handleColorChange(groupId: string, event: Event) {
@@ -124,7 +118,7 @@
124
118
 
125
119
  <div class="card-body p-0 overflow-auto" style="max-height: 400px;">
126
120
  <div class="p-2">
127
- <TreeView showControls={false} store={$treeStore}>
121
+ <TreeView showControls={false} store={treeStore}>
128
122
  {#snippet children({ node })}
129
123
  <div class="d-flex align-items-center justify-content-between w-100">
130
124