@smartnet360/svelte-components 0.0.105 → 0.0.106

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.
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Cell Generator - Configurable Demo Cell Data Generator
3
+ *
4
+ * Generates realistic cell network data with configurable parameters.
5
+ * Supports density zones, multiple technologies, and various site configurations.
6
+ */
7
+ /**
8
+ * Preset configurations
9
+ */
10
+ export const GENERATOR_PRESETS = {
11
+ /** Small dataset for quick demos - 10 sites, ~300 cells */
12
+ small: {
13
+ numSites: 10,
14
+ centerLat: 47.4979,
15
+ centerLng: 19.0402,
16
+ radiusKm: 3
17
+ },
18
+ /** Medium dataset for testing - 100 sites, ~3000 cells */
19
+ medium: {
20
+ numSites: 100,
21
+ centerLat: 47.4979,
22
+ centerLng: 19.0402,
23
+ radiusKm: 8
24
+ },
25
+ /** Large dataset for performance testing - 500 sites, ~15000 cells */
26
+ large: {
27
+ numSites: 500,
28
+ centerLat: 47.4979,
29
+ centerLng: 19.0402,
30
+ radiusKm: 12
31
+ },
32
+ /** Extra large dataset - 2000 sites, ~60000 cells */
33
+ xlarge: {
34
+ numSites: 2000,
35
+ centerLat: 47.4979,
36
+ centerLng: 19.0402,
37
+ radiusKm: 15
38
+ }
39
+ };
40
+ // Density zones (distance from center as fraction of radius)
41
+ const DENSITY_ZONES = [
42
+ { maxRadius: 0.3, minSpacing: 0.0008, maxSpacing: 0.0015, name: 'Very Dense Core' },
43
+ { maxRadius: 0.5, minSpacing: 0.0015, maxSpacing: 0.003, name: 'Dense Inner' },
44
+ { maxRadius: 0.7, minSpacing: 0.003, maxSpacing: 0.006, name: 'Medium' },
45
+ { maxRadius: 0.85, minSpacing: 0.006, maxSpacing: 0.012, name: 'Sparse Suburban' },
46
+ { maxRadius: 1.0, minSpacing: 0.012, maxSpacing: 0.025, name: 'Very Sparse Rural' }
47
+ ];
48
+ // Cell tech-band definitions
49
+ const TECH_BANDS = [
50
+ { tech: '2G', band: '900', fband: 'GSM900' },
51
+ { tech: '2G', band: '1800', fband: 'GSM1800' },
52
+ { tech: '4G', band: '700', fband: 'LTE700' },
53
+ { tech: '4G', band: '800', fband: 'LTE800' },
54
+ { tech: '4G', band: '900', fband: 'LTE900' },
55
+ { tech: '4G', band: '1800', fband: 'LTE1800' },
56
+ { tech: '4G', band: '2100', fband: 'LTE2100' },
57
+ { tech: '4G', band: '2600', fband: 'LTE2600' },
58
+ { tech: '5G', band: '700', fband: '5G-700' },
59
+ { tech: '5G', band: '2100', fband: '5G-2100' },
60
+ { tech: '5G', band: '3500', fband: '5G-3500' }
61
+ ];
62
+ // Sector configurations
63
+ const SECTORS = [
64
+ { azimuth: 0, sectorNum: 1 },
65
+ { azimuth: 120, sectorNum: 2 },
66
+ { azimuth: 240, sectorNum: 3 }
67
+ ];
68
+ // Status distribution
69
+ const STATUSES = [
70
+ 'On_Air', 'On_Air', 'On_Air', 'On_Air',
71
+ 'On_Air_UNDER_CONSTRUCTION', 'On_Air_Locked',
72
+ 'RF_Plan_Ready', 'RF_Plan_Ready',
73
+ 'Re-Planned_RF_Plan_Ready', 'Tavlati_RF_Plan_Ready',
74
+ 'On_Air', 'On_Air'
75
+ ];
76
+ const BEAMWIDTH = 65;
77
+ /**
78
+ * Simple seeded random number generator
79
+ */
80
+ function createRandom(seed) {
81
+ if (seed === undefined) {
82
+ return Math.random;
83
+ }
84
+ let s = seed;
85
+ return () => {
86
+ s = (s * 1103515245 + 12345) & 0x7fffffff;
87
+ return s / 0x7fffffff;
88
+ };
89
+ }
90
+ /**
91
+ * Get density zone for a given normalized radius
92
+ */
93
+ function getDensityZone(normalizedRadius) {
94
+ for (const zone of DENSITY_ZONES) {
95
+ if (normalizedRadius <= zone.maxRadius) {
96
+ return zone;
97
+ }
98
+ }
99
+ return DENSITY_ZONES[DENSITY_ZONES.length - 1];
100
+ }
101
+ /**
102
+ * Generate cell name from site, sector, and band index
103
+ * Format: SSSS S BB (e.g., "1000141")
104
+ */
105
+ function generateCellName(siteNum, sectorNum, bandIndex) {
106
+ const siteId = String(siteNum + 1000).padStart(4, '0');
107
+ const cellSuffix = String(41 + bandIndex).padStart(2, '0');
108
+ return `${siteId}${sectorNum}${cellSuffix}`;
109
+ }
110
+ /**
111
+ * Generate demo cells with configurable parameters
112
+ */
113
+ export function generateCells(config) {
114
+ const { numSites, centerLat, centerLng, radiusKm, seed } = config;
115
+ const random = createRandom(seed);
116
+ const radiusDegrees = radiusKm / 111;
117
+ const cells = [];
118
+ const usedPositions = [];
119
+ let cellCounter = 1;
120
+ let actualSiteIndex = 0;
121
+ /**
122
+ * Generate random point within circle
123
+ */
124
+ function generateRandomPointInCircle() {
125
+ const r = Math.sqrt(random()) * radiusDegrees;
126
+ const theta = random() * 2 * Math.PI;
127
+ return {
128
+ lat: centerLat + r * Math.cos(theta),
129
+ lng: centerLng + r * Math.sin(theta),
130
+ normalizedRadius: r / radiusDegrees
131
+ };
132
+ }
133
+ /**
134
+ * Check if position is too close to existing sites
135
+ */
136
+ function isTooClose(lat, lng, minSpacing) {
137
+ for (const pos of usedPositions) {
138
+ const distance = Math.sqrt(Math.pow(lat - pos.lat, 2) + Math.pow(lng - pos.lng, 2));
139
+ const requiredSpacing = (minSpacing + pos.minSpacing) / 2;
140
+ if (distance < requiredSpacing) {
141
+ return true;
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+ /**
147
+ * Add jitter to coordinate
148
+ */
149
+ function addJitter(value, maxJitter) {
150
+ return value + (random() - 0.5) * 2 * maxJitter;
151
+ }
152
+ // Generate sites
153
+ for (let attempt = 0; attempt < numSites * 3 && actualSiteIndex < numSites; attempt++) {
154
+ const { lat, lng, normalizedRadius } = generateRandomPointInCircle();
155
+ const zone = getDensityZone(normalizedRadius);
156
+ const minSpacing = zone.minSpacing + random() * (zone.maxSpacing - zone.minSpacing);
157
+ if (isTooClose(lat, lng, minSpacing)) {
158
+ continue;
159
+ }
160
+ const jitterAmount = minSpacing * 0.3;
161
+ const siteLat = addJitter(lat, jitterAmount);
162
+ const siteLng = addJitter(lng, jitterAmount);
163
+ usedPositions.push({ lat: siteLat, lng: siteLng, minSpacing });
164
+ const siteNum = actualSiteIndex;
165
+ const siteId = String(siteNum + 1000).padStart(4, '0');
166
+ actualSiteIndex++;
167
+ // 10% chance of 1-2 sectors instead of 3
168
+ const numSectors = random() < 0.1 ? (random() < 0.5 ? 1 : 2) : 3;
169
+ const sectorsToGenerate = SECTORS.slice(0, numSectors);
170
+ for (const sector of sectorsToGenerate) {
171
+ for (let bandIndex = 0; bandIndex < TECH_BANDS.length; bandIndex++) {
172
+ const techBand = TECH_BANDS[bandIndex];
173
+ const cellName = generateCellName(siteNum, sector.sectorNum, bandIndex);
174
+ const status = STATUSES[bandIndex % STATUSES.length];
175
+ cells.push({
176
+ id: cellName,
177
+ txId: cellName,
178
+ cellID: cellName,
179
+ cellID2G: techBand.tech === '2G' ? cellName : '',
180
+ cellName: cellName,
181
+ siteId: siteId,
182
+ tech: techBand.tech,
183
+ fband: techBand.fband,
184
+ frq: techBand.band,
185
+ type: 'MACRO',
186
+ status: status,
187
+ onAirDate: '2024-01-15',
188
+ bcch: techBand.tech === '2G' ? 100 + bandIndex : 0,
189
+ ctrlid: techBand.tech === '2G' ? `CTRL-${cellName}` : '',
190
+ dlEarfn: techBand.tech === '4G' ? 6200 + bandIndex * 100 : 0,
191
+ antenna: 'DEMO-ANTENNA-MODEL',
192
+ azimuth: sector.azimuth,
193
+ height: 30,
194
+ electricalTilt: '3',
195
+ beamwidth: BEAMWIDTH,
196
+ latitude: siteLat,
197
+ longitude: siteLng,
198
+ dx: 0,
199
+ dy: 0,
200
+ siteLatitude: siteLat,
201
+ siteLongitude: siteLng,
202
+ comment: `Demo ${techBand.tech} ${techBand.band} cell at azimuth ${sector.azimuth}°`,
203
+ planner: 'Demo User',
204
+ atollETP: 43.0,
205
+ atollPW: 20.0,
206
+ atollRS: 500.0 + (techBand.band === '700' ? 200 : 0),
207
+ atollBW: parseFloat(techBand.band) / 100,
208
+ cellId3: `${cellName}-3G`,
209
+ nwtP1: 20,
210
+ nwtP2: 40,
211
+ pci1: cellCounter % 504,
212
+ nwtRS: 450.0,
213
+ nwtBW: 10.0,
214
+ other: {
215
+ demoCell: true,
216
+ siteNumber: actualSiteIndex,
217
+ sector: sector.sectorNum,
218
+ techBandKey: `${techBand.tech}_${techBand.band}`,
219
+ radius: normalizedRadius,
220
+ densityZone: zone.name
221
+ },
222
+ customSubgroup: `Sector-${sector.sectorNum}`
223
+ });
224
+ cellCounter++;
225
+ }
226
+ }
227
+ }
228
+ return cells;
229
+ }
230
+ /**
231
+ * Generate cells using a preset configuration
232
+ */
233
+ export function generateCellsFromPreset(preset, seed) {
234
+ const config = { ...GENERATOR_PRESETS[preset], seed };
235
+ return generateCells(config);
236
+ }
237
+ /**
238
+ * Get info about generated data
239
+ */
240
+ export function getGeneratorInfo(cells) {
241
+ const siteIds = new Set(cells.map(c => c.siteId));
242
+ const techBreakdown = {};
243
+ const statusBreakdown = {};
244
+ for (const cell of cells) {
245
+ techBreakdown[cell.tech] = (techBreakdown[cell.tech] || 0) + 1;
246
+ statusBreakdown[cell.status] = (statusBreakdown[cell.status] || 0) + 1;
247
+ }
248
+ return {
249
+ totalCells: cells.length,
250
+ totalSites: siteIds.size,
251
+ techBreakdown,
252
+ statusBreakdown
253
+ };
254
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Shared Demo Data - Cell Types
3
+ *
4
+ * Core cell interface used across all components
5
+ */
6
+ /**
7
+ * Cell data model - represents a radio cell/sector
8
+ */
9
+ export interface Cell {
10
+ id: string;
11
+ txId: string;
12
+ cellID: string;
13
+ cellID2G: string;
14
+ cellName: string;
15
+ siteId: string;
16
+ tech: string;
17
+ fband: string;
18
+ frq: string;
19
+ type: string;
20
+ status: string;
21
+ onAirDate: string;
22
+ bcch: number;
23
+ ctrlid: string;
24
+ dlEarfn: number;
25
+ antenna: string;
26
+ azimuth: number;
27
+ height: number;
28
+ electricalTilt: string;
29
+ beamwidth: number;
30
+ latitude: number;
31
+ longitude: number;
32
+ dx: number;
33
+ dy: number;
34
+ siteLatitude: number;
35
+ siteLongitude: number;
36
+ comment: string;
37
+ planner: string;
38
+ atollETP: number;
39
+ atollPW: number;
40
+ atollRS: number;
41
+ atollBW: number;
42
+ cellId3: string;
43
+ nwtP1: number;
44
+ nwtP2: number;
45
+ pci1: number;
46
+ nwtRS: number;
47
+ nwtBW: number;
48
+ other?: Record<string, unknown>;
49
+ customSubgroup: string;
50
+ }
51
+ /**
52
+ * Supported cell sector status values
53
+ */
54
+ export type CellStatus = 'On_Air' | 'On_Air_UNDER_CONSTRUCTION' | 'On_Air_Locked' | 'RF_Plan_Ready' | 'Re-Planned_RF_Plan_Ready' | 'Tavlati_RF_Plan_Ready';
55
+ /**
56
+ * Technology-Band combination key
57
+ */
58
+ export type TechnologyBandKey = string;
59
+ /**
60
+ * Grouping fields for views
61
+ */
62
+ export type CellGroupingField = 'tech' | 'fband' | 'frq' | 'status' | 'siteId' | 'none';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared Demo Data - Cell Types
3
+ *
4
+ * Core cell interface used across all components
5
+ */
6
+ export {};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared Demo Data Module
3
+ *
4
+ * Provides common demo data generators and types for use across components.
5
+ */
6
+ export type { Cell, CellStatus, CellGroupingField } from './cell-types';
7
+ export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS, type CellGeneratorConfig, type GeneratorPreset } from './cell-generator';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared Demo Data Module
3
+ *
4
+ * Provides common demo data generators and types for use across components.
5
+ */
6
+ // Generator
7
+ export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS } from './cell-generator';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.105",
3
+ "version": "0.0.106",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -1,5 +0,0 @@
1
- import type { CellData } from './types';
2
- /**
3
- * Demo cell data for testing the CellTable component
4
- */
5
- export declare const demoCells: CellData[];