@smartnet360/svelte-components 0.0.13 → 0.0.14

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 (21) hide show
  1. package/dist/apps/antenna-pattern/components/AntennaControls.svelte +38 -48
  2. package/dist/apps/antenna-pattern/components/AntennaDiagrams.svelte +138 -96
  3. package/dist/apps/antenna-pattern/components/chart-engines/PolarAreaChart.svelte +125 -0
  4. package/dist/apps/antenna-pattern/components/chart-engines/PolarAreaChart.svelte.d.ts +16 -0
  5. package/dist/apps/antenna-pattern/components/chart-engines/PolarBarChart.svelte +121 -0
  6. package/dist/apps/antenna-pattern/components/chart-engines/PolarBarChart.svelte.d.ts +15 -0
  7. package/dist/apps/antenna-pattern/components/chart-engines/PolarLineChart.svelte +125 -0
  8. package/dist/apps/antenna-pattern/components/chart-engines/PolarLineChart.svelte.d.ts +16 -0
  9. package/dist/apps/antenna-pattern/components/chart-engines/index.d.ts +9 -0
  10. package/dist/apps/antenna-pattern/components/chart-engines/index.js +8 -0
  11. package/dist/apps/antenna-pattern/index.d.ts +1 -0
  12. package/dist/apps/antenna-pattern/index.js +2 -0
  13. package/dist/apps/antenna-pattern/utils/chart-engines/polar-area-utils.d.ts +89 -0
  14. package/dist/apps/antenna-pattern/utils/chart-engines/polar-area-utils.js +146 -0
  15. package/dist/apps/antenna-pattern/utils/chart-engines/polar-bar-utils.d.ts +88 -0
  16. package/dist/apps/antenna-pattern/utils/chart-engines/polar-bar-utils.js +131 -0
  17. package/dist/apps/antenna-pattern/utils/chart-engines/polar-line-utils.d.ts +88 -0
  18. package/dist/apps/antenna-pattern/utils/chart-engines/polar-line-utils.js +134 -0
  19. package/dist/apps/antenna-pattern/utils/recent-antennas.d.ts +20 -0
  20. package/dist/apps/antenna-pattern/utils/recent-antennas.js +60 -0
  21. package/package.json +1 -1
@@ -2,6 +2,7 @@
2
2
 
3
3
  <script lang="ts">
4
4
  import type { Antenna } from '../db';
5
+ import { sortAntennasWithRecent, addToRecentAntennas } from '../utils/recent-antennas';
5
6
 
