@smartnet360/svelte-components 0.0.118 → 0.0.120
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/components/AntennaDiagramsV2.svelte +412 -0
- package/dist/apps/antenna-pattern/components/AntennaDiagramsV2.svelte.d.ts +8 -0
- package/dist/apps/antenna-pattern/index.d.ts +3 -0
- package/dist/apps/antenna-pattern/index.js +4 -0
- package/dist/apps/antenna-pattern/types.d.ts +87 -0
- package/dist/apps/antenna-pattern/types.js +5 -0
- package/dist/apps/antenna-pattern/utils/antenna-helpers.d.ts +57 -0
- package/dist/apps/antenna-pattern/utils/antenna-helpers.js +140 -0
- package/dist/apps/antenna-tools/band-config.d.ts +53 -0
- package/dist/apps/antenna-tools/band-config.js +112 -0
- package/dist/apps/antenna-tools/components/AntennaControls.svelte +558 -0
- package/dist/apps/antenna-tools/components/AntennaControls.svelte.d.ts +16 -0
- package/dist/apps/antenna-tools/components/AntennaSettingsModal.svelte +304 -0
- package/dist/apps/antenna-tools/components/AntennaSettingsModal.svelte.d.ts +8 -0
- package/dist/apps/antenna-tools/components/AntennaTools.svelte +597 -0
- package/dist/apps/antenna-tools/components/AntennaTools.svelte.d.ts +42 -0
- package/dist/apps/antenna-tools/components/DatabaseViewer.svelte +278 -0
- package/dist/apps/antenna-tools/components/DatabaseViewer.svelte.d.ts +3 -0
- package/dist/apps/antenna-tools/components/DbNotification.svelte +67 -0
- package/dist/apps/antenna-tools/components/DbNotification.svelte.d.ts +18 -0
- package/dist/apps/antenna-tools/components/JsonImporter.svelte +115 -0
- package/dist/apps/antenna-tools/components/JsonImporter.svelte.d.ts +6 -0
- package/dist/apps/antenna-tools/components/MSIConverter.svelte +282 -0
- package/dist/apps/antenna-tools/components/MSIConverter.svelte.d.ts +6 -0
- package/dist/apps/antenna-tools/components/chart-engines/PolarAreaChart.svelte +123 -0
- package/dist/apps/antenna-tools/components/chart-engines/PolarAreaChart.svelte.d.ts +16 -0
- package/dist/apps/antenna-tools/components/chart-engines/PolarLineChart.svelte +123 -0
- package/dist/apps/antenna-tools/components/chart-engines/PolarLineChart.svelte.d.ts +16 -0
- package/dist/apps/antenna-tools/components/chart-engines/index.d.ts +9 -0
- package/dist/apps/antenna-tools/components/chart-engines/index.js +9 -0
- package/dist/apps/antenna-tools/components/index.d.ts +8 -0
- package/dist/apps/antenna-tools/components/index.js +10 -0
- package/dist/apps/antenna-tools/db.d.ts +28 -0
- package/dist/apps/antenna-tools/db.js +45 -0
- package/dist/apps/antenna-tools/index.d.ts +26 -0
- package/dist/apps/antenna-tools/index.js +40 -0
- package/dist/apps/antenna-tools/stores/antennas.d.ts +13 -0
- package/dist/apps/antenna-tools/stores/antennas.js +25 -0
- package/dist/apps/antenna-tools/stores/db-status.d.ts +32 -0
- package/dist/apps/antenna-tools/stores/db-status.js +38 -0
- package/dist/apps/antenna-tools/stores/index.d.ts +5 -0
- package/dist/apps/antenna-tools/stores/index.js +5 -0
- package/dist/apps/antenna-tools/types.d.ts +137 -0
- package/dist/apps/antenna-tools/types.js +16 -0
- package/dist/apps/antenna-tools/utils/antenna-helpers.d.ts +83 -0
- package/dist/apps/antenna-tools/utils/antenna-helpers.js +198 -0
- package/dist/apps/antenna-tools/utils/chart-engines/index.d.ts +5 -0
- package/dist/apps/antenna-tools/utils/chart-engines/index.js +5 -0
- package/dist/apps/antenna-tools/utils/chart-engines/polar-area-utils.d.ts +94 -0
- package/dist/apps/antenna-tools/utils/chart-engines/polar-area-utils.js +151 -0
- package/dist/apps/antenna-tools/utils/chart-engines/polar-line-utils.d.ts +93 -0
- package/dist/apps/antenna-tools/utils/chart-engines/polar-line-utils.js +139 -0
- package/dist/apps/antenna-tools/utils/db-utils.d.ts +50 -0
- package/dist/apps/antenna-tools/utils/db-utils.js +266 -0
- package/dist/apps/antenna-tools/utils/index.d.ts +7 -0
- package/dist/apps/antenna-tools/utils/index.js +7 -0
- package/dist/apps/antenna-tools/utils/msi-parser.d.ts +21 -0
- package/dist/apps/antenna-tools/utils/msi-parser.js +215 -0
- package/dist/apps/antenna-tools/utils/recent-antennas.d.ts +24 -0
- package/dist/apps/antenna-tools/utils/recent-antennas.js +64 -0
- package/package.json +1 -1
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
<svelte:options runes={true} />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import { onMount } from 'svelte';
|
|
5
|
+
import { loadAntennas } from '../utils/db-utils';
|
|
6
|
+
import type { Antenna } from '../db';
|
|
7
|
+
import type {
|
|
8
|
+
ViewMode,
|
|
9
|
+
PatternType,
|
|
10
|
+
PatternDisplayMode,
|
|
11
|
+
ChartEngineType,
|
|
12
|
+
AntennaCompareInit
|
|
13
|
+
} from '../types';
|
|
14
|
+
import {
|
|
15
|
+
findAntennaByName,
|
|
16
|
+
collectAvailableTilts,
|
|
17
|
+
findTiltIndex
|
|
18
|
+
} from '../utils/antenna-helpers';
|
|
19
|
+
import AntennaControls from './AntennaControls.svelte';
|
|
20
|
+
import AntennaSettingsModal from './AntennaSettingsModal.svelte';
|
|
21
|
+
import { PolarLineChart, PolarAreaChart } from './chart-engines/index';
|
|
22
|
+
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
// PROPS - Optional initialization from external sources
|
|
25
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
/** Initial configuration for comparison mode */
|
|
29
|
+
init?: AntennaCompareInit;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let { init }: Props = $props();
|
|
33
|
+
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
// STATE - Core reactive state
|
|
36
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
// Data
|
|
39
|
+
let antennas = $state<Antenna[]>([]);
|
|
40
|
+
let isLoading = $state(true);
|
|
41
|
+
let error = $state<string | null>(null);
|
|
42
|
+
|
|
43
|
+
// Antenna 1 selection
|
|
44
|
+
let selectedAntenna1 = $state<Antenna | null>(null);
|
|
45
|
+
let ant1ElectricalTiltIndex = $state(0);
|
|
46
|
+
let ant1MechanicalTilt = $state(0);
|
|
47
|
+
let ant1AvailableTilts = $state<string[]>(['0']);
|
|
48
|
+
|
|
49
|
+
// Antenna 2 selection
|
|
50
|
+
let selectedAntenna2 = $state<Antenna | null>(null);
|
|
51
|
+
let ant2ElectricalTiltIndex = $state(0);
|
|
52
|
+
let ant2MechanicalTilt = $state(0);
|
|
53
|
+
let ant2AvailableTilts = $state<string[]>(['0']);
|
|
54
|
+
|
|
55
|
+
// View settings
|
|
56
|
+
let viewMode = $state<ViewMode>('single');
|
|
57
|
+
let patternType = $state<PatternType>('vertical');
|
|
58
|
+
let displayMode = $state<PatternDisplayMode>('normalized');
|
|
59
|
+
let chartEngine = $state<ChartEngineType>('polar-line');
|
|
60
|
+
|
|
61
|
+
// Settings modal
|
|
62
|
+
let showSettingsModal = $state(false);
|
|
63
|
+
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
// DERIVED - Computed values
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/** Generate chart title based on current selection */
|
|
69
|
+
let chartTitle = $derived.by(() => {
|
|
70
|
+
if (viewMode === 'compare' && selectedAntenna1 && selectedAntenna2) {
|
|
71
|
+
const label1 = init?.label1 || selectedAntenna1.name;
|
|
72
|
+
const label2 = init?.label2 || selectedAntenna2.name;
|
|
73
|
+
return `${label1} vs ${label2}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (selectedAntenna1) {
|
|
77
|
+
const label = init?.label1 || selectedAntenna1.name;
|
|
78
|
+
return `${label} - Pattern Analysis`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return 'Antenna Pattern Analysis';
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
// INITIALIZATION
|
|
86
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
onMount(async () => {
|
|
89
|
+
try {
|
|
90
|
+
isLoading = true;
|
|
91
|
+
antennas = await loadAntennas();
|
|
92
|
+
|
|
93
|
+
if (antennas.length === 0) {
|
|
94
|
+
error = 'No antenna data found. Please load antenna files.';
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Initialize with provided config or defaults
|
|
99
|
+
initializeAntennas();
|
|
100
|
+
|
|
101
|
+
} catch (e) {
|
|
102
|
+
error = e instanceof Error ? e.message : 'Failed to load antenna data';
|
|
103
|
+
console.error('[AntennaDiagrams] Initialization error:', e);
|
|
104
|
+
} finally {
|
|
105
|
+
isLoading = false;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Initialize antenna selections from init props or defaults
|
|
111
|
+
*/
|
|
112
|
+
function initializeAntennas() {
|
|
113
|
+
// Set view mode from init or default
|
|
114
|
+
viewMode = init?.viewMode || 'single';
|
|
115
|
+
|
|
116
|
+
// Initialize Antenna 1
|
|
117
|
+
if (init?.antenna1Name) {
|
|
118
|
+
const result = findAntennaByName(antennas, init.antenna1Name);
|
|
119
|
+
selectedAntenna1 = result.antenna || antennas[0];
|
|
120
|
+
|
|
121
|
+
if (result.matchType === 'not-found') {
|
|
122
|
+
console.warn(`[AntennaDiagrams] Antenna 1 not found: "${init.antenna1Name}"`);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
selectedAntenna1 = antennas[0];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Collect available tilts for antenna 1
|
|
129
|
+
if (selectedAntenna1) {
|
|
130
|
+
ant1AvailableTilts = collectAvailableTilts(antennas, selectedAntenna1.name);
|
|
131
|
+
ant1ElectricalTiltIndex = findTiltIndex(ant1AvailableTilts, init?.etilt1 || 0);
|
|
132
|
+
ant1MechanicalTilt = init?.mtilt1 || 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Initialize Antenna 2
|
|
136
|
+
if (init?.antenna2Name) {
|
|
137
|
+
const result = findAntennaByName(antennas, init.antenna2Name);
|
|
138
|
+
selectedAntenna2 = result.antenna || (antennas.length > 1 ? antennas[1] : antennas[0]);
|
|
139
|
+
|
|
140
|
+
if (result.matchType === 'not-found') {
|
|
141
|
+
console.warn(`[AntennaDiagrams] Antenna 2 not found: "${init.antenna2Name}"`);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
selectedAntenna2 = antennas.length > 1 ? antennas[1] : antennas[0];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Collect available tilts for antenna 2
|
|
148
|
+
if (selectedAntenna2) {
|
|
149
|
+
ant2AvailableTilts = collectAvailableTilts(antennas, selectedAntenna2.name);
|
|
150
|
+
ant2ElectricalTiltIndex = findTiltIndex(ant2AvailableTilts, init?.etilt2 || 0);
|
|
151
|
+
ant2MechanicalTilt = init?.mtilt2 || 0;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
156
|
+
// EVENT HANDLERS
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
function handleAntenna1Change(antenna: Antenna | null) {
|
|
160
|
+
selectedAntenna1 = antenna;
|
|
161
|
+
if (antenna) {
|
|
162
|
+
ant1AvailableTilts = collectAvailableTilts(antennas, antenna.name);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function handleAntenna2Change(antenna: Antenna | null) {
|
|
167
|
+
selectedAntenna2 = antenna;
|
|
168
|
+
if (antenna) {
|
|
169
|
+
ant2AvailableTilts = collectAvailableTilts(antennas, antenna.name);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function handleTilt1Change(tiltIndex: number) {
|
|
174
|
+
ant1ElectricalTiltIndex = tiltIndex;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function handleTilt2Change(tiltIndex: number) {
|
|
178
|
+
ant2ElectricalTiltIndex = tiltIndex;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function handleMechTilt1Change(tilt: number) {
|
|
182
|
+
ant1MechanicalTilt = tilt;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function handleMechTilt2Change(tilt: number) {
|
|
186
|
+
ant2MechanicalTilt = tilt;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function handleDataRefresh() {
|
|
190
|
+
try {
|
|
191
|
+
antennas = await loadAntennas();
|
|
192
|
+
if (antennas.length > 0) {
|
|
193
|
+
selectedAntenna1 = antennas[0];
|
|
194
|
+
selectedAntenna2 = antennas.length > 1 ? antennas[1] : antennas[0];
|
|
195
|
+
ant1ElectricalTiltIndex = 0;
|
|
196
|
+
ant2ElectricalTiltIndex = 0;
|
|
197
|
+
ant1MechanicalTilt = 0;
|
|
198
|
+
ant2MechanicalTilt = 0;
|
|
199
|
+
}
|
|
200
|
+
} catch (e) {
|
|
201
|
+
console.error('[AntennaDiagrams] Failed to refresh data:', e);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
</script>
|
|
205
|
+
|
|
206
|
+
<!-- ═══════════════════════════════════════════════════════════════════════════ -->
|
|
207
|
+
<!-- TEMPLATE -->
|
|
208
|
+
<!-- ═══════════════════════════════════════════════════════════════════════════ -->
|
|
209
|
+
|
|
210
|
+
<div class="container-fluid mt-4">
|
|
211
|
+
|
|
212
|
+
{#if isLoading}
|
|
213
|
+
<!-- Loading State -->
|
|
214
|
+
<div class="text-center py-5">
|
|
215
|
+
<div class="spinner-border text-primary" role="status">
|
|
216
|
+
<span class="visually-hidden">Loading...</span>
|
|
217
|
+
</div>
|
|
218
|
+
<p class="mt-3 text-muted">Loading antenna data...</p>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
{:else if error}
|
|
222
|
+
<!-- Error State -->
|
|
223
|
+
<div class="alert alert-warning d-flex align-items-center" role="alert">
|
|
224
|
+
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
|
225
|
+
<div>
|
|
226
|
+
{error}
|
|
227
|
+
<button type="button" class="btn btn-sm btn-outline-primary ms-3" onclick={() => showSettingsModal = true}>
|
|
228
|
+
Load Antenna Data
|
|
229
|
+
</button>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
{:else}
|
|
234
|
+
<!-- Main Content -->
|
|
235
|
+
|
|
236
|
+
<!-- Control Bar -->
|
|
237
|
+
<div class="row mb-3 g-2">
|
|
238
|
+
|
|
239
|
+
<!-- View Mode -->
|
|
240
|
+
<div class="col-auto">
|
|
241
|
+
<div class="btn-group" role="group" aria-label="View mode">
|
|
242
|
+
<input type="radio" class="btn-check" id="viewSingle" bind:group={viewMode} value="single">
|
|
243
|
+
<label class="btn btn-outline-primary" for="viewSingle">
|
|
244
|
+
<i class="bi bi-square"></i> Single
|
|
245
|
+
</label>
|
|
246
|
+
<input type="radio" class="btn-check" id="viewCompare" bind:group={viewMode} value="compare">
|
|
247
|
+
<label class="btn btn-outline-primary" for="viewCompare">
|
|
248
|
+
<i class="bi bi-columns"></i> Compare
|
|
249
|
+
</label>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<!-- Chart Type -->
|
|
254
|
+
<div class="col-auto">
|
|
255
|
+
<div class="btn-group" role="group" aria-label="Chart type">
|
|
256
|
+
<input type="radio" class="btn-check" id="chartLine" bind:group={chartEngine} value="polar-line">
|
|
257
|
+
<label class="btn btn-outline-secondary" for="chartLine">Line</label>
|
|
258
|
+
<input type="radio" class="btn-check" id="chartArea" bind:group={chartEngine} value="polar-area">
|
|
259
|
+
<label class="btn btn-outline-secondary" for="chartArea">Area</label>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<!-- Display Mode -->
|
|
264
|
+
<div class="col-auto">
|
|
265
|
+
<div class="btn-group" role="group" aria-label="Display mode">
|
|
266
|
+
<input type="radio" class="btn-check" id="dispPattern" bind:group={displayMode} value="normalized">
|
|
267
|
+
<label class="btn btn-outline-secondary" for="dispPattern">Pattern</label>
|
|
268
|
+
<input type="radio" class="btn-check" id="dispGain" bind:group={displayMode} value="gain-adjusted">
|
|
269
|
+
<label class="btn btn-outline-secondary" for="dispGain">+Gain</label>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<!-- Pattern Type -->
|
|
274
|
+
<div class="col-auto">
|
|
275
|
+
<div class="btn-group" role="group" aria-label="Pattern type">
|
|
276
|
+
<input type="radio" class="btn-check" id="patHoriz" bind:group={patternType} value="horizontal">
|
|
277
|
+
<label class="btn btn-outline-secondary" for="patHoriz">Horizontal</label>
|
|
278
|
+
<input type="radio" class="btn-check" id="patVert" bind:group={patternType} value="vertical">
|
|
279
|
+
<label class="btn btn-outline-secondary" for="patVert">Vertical</label>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<!-- Spacer -->
|
|
284
|
+
<div class="col"></div>
|
|
285
|
+
|
|
286
|
+
<!-- Settings Button -->
|
|
287
|
+
<div class="col-auto">
|
|
288
|
+
<button
|
|
289
|
+
type="button"
|
|
290
|
+
class="btn btn-outline-secondary"
|
|
291
|
+
onclick={() => showSettingsModal = true}
|
|
292
|
+
aria-label="Antenna Settings"
|
|
293
|
+
>
|
|
294
|
+
<i class="bi bi-gear"></i>
|
|
295
|
+
</button>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<!-- Main Layout: Controls | Chart | Controls -->
|
|
300
|
+
<div class="row">
|
|
301
|
+
|
|
302
|
+
<!-- Antenna 1 Controls -->
|
|
303
|
+
<div class="col-lg-3 col-md-4">
|
|
304
|
+
<AntennaControls
|
|
305
|
+
{antennas}
|
|
306
|
+
selectedAntenna={selectedAntenna1}
|
|
307
|
+
antennaNumber={1}
|
|
308
|
+
electricalTiltIndex={ant1ElectricalTiltIndex}
|
|
309
|
+
mechanicalTilt={ant1MechanicalTilt}
|
|
310
|
+
colorTheme="primary"
|
|
311
|
+
onAntennaChange={handleAntenna1Change}
|
|
312
|
+
onElectricalTiltChange={handleTilt1Change}
|
|
313
|
+
onMechanicalTiltChange={handleMechTilt1Change}
|
|
314
|
+
/>
|
|
315
|
+
</div>
|
|
316
|
+
|
|
317
|
+
<!-- Chart -->
|
|
318
|
+
<div class="col-lg-6 col-md-4">
|
|
319
|
+
<div class="chart-card">
|
|
320
|
+
{#if chartEngine === 'polar-line'}
|
|
321
|
+
<PolarLineChart
|
|
322
|
+
selectedAntenna={selectedAntenna1}
|
|
323
|
+
selectedAntenna2={selectedAntenna2}
|
|
324
|
+
{viewMode}
|
|
325
|
+
{patternType}
|
|
326
|
+
patternDisplayMode={displayMode}
|
|
327
|
+
ant1ElectricalTilt={ant1ElectricalTiltIndex}
|
|
328
|
+
ant1MechanicalTilt={ant1MechanicalTilt}
|
|
329
|
+
ant2ElectricalTilt={ant2ElectricalTiltIndex}
|
|
330
|
+
ant2MechanicalTilt={ant2MechanicalTilt}
|
|
331
|
+
title={chartTitle}
|
|
332
|
+
/>
|
|
333
|
+
{:else if chartEngine === 'polar-area'}
|
|
334
|
+
<PolarAreaChart
|
|
335
|
+
selectedAntenna={selectedAntenna1}
|
|
336
|
+
selectedAntenna2={selectedAntenna2}
|
|
337
|
+
{viewMode}
|
|
338
|
+
{patternType}
|
|
339
|
+
patternDisplayMode={displayMode}
|
|
340
|
+
ant1ElectricalTilt={ant1ElectricalTiltIndex}
|
|
341
|
+
ant1MechanicalTilt={ant1MechanicalTilt}
|
|
342
|
+
ant2ElectricalTilt={ant2ElectricalTiltIndex}
|
|
343
|
+
ant2MechanicalTilt={ant2MechanicalTilt}
|
|
344
|
+
title={chartTitle}
|
|
345
|
+
/>
|
|
346
|
+
{/if}
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<!-- Antenna 2 Controls (Compare Mode) -->
|
|
351
|
+
<div class="col-lg-3 col-md-4">
|
|
352
|
+
{#if viewMode === 'compare'}
|
|
353
|
+
<AntennaControls
|
|
354
|
+
{antennas}
|
|
355
|
+
selectedAntenna={selectedAntenna2}
|
|
356
|
+
antennaNumber={2}
|
|
357
|
+
electricalTiltIndex={ant2ElectricalTiltIndex}
|
|
358
|
+
mechanicalTilt={ant2MechanicalTilt}
|
|
359
|
+
colorTheme="warning"
|
|
360
|
+
onAntennaChange={handleAntenna2Change}
|
|
361
|
+
onElectricalTiltChange={handleTilt2Change}
|
|
362
|
+
onMechanicalTiltChange={handleMechTilt2Change}
|
|
363
|
+
/>
|
|
364
|
+
{:else}
|
|
365
|
+
<!-- Placeholder to maintain layout -->
|
|
366
|
+
<div class="empty-placeholder"></div>
|
|
367
|
+
{/if}
|
|
368
|
+
</div>
|
|
369
|
+
</div>
|
|
370
|
+
{/if}
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<!-- Settings Modal -->
|
|
374
|
+
<AntennaSettingsModal
|
|
375
|
+
show={showSettingsModal}
|
|
376
|
+
onClose={() => showSettingsModal = false}
|
|
377
|
+
on:dataRefresh={handleDataRefresh}
|
|
378
|
+
/>
|
|
379
|
+
|
|
380
|
+
<!-- ═══════════════════════════════════════════════════════════════════════════ -->
|
|
381
|
+
<!-- STYLES -->
|
|
382
|
+
<!-- ═══════════════════════════════════════════════════════════════════════════ -->
|
|
383
|
+
|
|
384
|
+
<style>
|
|
385
|
+
.chart-card {
|
|
386
|
+
background: white;
|
|
387
|
+
border-radius: 12px;
|
|
388
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
389
|
+
padding: 0.5rem;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.empty-placeholder {
|
|
393
|
+
min-height: 200px;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* Bootstrap icon font (if not already loaded) */
|
|
397
|
+
.bi::before {
|
|
398
|
+
vertical-align: -0.125em;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* Enhanced button group styling */
|
|
402
|
+
.btn-group .btn {
|
|
403
|
+
font-size: 0.875rem;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/* Responsive adjustments */
|
|
407
|
+
@media (max-width: 992px) {
|
|
408
|
+
.chart-card {
|
|
409
|
+
margin-bottom: 1rem;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AntennaCompareInit } from '../types';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Initial configuration for comparison mode */
|
|
4
|
+
init?: AntennaCompareInit;
|
|
5
|
+
}
|
|
6
|
+
declare const AntennaDiagramsV2: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type AntennaDiagramsV2 = ReturnType<typeof AntennaDiagramsV2>;
|
|
8
|
+
export default AntennaDiagramsV2;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as PlotlyRadarChart } from './components/PlotlyRadarChart.svelte';
|
|
2
2
|
export { default as AntennaControls } from './components/AntennaControls.svelte';
|
|
3
3
|
export { default as AntennaDiagrams } from './components/AntennaDiagrams.svelte';
|
|
4
|
+
export { default as AntennaDiagramsV2 } from './components/AntennaDiagramsV2.svelte';
|
|
4
5
|
export { default as AntennaSettingsModal } from './components/AntennaSettingsModal.svelte';
|
|
5
6
|
export { default as JsonImporter } from './components/JsonImporter.svelte';
|
|
6
7
|
export { default as MSIConverter } from './components/MSIConverter.svelte';
|
|
@@ -10,8 +11,10 @@ export { PolarLineChart, PolarBarChart } from './components/chart-engines/index'
|
|
|
10
11
|
export { antennas, selectedAntenna, searchQuery, filteredAntennas } from './stores/antennas';
|
|
11
12
|
export { dbStatus, dataOperationStatus, updateDbStatus, trackDataOperation } from './stores/db-status';
|
|
12
13
|
export { db, type Antenna } from './db';
|
|
14
|
+
export * from './types';
|
|
13
15
|
export * from './utils/db-utils';
|
|
14
16
|
export * from './utils/init-db';
|
|
15
17
|
export * from './utils/msi-parser';
|
|
16
18
|
export * from './utils/plotly-chart-utils';
|
|
17
19
|
export * from './utils/load-static-antennas';
|
|
20
|
+
export * from './utils/antenna-helpers';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { default as PlotlyRadarChart } from './components/PlotlyRadarChart.svelte';
|
|
3
3
|
export { default as AntennaControls } from './components/AntennaControls.svelte';
|
|
4
4
|
export { default as AntennaDiagrams } from './components/AntennaDiagrams.svelte';
|
|
5
|
+
export { default as AntennaDiagramsV2 } from './components/AntennaDiagramsV2.svelte';
|
|
5
6
|
export { default as AntennaSettingsModal } from './components/AntennaSettingsModal.svelte';
|
|
6
7
|
export { default as JsonImporter } from './components/JsonImporter.svelte';
|
|
7
8
|
export { default as MSIConverter } from './components/MSIConverter.svelte';
|
|
@@ -14,9 +15,12 @@ export { antennas, selectedAntenna, searchQuery, filteredAntennas } from './stor
|
|
|
14
15
|
export { dbStatus, dataOperationStatus, updateDbStatus, trackDataOperation } from './stores/db-status';
|
|
15
16
|
// Database and types
|
|
16
17
|
export { db } from './db';
|
|
18
|
+
// Types
|
|
19
|
+
export * from './types';
|
|
17
20
|
// Utilities
|
|
18
21
|
export * from './utils/db-utils';
|
|
19
22
|
export * from './utils/init-db';
|
|
20
23
|
export * from './utils/msi-parser';
|
|
21
24
|
export * from './utils/plotly-chart-utils';
|
|
22
25
|
export * from './utils/load-static-antennas';
|
|
26
|
+
export * from './utils/antenna-helpers';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antenna Pattern Types
|
|
3
|
+
* Clean, centralized type definitions for the antenna pattern module
|
|
4
|
+
*/
|
|
5
|
+
import type { Antenna } from './db';
|
|
6
|
+
/** View mode for antenna diagrams */
|
|
7
|
+
export type ViewMode = 'single' | 'compare';
|
|
8
|
+
/** Pattern type for radiation display */
|
|
9
|
+
export type PatternType = 'horizontal' | 'vertical';
|
|
10
|
+
/** Display mode for pattern visualization */
|
|
11
|
+
export type PatternDisplayMode = 'normalized' | 'gain-adjusted';
|
|
12
|
+
/** Chart engine type */
|
|
13
|
+
export type ChartEngineType = 'polar-line' | 'polar-bar' | 'polar-area';
|
|
14
|
+
/** Color theme for antenna controls */
|
|
15
|
+
export type ColorTheme = 'primary' | 'warning' | 'success' | 'info' | 'secondary';
|
|
16
|
+
/**
|
|
17
|
+
* Antenna selection state - tracks antenna, tilts, and available options
|
|
18
|
+
*/
|
|
19
|
+
export interface AntennaSelection {
|
|
20
|
+
/** The selected antenna record */
|
|
21
|
+
antenna: Antenna | null;
|
|
22
|
+
/** Index into availableTilts array for electrical tilt */
|
|
23
|
+
electricalTiltIndex: number;
|
|
24
|
+
/** Mechanical tilt value in degrees */
|
|
25
|
+
mechanicalTilt: number;
|
|
26
|
+
/** Available electrical tilt values for this antenna model */
|
|
27
|
+
availableTilts: string[];
|
|
28
|
+
/** Available frequencies for this antenna model */
|
|
29
|
+
availableFrequencies: number[];
|
|
30
|
+
/** Custom label for display (e.g., cell name) */
|
|
31
|
+
label?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Props for initializing AntennaDiagrams from external sources (URL params, etc.)
|
|
35
|
+
*/
|
|
36
|
+
export interface AntennaCompareInit {
|
|
37
|
+
/** Antenna 1 name pattern to match */
|
|
38
|
+
antenna1Name?: string;
|
|
39
|
+
/** Antenna 2 name pattern to match */
|
|
40
|
+
antenna2Name?: string;
|
|
41
|
+
/** Electrical tilt VALUE for antenna 1 */
|
|
42
|
+
etilt1?: number;
|
|
43
|
+
/** Electrical tilt VALUE for antenna 2 */
|
|
44
|
+
etilt2?: number;
|
|
45
|
+
/** Mechanical tilt for antenna 1 */
|
|
46
|
+
mtilt1?: number;
|
|
47
|
+
/** Mechanical tilt for antenna 2 */
|
|
48
|
+
mtilt2?: number;
|
|
49
|
+
/** Initial view mode */
|
|
50
|
+
viewMode?: ViewMode;
|
|
51
|
+
/** Custom label for antenna 1 */
|
|
52
|
+
label1?: string;
|
|
53
|
+
/** Custom label for antenna 2 */
|
|
54
|
+
label2?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result of finding an antenna by name
|
|
58
|
+
*/
|
|
59
|
+
export interface AntennaSearchResult {
|
|
60
|
+
antenna: Antenna | null;
|
|
61
|
+
matchType: 'exact' | 'case-insensitive' | 'partial' | 'not-found';
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Complete state for the antenna diagram visualization
|
|
65
|
+
*/
|
|
66
|
+
export interface AntennaDiagramState {
|
|
67
|
+
/** All loaded antennas */
|
|
68
|
+
antennas: Antenna[];
|
|
69
|
+
/** First antenna selection */
|
|
70
|
+
selection1: AntennaSelection;
|
|
71
|
+
/** Second antenna selection (for compare mode) */
|
|
72
|
+
selection2: AntennaSelection;
|
|
73
|
+
/** Current view mode */
|
|
74
|
+
viewMode: ViewMode;
|
|
75
|
+
/** Current pattern type */
|
|
76
|
+
patternType: PatternType;
|
|
77
|
+
/** Current display mode */
|
|
78
|
+
displayMode: PatternDisplayMode;
|
|
79
|
+
/** Current chart engine */
|
|
80
|
+
chartEngine: ChartEngineType;
|
|
81
|
+
/** Whether data is loading */
|
|
82
|
+
isLoading: boolean;
|
|
83
|
+
/** Error message if any */
|
|
84
|
+
error: string | null;
|
|
85
|
+
}
|
|
86
|
+
/** Re-export Antenna type for convenience */
|
|
87
|
+
export type { Antenna } from './db';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antenna Data Utilities
|
|
3
|
+
* Helper functions for working with antenna data, tilts, and searches
|
|
4
|
+
*/
|
|
5
|
+
import type { Antenna, AntennaSearchResult } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Find an antenna by name with fallback matching strategies
|
|
8
|
+
* @param antennas - Array of all antennas
|
|
9
|
+
* @param name - Name pattern to search for
|
|
10
|
+
* @returns Search result with antenna and match type
|
|
11
|
+
*/
|
|
12
|
+
export declare function findAntennaByName(antennas: Antenna[], name: string): AntennaSearchResult;
|
|
13
|
+
/**
|
|
14
|
+
* Collect all available electrical tilts for an antenna model
|
|
15
|
+
* Searches all antennas with the same name and extracts unique tilt values
|
|
16
|
+
* @param antennas - Array of all antennas
|
|
17
|
+
* @param antennaName - The antenna model name
|
|
18
|
+
* @param frequency - Optional frequency to filter by
|
|
19
|
+
* @returns Sorted array of tilt values as strings
|
|
20
|
+
*/
|
|
21
|
+
export declare function collectAvailableTilts(antennas: Antenna[], antennaName: string, frequency?: number | null): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Collect all available frequencies for an antenna model
|
|
24
|
+
* @param antennas - Array of all antennas
|
|
25
|
+
* @param antennaName - The antenna model name
|
|
26
|
+
* @returns Sorted array of unique frequencies
|
|
27
|
+
*/
|
|
28
|
+
export declare function collectAvailableFrequencies(antennas: Antenna[], antennaName: string): number[];
|
|
29
|
+
/**
|
|
30
|
+
* Find the index of a tilt value in the available tilts array
|
|
31
|
+
* @param availableTilts - Array of available tilt values
|
|
32
|
+
* @param tiltValue - The tilt value to find (as number)
|
|
33
|
+
* @returns Index in the array, or 0 if not found
|
|
34
|
+
*/
|
|
35
|
+
export declare function findTiltIndex(availableTilts: string[], tiltValue: number): number;
|
|
36
|
+
/**
|
|
37
|
+
* Get the tilt value at a given index
|
|
38
|
+
* @param availableTilts - Array of available tilt values
|
|
39
|
+
* @param index - Index to retrieve
|
|
40
|
+
* @returns Tilt value as number
|
|
41
|
+
*/
|
|
42
|
+
export declare function getTiltValue(availableTilts: string[], index: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Find an antenna with specific name, frequency, and tilt
|
|
45
|
+
* @param antennas - Array of all antennas
|
|
46
|
+
* @param name - Antenna model name
|
|
47
|
+
* @param frequency - Target frequency (optional)
|
|
48
|
+
* @param tiltValue - Target tilt value
|
|
49
|
+
* @returns Matching antenna or null
|
|
50
|
+
*/
|
|
51
|
+
export declare function findAntennaWithTilt(antennas: Antenna[], name: string, frequency: number | null, tiltValue: string): Antenna | null;
|
|
52
|
+
/**
|
|
53
|
+
* Get unique antenna models (by name)
|
|
54
|
+
* @param antennas - Array of all antennas
|
|
55
|
+
* @returns Array of unique antenna names
|
|
56
|
+
*/
|
|
57
|
+
export declare function getUniqueAntennaModels(antennas: Antenna[]): string[];
|