@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.
- package/dist/apps/antenna-pattern/index.d.ts +1 -0
- package/dist/apps/antenna-pattern/index.js +1 -0
- package/dist/apps/antenna-pattern/utils/load-static-antennas.d.ts +17 -0
- package/dist/apps/antenna-pattern/utils/load-static-antennas.js +83 -0
- package/dist/apps/site-check/SiteCheck.svelte +4 -6
- package/dist/core/Charts/ChartCard.svelte +122 -12
- package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
- package/dist/core/Charts/ChartComponent.svelte +8 -6
- package/dist/core/CoverageMap/ai/AITools.d.ts +117 -0
- package/dist/core/CoverageMap/ai/AITools.js +380 -0
- package/dist/core/CoverageMap/core/CoverageCalculator.d.ts +138 -0
- package/dist/core/CoverageMap/core/CoverageCalculator.js +375 -0
- package/dist/core/CoverageMap/core/GridCalculator.d.ts +115 -0
- package/dist/core/CoverageMap/core/GridCalculator.js +484 -0
- package/dist/core/CoverageMap/core/PathLossModels.d.ts +253 -0
- package/dist/core/CoverageMap/core/PathLossModels.js +380 -0
- package/dist/core/CoverageMap/core/SignalProcessor.d.ts +288 -0
- package/dist/core/CoverageMap/core/SignalProcessor.js +424 -0
- package/dist/core/CoverageMap/data/AntennaStore.d.ts +165 -0
- package/dist/core/CoverageMap/data/AntennaStore.js +327 -0
- package/dist/core/CoverageMap/data/SiteStore.d.ts +155 -0
- package/dist/core/CoverageMap/data/SiteStore.js +355 -0
- package/dist/core/CoverageMap/index.d.ts +74 -0
- package/dist/core/CoverageMap/index.js +103 -0
- package/dist/core/CoverageMap/types.d.ts +252 -0
- package/dist/core/CoverageMap/types.js +7 -0
- package/dist/core/CoverageMap/utils/geoUtils.d.ts +223 -0
- package/dist/core/CoverageMap/utils/geoUtils.js +374 -0
- package/dist/core/CoverageMap/utils/rfUtils.d.ts +329 -0
- package/dist/core/CoverageMap/utils/rfUtils.js +434 -0
- package/dist/core/CoverageMap/visualization/ColorSchemes.d.ts +149 -0
- package/dist/core/CoverageMap/visualization/ColorSchemes.js +377 -0
- package/dist/core/TreeView/index.d.ts +4 -4
- package/dist/core/TreeView/index.js +5 -5
- package/dist/core/TreeView/tree-utils.d.ts +12 -0
- package/dist/core/TreeView/tree-utils.js +115 -6
- package/dist/core/TreeView/tree.store.svelte.d.ts +94 -0
- package/dist/core/TreeView/tree.store.svelte.js +274 -0
- package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +16 -27
- package/dist/map-v2/features/cells/utils/cellGeoJSON.js +1 -0
- package/dist/map-v2/features/repeaters/controls/RepeaterFilterControl.svelte +33 -42
- package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +12 -19
- package/dist/map-v3/core/components/Map.svelte +4 -0
- package/dist/map-v3/core/stores/map.store.svelte.js +2 -0
- package/dist/map-v3/demo/DemoMap.svelte +31 -5
- package/dist/map-v3/demo/demo-cells.js +51 -22
- package/dist/map-v3/features/cells/components/CellFilterControl.svelte +24 -30
- package/dist/map-v3/features/cells/layers/CellsLayer.svelte +29 -9
- package/dist/map-v3/features/cells/logic/geometry.js +3 -0
- package/dist/map-v3/features/cells/stores/cell.data.svelte.d.ts +27 -0
- package/dist/map-v3/features/cells/stores/cell.data.svelte.js +65 -0
- package/dist/map-v3/features/coverage/index.d.ts +12 -0
- package/dist/map-v3/features/coverage/index.js +16 -0
- package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte +198 -0
- package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte.d.ts +10 -0
- package/dist/map-v3/features/coverage/logic/coloring.d.ts +28 -0
- package/dist/map-v3/features/coverage/logic/coloring.js +77 -0
- package/dist/map-v3/features/coverage/logic/geometry.d.ts +33 -0
- package/dist/map-v3/features/coverage/logic/geometry.js +112 -0
- package/dist/map-v3/features/coverage/stores/coverage.data.svelte.d.ts +46 -0
- package/dist/map-v3/features/coverage/stores/coverage.data.svelte.js +95 -0
- package/dist/map-v3/features/coverage/stores/coverage.display.svelte.d.ts +33 -0
- package/dist/map-v3/features/coverage/stores/coverage.display.svelte.js +90 -0
- package/dist/map-v3/features/coverage/types.d.ts +52 -0
- package/dist/map-v3/features/coverage/types.js +7 -0
- package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +14 -20
- package/dist/map-v3/features/selection/components/FeatureSelectionControl.svelte +82 -65
- package/dist/map-v3/features/selection/components/FeatureSelectionControl.svelte.d.ts +5 -9
- package/dist/map-v3/features/selection/index.d.ts +1 -2
- package/dist/map-v3/features/selection/index.js +0 -1
- package/dist/map-v3/features/selection/stores/selection.store.svelte.d.ts +44 -15
- package/dist/map-v3/features/selection/stores/selection.store.svelte.js +163 -40
- package/dist/map-v3/features/selection/types.d.ts +4 -2
- package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +23 -33
- package/dist/map-v3/index.d.ts +4 -0
- package/dist/map-v3/index.js +5 -0
- package/package.json +2 -2
- package/dist/core/TreeView/tree.store.d.ts +0 -10
- package/dist/core/TreeView/tree.store.js +0 -320
- package/dist/map-v3/features/selection/layers/SelectionHighlightLayers.svelte +0 -209
- 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
|
+
}
|
|
@@ -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
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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={
|
|
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
|
|