6
7
  interface Props {
7
8
  antennas?: Antenna[];
@@ -47,9 +48,7 @@
47
48
  $effect(() => {
48
49
  // Only update internal state if the prop actually changed
49
50
  // Avoid overwriting user selections
50
- console.log(`[Antenna ${antennaNumber}] Effect triggered - selectedAntenna prop:`, selectedAntenna?.name || 'null', 'internal:', internalSelectedAntenna?.name || 'null');
51
51
  if (selectedAntenna !== internalSelectedAntenna) {
52
- console.log(`[Antenna ${antennaNumber}] Effect updating internal state from:`, internalSelectedAntenna?.name || 'null', 'to:', selectedAntenna?.name || 'null');
53
52
  internalSelectedAntenna = selectedAntenna;
54
53
  }
55
54
  });
@@ -88,33 +87,17 @@
88
87
 
89
88
  // Find the specific antenna that matches name, frequency, and electrical tilt
90
89
  function findAntennaWithTilt(antennaName: string, tiltIndex: number): Antenna | null {
91
- console.log(`[Antenna ${antennaNumber}] findAntennaWithTilt called with:`, antennaName, 'tiltIndex:', tiltIndex);
92
-
93
- if (!antennaName) {
94
- console.log(`[Antenna ${antennaNumber}] No antennaName provided, returning null`);
95
- return null;
96
- }
90
+ if (!antennaName) return null;
97
91
 
98
92
  // Handle case where availableElectricalTilts might not be populated yet
99
93
  const targetTilt = availableElectricalTilts[tiltIndex] || '0';
100
- console.log(`[Antenna ${antennaNumber}] availableElectricalTilts:`, availableElectricalTilts);
101
- console.log(`[Antenna ${antennaNumber}] targetTilt:`, targetTilt);
102
- console.log(`[Antenna ${antennaNumber}] selectedFrequency:`, selectedFrequency);
103
94
 
104
95
  // Find antenna with matching name, frequency, and electrical tilt
105
- const result = antennas.find(antenna => {
106
- console.log(`[Antenna ${antennaNumber}] Checking antenna:`, antenna.name, 'freq:', antenna.frequency, 'tilt:', antenna.tilt);
107
-
108
- if (antenna.name !== antennaName) {
109
- console.log(`[Antenna ${antennaNumber}] Name mismatch:`, antenna.name, '!==', antennaName);
110
- return false;
111
- }
96
+ return antennas.find(antenna => {
97
+ if (antenna.name !== antennaName) return false;
112
98
 
113
99
  // If frequency is selected, must match
114
- if (selectedFrequency && antenna.frequency !== selectedFrequency) {
115
- console.log(`[Antenna ${antennaNumber}] Frequency mismatch:`, antenna.frequency, '!==', selectedFrequency);
116
- return false;
117
- }
100
+ if (selectedFrequency && antenna.frequency !== selectedFrequency) return false;
118
101
 
119
102
  if (antenna.tilt) {
120
103
  const tiltString = antenna.tilt.toString();
@@ -122,19 +105,11 @@
122
105
  ? tiltString.split(',').map(t => t.trim())
123
106
  : [tiltString];
124
107
 
125
- console.log(`[Antenna ${antennaNumber}] Antenna tilts:`, antennasTilts, 'target:', targetTilt);
126
- const tiltMatch = antennasTilts.includes(targetTilt);
127
- console.log(`[Antenna ${antennaNumber}] Tilt match:`, tiltMatch);
128
- return tiltMatch;
108
+ return antennasTilts.includes(targetTilt);
129
109
  }
130
110
 
131
- const defaultMatch = targetTilt === '0';
132
- console.log(`[Antenna ${antennaNumber}] Default tilt match:`, defaultMatch);
133
- return defaultMatch; // Default tilt
111
+ return targetTilt === '0'; // Default tilt
134
112
  }) || null;
135
-
136
- console.log(`[Antenna ${antennaNumber}] findAntennaWithTilt result:`, result?.name || 'null');
137
- return result;
138
113
  }
139
114
 
140
115
  // Handle frequency selection
@@ -160,9 +135,6 @@
160
135
  const target = event.target as HTMLSelectElement;
161
136
  const antennaName = target.value;
162
137
 
163
- console.log(`[Antenna ${antennaNumber}] handleAntennaChange called with:`, antennaName);
164
- console.log(`[Antenna ${antennaNumber}] Before change - internalSelectedAntenna:`, internalSelectedAntenna?.name || 'null');
165
-
166
138
  // Reset tilt and frequency values when antenna changes
167
139
  internalElectricalTiltIndex = 0;
168
140
  internalMechanicalTilt = 0;
@@ -170,12 +142,10 @@
170
142
 
171
143
  // Handle "Select Antenna" case (empty string)
172
144
  if (!antennaName) {
173
- console.log(`[Antenna ${antennaNumber}] Setting to null (Select Antenna case)`);
174
145
  internalSelectedAntenna = null;
175
146
  onAntennaChange?.(null);
176
147
  onElectricalTiltChange?.(0);
177
148
  onMechanicalTiltChange?.(0);
178
- console.log(`[Antenna ${antennaNumber}] After null set - internalSelectedAntenna:`, internalSelectedAntenna?.name || 'null');
179
149
  return;
180
150
  }
181
151
 
@@ -191,9 +161,6 @@
191
161
  let tiltToUse = tilts.includes('0') ? '0' : tilts[0];
192
162
  let tiltIndexToUse = tilts.includes('0') ? tilts.indexOf('0') : 0;
193
163
 
194
- console.log(`[Antenna ${antennaNumber}] Available tilts for ${antennaName}:`, tilts);
195
- console.log(`[Antenna ${antennaNumber}] Using tilt:`, tiltToUse, 'at index:', tiltIndexToUse);
196
-
197
164
  // Find the specific antenna with the chosen tilt
198
165
  const newAntenna = antennas.find(antenna => {
199
166
  if (antenna.name !== antennaName) return false;
@@ -207,21 +174,23 @@
207
174
  return tiltToUse === '0';
208
175
  });
209
176
 
210
- console.log(`[Antenna ${antennaNumber}] Found antenna with tilt ${tiltToUse}:`, newAntenna?.name || 'null');
211
177
  internalSelectedAntenna = newAntenna || null;
212
178
  internalElectricalTiltIndex = tiltIndexToUse;
213
179
 
214
180
  } else {
215
181
  // Fallback: use findAntennaWithTilt with index 0
216
182
  const newAntenna = findAntennaWithTilt(antennaName, 0);
217
- console.log(`[Antenna ${antennaNumber}] Fallback - Found antenna:`, newAntenna?.name || 'null');
218
183
  internalSelectedAntenna = newAntenna;
219
184
  }
220
185
 
221
186
  onAntennaChange?.(internalSelectedAntenna);
222
187
  onElectricalTiltChange?.(internalElectricalTiltIndex);
223
188
  onMechanicalTiltChange?.(0);
224
- console.log(`[Antenna ${antennaNumber}] After set - internalSelectedAntenna:`, internalSelectedAntenna?.name || 'null');
189
+
190
+ // Track antenna selection in recent list
191
+ if (internalSelectedAntenna) {
192
+ addToRecentAntennas(internalSelectedAntenna);
193
+ }
225
194
  }
226
195
 
227
196
  // Handle electrical tilt changes
@@ -300,6 +269,9 @@
300
269
 
301
270
  // Get unique antennas (by name, not by individual DB entries with different tilts)
302
271
  let uniqueAntennas = $state<Antenna[]>([]);
272
+ let recentAntennas = $state<Antenna[]>([]);
273
+ let otherAntennas = $state<Antenna[]>([]);
274
+
303
275
  $effect(() => {
304
276
  if (antennas.length > 0) {
305
277
  // Group antennas by name and take the first one from each group
@@ -309,7 +281,13 @@
309
281
  antennaMap.set(antenna.name, antenna);
310
282
  }
311
283
  });
312
- uniqueAntennas = Array.from(antennaMap.values()).sort((a, b) => a.name.localeCompare(b.name));
284
+ const allUniqueAntennas = Array.from(antennaMap.values()).sort((a, b) => a.name.localeCompare(b.name));
285
+
286
+ // Sort with recent antennas first
287
+ const { recent, others } = sortAntennasWithRecent(allUniqueAntennas);
288
+ recentAntennas = recent;
289
+ otherAntennas = others;
290
+ uniqueAntennas = [...recent, ...others];
313
291
  }
314
292
  });
315
293
  </script>
@@ -330,12 +308,24 @@
330
308
  class="form-select form-select-sm"
331
309
  value={internalSelectedAntenna?.name || ''}
332
310
  onchange={handleAntennaChange}
333
- onfocus={() => console.log(`[Antenna ${antennaNumber}] Dropdown focused - current value:`, internalSelectedAntenna?.name || 'null')}
334
311
  >
335
312
  <option value="">-- Select Antenna --</option>
336
- {#each uniqueAntennas as antenna}
337
- <option value={antenna.name}>{antenna.name}</option>
338
- {/each}
313
+
314
+ <!-- Recent Antennas -->
315
+ {#if recentAntennas.length > 0}
316
+ <optgroup label="Recent">
317
+ {#each recentAntennas as antenna}
318
+ <option value={antenna.name}>▸ {antenna.name}</option>
319
+ {/each}
320
+ </optgroup>
321
+ {/if}
322
+
323
+ <!-- All Other Antennas -->
324
+ <optgroup label="All Antennas">
325
+ {#each otherAntennas as antenna}
326
+ <option value={antenna.name}>{antenna.name}</option>
327
+ {/each}
328
+ </optgroup>
339
329
  </select>
340
330
  {#if internalSelectedAntenna}
341
331
  <small class="text-muted mt-1 d-block">
@@ -2,25 +2,18 @@
2
2
 
3
3
  <script lang="ts">
4
4
  import { onMount } from 'svelte';
5
- import { browser } from '$app/environment';
6
5
  import { loadAntennas } from '../utils/db-utils';
7
6
  import type { Antenna } from '../db';
8
7
  import AntennaControls from './AntennaControls.svelte';
9
8
  import AntennaSettingsModal from './AntennaSettingsModal.svelte';
10
- import {
11
- createAntennaChartData,
12
- createChartLayout,
13
- createChartConfig,
14
- generateChartTitle,
15
- type PlotlyTraceData
16
- } from '../utils/plotly-chart-utils';
17
-
18
- let Plotly: any;
19
- let chartDiv = $state<HTMLDivElement>();
9
+ import { PolarLineChart, PolarBarChart, PolarAreaChart } from './chart-engines/index';
10
+
11
+ // Chart engine types
12
+ type ChartEngineType = 'polar-line' | 'polar-bar' | 'polar-area';
13
+
20
14
  let antennas = $state<Antenna[]>([]);
21
15
  let selectedAntenna = $state<Antenna | null>(null);
22
16
  let selectedAntenna2 = $state<Antenna | null>(null);
23
- let chartInitialized = $state(false);
24
17
 
25
18
  // External Bootstrap slider values
26
19
  let ant1ElectricalTilt = $state(0);
@@ -31,6 +24,12 @@
31
24
  // Viewing mode and pattern visibility
32
25
  let viewMode = $state<'single' | 'compare'>('single');
33
26
  let patternType = $state<'horizontal' | 'vertical'>('vertical');
27
+
28
+ // Chart engine selection
29
+ let chartEngine = $state<ChartEngineType>('polar-line');
30
+
31
+ // Pattern display mode - normalized vs gain-adjusted
32
+ let patternDisplayMode = $state<'normalized' | 'gain-adjusted'>('normalized');
34
33
 
35
34
  // Settings modal state
36
35
  let showSettingsModal = $state(false);
@@ -118,89 +117,38 @@
118
117
  }
119
118
  }
120
119
 
121
- // Watch for slider changes and update chart
122
- $effect(() => {
123
- if (chartInitialized) {
124
- updateChart();
125
- }
126
- });
127
-
128
120
  onMount(async () => {
129
- if (browser) {
130
- try {
131
- // Load Plotly and antenna data
132
- Plotly = await import('plotly.js-dist-min');
133
- antennas = await loadAntennas();
121
+ try {
122
+ // Load antenna data
123
+ antennas = await loadAntennas();
134
124
 
135
- if (antennas.length > 0) {
136
- // Set default antenna selection for antenna 1
137
- selectedAntenna = antennas[0];
138
- if (selectedAntenna.tilt) {
139
- availableElectricalTilts = selectedAntenna.tilt.split(',').map(t => t.trim());
140
- }
141
-
142
- // Set default antenna selection for antenna 2 (for compare mode)
143
- if (antennas.length > 1) {
144
- selectedAntenna2 = antennas[1];
145
- } else {
146
- selectedAntenna2 = antennas[0]; // Use same antenna if only one available
147
- }
148
-
149
- await initializeChart();
125
+ if (antennas.length > 0) {
126
+ // Set default antenna selection for antenna 1
127
+ selectedAntenna = antennas[0];
128
+ if (selectedAntenna.tilt) {
129
+ availableElectricalTilts = selectedAntenna.tilt.split(',').map(t => t.trim());
130
+ }
131
+
132
+ // Set default antenna selection for antenna 2 (for compare mode)
133
+ if (antennas.length > 1) {
134
+ selectedAntenna2 = antennas[1];
135
+ } else {
136
+ selectedAntenna2 = antennas[0]; // Use same antenna if only one available
150
137
  }
151
- } catch (error) {
152
- console.error('Failed to initialize:', error);
153
138
  }
154
- }
155
- });
156
-
157
- async function initializeChart() {
158
- if (!Plotly || !chartDiv) return;
159
-
160
- const data = createAntennaChartData(
161
- selectedAntenna,
162
- selectedAntenna2,
163
- viewMode,
164
- patternType === 'horizontal',
165
- patternType === 'vertical',
166
- ant1ElectricalTilt,
167
- ant1MechanicalTilt,
168
- ant2ElectricalTilt,
169
- ant2MechanicalTilt
170
- );
171
- const title = generateChartTitle(viewMode, selectedAntenna, selectedAntenna2);
172
- const layout = createChartLayout(title);
173
- const config = createChartConfig();
174
-
175
- try {
176
- await Plotly.newPlot(chartDiv, data, layout, config);
177
- chartInitialized = true;
178
- console.log('Chart initialized with antenna controls');
179
139
  } catch (error) {
180
- console.error('Failed to create chart:', error);
140
+ console.error('Failed to initialize:', error);
181
141
  }
182
- }
183
-
184
- async function updateChart() {
185
- if (!Plotly || !chartDiv || !chartInitialized) return;
142
+ });
186
143
 
187
- try {
188
- const data = createAntennaChartData(
189
- selectedAntenna,
190
- selectedAntenna2,
191
- viewMode,
192
- patternType === 'horizontal',
193
- patternType === 'vertical',
194
- ant1ElectricalTilt,
195
- ant1MechanicalTilt,
196
- ant2ElectricalTilt,
197
- ant2MechanicalTilt
198
- );
199
- const title = generateChartTitle(viewMode, selectedAntenna, selectedAntenna2);
200
- await Plotly.react(chartDiv, data, createChartLayout(title));
201
- } catch (error) {
202
- console.error('Failed to update chart:', error);
144
+ // Generate chart title based on current selection
145
+ function generateChartTitle(): string {
146
+ if (viewMode === 'compare' && selectedAntenna && selectedAntenna2) {
147
+ return `${selectedAntenna.name} vs ${selectedAntenna2.name}`;
148
+ } else if (selectedAntenna) {
149
+ return `${selectedAntenna.name} - Pattern Analysis`;
203
150
  }
151
+ return 'Antenna Pattern Analysis';
204
152
  }
205
153
  </script>
206
154
 
@@ -208,10 +156,10 @@
208
156
 
209
157
 
210
158
  <!-- Viewing Mode and Pattern Visibility Controls -->
211
- <div class="row mb-4">
212
- <div class="col-md-4">
213
- <div class="form-label">Viewing Mode:</div>
214
- <div class="btn-group w-100" role="group" aria-label="Viewing mode selection">
159
+ <div class="row mb-3">
160
+ <div class="col-md-2">
161
+ <div class="form-label">View Mode:</div>
162
+ <div class="btn-group w-100" role="group" aria-label="View mode selection">
215
163
  <input
216
164
  type="radio"
217
165
  class="btn-check"
@@ -219,7 +167,7 @@
219
167
  bind:group={viewMode}
220
168
  value="single"
221
169
  >
222
- <label class="btn btn-outline-primary" for="singleMode">Single Antenna</label>
170
+ <label class="btn btn-outline-primary" for="singleMode">Single</label>
223
171
 
224
172
  <input
225
173
  type="radio"
@@ -232,7 +180,62 @@
232
180
  </div>
233
181
  </div>
234
182
 
235
- <div class="col-md-4">
183
+ <div class="col-md-2">
184
+ <div class="form-label">Chart Type:</div>
185
+ <div class="btn-group w-100" role="group" aria-label="Chart type selection">
186
+ <input
187
+ type="radio"
188
+ class="btn-check"
189
+ id="polarLineChart"
190
+ bind:group={chartEngine}
191
+ value="polar-line"
192
+ >
193
+ <label class="btn btn-outline-primary" for="polarLineChart">Line</label>
194
+
195
+ <!-- <input
196
+ type="radio"
197
+ class="btn-check"
198
+ id="polarBarChart"
199
+ bind:group={chartEngine}
200
+ value="polar-bar"
201
+ >
202
+ <label class="btn btn-outline-success" for="polarBarChart">Bar</label> -->
203
+
204
+ <input
205
+ type="radio"
206
+ class="btn-check"
207
+ id="polarAreaChart"
208
+ bind:group={chartEngine}
209
+ value="polar-area"
210
+ >
211
+ <label class="btn btn-outline-primary" for="polarAreaChart">Area</label>
212
+ </div>
213
+ </div>
214
+
215
+ <div class="col-md-3">
216
+ <div class="form-label">Display Mode:</div>
217
+ <div class="btn-group w-100" role="group" aria-label="Pattern display mode selection">
218
+ <input
219
+ type="radio"
220
+ class="btn-check"
221
+ id="normalizedMode"
222
+ bind:group={patternDisplayMode}
223
+ value="normalized"
224
+ >
225
+ <label class="btn btn-outline-primary" for="normalizedMode">Pattern</label>
226
+
227
+ <input
228
+ type="radio"
229
+ class="btn-check"
230
+ id="gainAdjustedMode"
231
+ bind:group={patternDisplayMode}
232
+ value="gain-adjusted"
233
+ >
234
+ <label class="btn btn-outline-primary" for="gainAdjustedMode">+Gain</label>
235
+ </div>
236
+ </div>
237
+
238
+ <div class="col-md-2">
236
239
  <div class="form-label">Pattern Type:</div>
237
240
  <div class="btn-group w-100" role="group" aria-label="Pattern type selection">
238
241
  <input
@@ -255,7 +258,7 @@
255
258
  </div>
256
259
  </div>
257
260
 
258
- <div class="col-md-4">
261
+ <div class="col-md-3">
259
262
  <div class="form-label">Actions:</div>
260
263
  <button
261
264
  type="button"
@@ -284,11 +287,50 @@
284
287
  />
285
288
  </div>
286
289
 
287
- <!-- Center Column - Chart (always centered) -->
290
+ <!-- Center Column - Chart Engine (always centered) -->
288
291
  <div class="col-md-6">
289
292
  <div class="card">
290
293
  <div class="card-body p-1">
291
- <div bind:this={chartDiv} style="height: 700px;"></div>
294
+ {#if chartEngine === 'polar-line'}
295
+ <PolarLineChart
296
+ {selectedAntenna}
297
+ {selectedAntenna2}
298
+ {viewMode}
299
+ {patternType}
300
+ {patternDisplayMode}
301
+ {ant1ElectricalTilt}
302
+ {ant1MechanicalTilt}
303
+ {ant2ElectricalTilt}
304
+ {ant2MechanicalTilt}
305
+ title={generateChartTitle()}
306
+ />
307
+ {:else if chartEngine === 'polar-bar'}
308
+ <PolarBarChart
309
+ {selectedAntenna}
310
+ {selectedAntenna2}
311
+ {viewMode}
312
+ {patternType}
313
+ {patternDisplayMode}
314
+ {ant1ElectricalTilt}
315
+ {ant1MechanicalTilt}
316
+ {ant2ElectricalTilt}
317
+ {ant2MechanicalTilt}
318
+ title={generateChartTitle()}
319
+ />
320
+ {:else if chartEngine === 'polar-area'}
321
+ <PolarAreaChart
322
+ {selectedAntenna}
323
+ {selectedAntenna2}
324
+ {viewMode}
325
+ {patternType}
326
+ {patternDisplayMode}
327
+ {ant1ElectricalTilt}
328
+ {ant1MechanicalTilt}
329
+ {ant2ElectricalTilt}
330
+ {ant2MechanicalTilt}
331
+ title={generateChartTitle()}
332
+ />
333
+ {/if}
292
334
  </div>
293
335
  </div>
294
336
  </div>
@@ -0,0 +1,125 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import { onMount } from 'svelte';
5
+ import { browser } from '$app/environment';
6
+ import type { Antenna } from '../../db';
7
+ import {
8
+ createPolarAreaChartData,
9
+ createPolarAreaLayout,
10
+ type PolarAreaTraceData
11
+ } from '../../utils/chart-engines/polar-area-utils';
12
+
13
+ interface Props {
14
+ selectedAntenna?: Antenna | null;
15
+ selectedAntenna2?: Antenna | null;
16
+ viewMode?: 'single' | 'compare';
17
+ patternType?: 'horizontal' | 'vertical';
18
+ patternDisplayMode?: 'normalized' | 'gain-adjusted';
19
+ ant1ElectricalTilt?: number;
20
+ ant1MechanicalTilt?: number;
21
+ ant2ElectricalTilt?: number;
22
+ ant2MechanicalTilt?: number;
23
+ title?: string;
24
+ }
25
+
26
+ let {
27
+ selectedAntenna = null,
28
+ selectedAntenna2 = null,
29
+ viewMode = 'single',
30
+ patternType = 'vertical',
31
+ patternDisplayMode = 'normalized',
32
+ ant1ElectricalTilt = 0,
33
+ ant1MechanicalTilt = 0,
34
+ ant2ElectricalTilt = 0,
35
+ ant2MechanicalTilt = 0,
36
+ title = 'Antenna Pattern - Polar Area Chart'
37
+ }: Props = $props();
38
+
39
+ let Plotly: any;
40
+ let chartDiv = $state<HTMLDivElement>();
41
+ let chartInitialized = $state(false);
42
+
43
+ // Initialize Plotly on mount
44
+ onMount(async () => {
45
+ if (browser) {
46
+ try {
47
+ Plotly = await import('plotly.js-dist-min');
48
+ console.log('Plotly loaded for polar area chart');
49
+ await initializeChart();
50
+ } catch (error) {
51
+ console.error('Failed to load Plotly:', error);
52
+ }
53
+ }
54
+ });
55
+
56
+ // Update chart when data changes
57
+ $effect(() => {
58
+ if (chartInitialized) {
59
+ updateChart();
60
+ }
61
+ });
62
+
63
+ async function initializeChart() {
64
+ if (!Plotly || !chartDiv) return;
65
+
66
+ const data = createPolarAreaChartData(
67
+ selectedAntenna,
68
+ selectedAntenna2,
69
+ viewMode,
70
+ patternType === 'horizontal',
71
+ patternType === 'vertical',
72
+ ant1ElectricalTilt,
73
+ ant1MechanicalTilt,
74
+ ant2ElectricalTilt,
75
+ ant2MechanicalTilt,
76
+ patternDisplayMode
77
+ );
78
+
79
+ const layout = createPolarAreaLayout(title);
80
+ const config = {
81
+ responsive: true,
82
+ displayModeBar: true,
83
+ displaylogo: false,
84
+ modeBarButtonsToRemove: [
85
+ 'zoom2d', 'pan2d', 'select2d', 'lasso2d',
86
+ 'zoomIn2d', 'zoomOut2d', 'autoScale2d',
87
+ 'resetScale2d', 'toggleSpikelines', 'toImage'
88
+ ]
89
+ };
90
+
91
+ try {
92
+ await Plotly.newPlot(chartDiv, data, layout, config);
93
+ chartInitialized = true;
94
+ console.log('Polar area chart initialized');
95
+ } catch (error) {
96
+ console.error('Failed to create polar area chart:', error);
97
+ }
98
+ }
99
+
100
+ async function updateChart() {
101
+ if (!Plotly || !chartDiv || !chartInitialized) return;
102
+
103
+ try {
104
+ const data = createPolarAreaChartData(
105
+ selectedAntenna,
106
+ selectedAntenna2,
107
+ viewMode,
108
+ patternType === 'horizontal',
109
+ patternType === 'vertical',
110
+ ant1ElectricalTilt,
111
+ ant1MechanicalTilt,
112
+ ant2ElectricalTilt,
113
+ ant2MechanicalTilt,
114
+ patternDisplayMode
115
+ );
116
+
117
+ const layout = createPolarAreaLayout(title);
118
+ await Plotly.react(chartDiv, data, layout);
119
+ } catch (error) {
120
+ console.error('Failed to update polar area chart:', error);
121
+ }
122
+ }
123
+ </script>
124
+
125
+ <div bind:this={chartDiv} style="height: 700px;"></div>
@@ -0,0 +1,16 @@
1
+ import type { Antenna } from '../../db';
2
+ interface Props {
3
+ selectedAntenna?: Antenna | null;
4
+ selectedAntenna2?: Antenna | null;
5
+ viewMode?: 'single' | 'compare';
6
+ patternType?: 'horizontal' | 'vertical';
7
+ patternDisplayMode?: 'normalized' | 'gain-adjusted';
8
+ ant1ElectricalTilt?: number;
9
+ ant1MechanicalTilt?: number;
10
+ ant2ElectricalTilt?: number;
11
+ ant2MechanicalTilt?: number;
12
+ title?: string;
13
+ }
14
+ declare const PolarAreaChart: import("svelte").Component<Props, {}, "">;
15
+ type PolarAreaChart = ReturnType<typeof PolarAreaChart>;
16
+ export default PolarAreaChart;