@tellegen/svelte 0.1.0
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/LICENSE +19 -0
- package/README.md +70 -0
- package/dist/Sparkline.svelte +100 -0
- package/dist/Sparkline.svelte.d.ts +8 -0
- package/dist/Sparkline.svelte.d.ts.map +1 -0
- package/dist/TellegenMap.svelte +1430 -0
- package/dist/TellegenMap.svelte.d.ts +14 -0
- package/dist/TellegenMap.svelte.d.ts.map +1 -0
- package/dist/TellegenProvider.svelte +38 -0
- package/dist/TellegenProvider.svelte.d.ts +9 -0
- package/dist/TellegenProvider.svelte.d.ts.map +1 -0
- package/dist/TellegenShell.svelte +126 -0
- package/dist/TellegenShell.svelte.d.ts +4 -0
- package/dist/TellegenShell.svelte.d.ts.map +1 -0
- package/dist/TellegenViewer.svelte +19 -0
- package/dist/TellegenViewer.svelte.d.ts +4 -0
- package/dist/TellegenViewer.svelte.d.ts.map +1 -0
- package/dist/api.d.ts +44 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +137 -0
- package/dist/colors.d.ts +51 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +140 -0
- package/dist/components/AppFooter.svelte +73 -0
- package/dist/components/AppFooter.svelte.d.ts +19 -0
- package/dist/components/AppFooter.svelte.d.ts.map +1 -0
- package/dist/components/AppHeader.svelte +405 -0
- package/dist/components/AppHeader.svelte.d.ts +4 -0
- package/dist/components/AppHeader.svelte.d.ts.map +1 -0
- package/dist/components/BindingLines.svelte +101 -0
- package/dist/components/BindingLines.svelte.d.ts +4 -0
- package/dist/components/BindingLines.svelte.d.ts.map +1 -0
- package/dist/components/BusPicker.svelte +227 -0
- package/dist/components/BusPicker.svelte.d.ts +4 -0
- package/dist/components/BusPicker.svelte.d.ts.map +1 -0
- package/dist/components/ControlPanel.svelte +154 -0
- package/dist/components/ControlPanel.svelte.d.ts +19 -0
- package/dist/components/ControlPanel.svelte.d.ts.map +1 -0
- package/dist/components/DemandSlider.svelte +271 -0
- package/dist/components/DemandSlider.svelte.d.ts +4 -0
- package/dist/components/DemandSlider.svelte.d.ts.map +1 -0
- package/dist/components/DisplayControls.svelte +81 -0
- package/dist/components/DisplayControls.svelte.d.ts +19 -0
- package/dist/components/DisplayControls.svelte.d.ts.map +1 -0
- package/dist/components/DropZone.svelte +46 -0
- package/dist/components/DropZone.svelte.d.ts +19 -0
- package/dist/components/DropZone.svelte.d.ts.map +1 -0
- package/dist/components/FormulationSelector.svelte +82 -0
- package/dist/components/FormulationSelector.svelte.d.ts +19 -0
- package/dist/components/FormulationSelector.svelte.d.ts.map +1 -0
- package/dist/components/LocalCaseDetails.svelte +253 -0
- package/dist/components/LocalCaseDetails.svelte.d.ts +4 -0
- package/dist/components/LocalCaseDetails.svelte.d.ts.map +1 -0
- package/dist/components/MulticonductorDetails.svelte +280 -0
- package/dist/components/MulticonductorDetails.svelte.d.ts +19 -0
- package/dist/components/MulticonductorDetails.svelte.d.ts.map +1 -0
- package/dist/components/NetworkStats.svelte +75 -0
- package/dist/components/NetworkStats.svelte.d.ts +19 -0
- package/dist/components/NetworkStats.svelte.d.ts.map +1 -0
- package/dist/components/PlacementCue.svelte +35 -0
- package/dist/components/PlacementCue.svelte.d.ts +19 -0
- package/dist/components/PlacementCue.svelte.d.ts.map +1 -0
- package/dist/components/RatingSlider.svelte +273 -0
- package/dist/components/RatingSlider.svelte.d.ts +4 -0
- package/dist/components/RatingSlider.svelte.d.ts.map +1 -0
- package/dist/components/RestoreDefaultsButton.svelte +34 -0
- package/dist/components/RestoreDefaultsButton.svelte.d.ts +19 -0
- package/dist/components/RestoreDefaultsButton.svelte.d.ts.map +1 -0
- package/dist/components/SensitivityReadout.svelte +126 -0
- package/dist/components/SensitivityReadout.svelte.d.ts +4 -0
- package/dist/components/SensitivityReadout.svelte.d.ts.map +1 -0
- package/dist/components/SizeLegend.svelte +55 -0
- package/dist/components/SizeLegend.svelte.d.ts +19 -0
- package/dist/components/SizeLegend.svelte.d.ts.map +1 -0
- package/dist/components/SolveCard.svelte +84 -0
- package/dist/components/SolveCard.svelte.d.ts +4 -0
- package/dist/components/SolveCard.svelte.d.ts.map +1 -0
- package/dist/components/TopMovers.svelte +68 -0
- package/dist/components/TopMovers.svelte.d.ts +19 -0
- package/dist/components/TopMovers.svelte.d.ts.map +1 -0
- package/dist/components.d.ts +19 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +18 -0
- package/dist/context.svelte.d.ts +20 -0
- package/dist/context.svelte.d.ts.map +1 -0
- package/dist/context.svelte.js +43 -0
- package/dist/controller.svelte.d.ts +334 -0
- package/dist/controller.svelte.d.ts.map +1 -0
- package/dist/controller.svelte.js +2026 -0
- package/dist/display.d.ts +31 -0
- package/dist/display.d.ts.map +1 -0
- package/dist/display.js +63 -0
- package/dist/drop-classify.d.ts +48 -0
- package/dist/drop-classify.d.ts.map +1 -0
- package/dist/drop-classify.js +92 -0
- package/dist/format.d.ts +30 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +49 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/map.d.ts +9 -0
- package/dist/map.d.ts.map +1 -0
- package/dist/map.js +4 -0
- package/dist/multiconductor.d.ts +63 -0
- package/dist/multiconductor.d.ts.map +1 -0
- package/dist/multiconductor.js +255 -0
- package/dist/state.svelte.d.ts +258 -0
- package/dist/state.svelte.d.ts.map +1 -0
- package/dist/state.svelte.js +323 -0
- package/dist/study-package.d.ts +9 -0
- package/dist/study-package.d.ts.map +1 -0
- package/dist/study-package.js +17 -0
- package/dist/styles.css +393 -0
- package/dist/synthetic-layout.d.ts +12 -0
- package/dist/synthetic-layout.d.ts.map +1 -0
- package/dist/synthetic-layout.js +271 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +67 -0
package/dist/styles.css
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/* tellegen design tokens: warm paper ground, burnt amber accent, the physics
|
|
2
|
+
owns all other saturation. */
|
|
3
|
+
:root {
|
|
4
|
+
--bg: #ece9e2;
|
|
5
|
+
--panel: rgba(252, 251, 247, 0.92);
|
|
6
|
+
--line: #d9d3c6;
|
|
7
|
+
--ink: #20242b;
|
|
8
|
+
--ink-dim: #6e7378;
|
|
9
|
+
--ink-faint: #989b92;
|
|
10
|
+
--accent: #b25e00;
|
|
11
|
+
--accent-bright: #ffb000;
|
|
12
|
+
--accent-soft: rgba(178, 94, 0, 0.1);
|
|
13
|
+
--red: #b3261e;
|
|
14
|
+
--pos: #762a83;
|
|
15
|
+
--neg: #1b7837;
|
|
16
|
+
|
|
17
|
+
--font-display: 'Bricolage Grotesque Variable', system-ui, sans-serif;
|
|
18
|
+
--font-mono: 'IBM Plex Mono', ui-monospace, monospace;
|
|
19
|
+
|
|
20
|
+
/* channel forms of the grounds, so scrims and shadows derive from one source */
|
|
21
|
+
--bg-rgb: 236 233 226;
|
|
22
|
+
--ink-rgb: 32 36 43;
|
|
23
|
+
--accent-rgb: 178 94 0;
|
|
24
|
+
--paper: #fcfbf7;
|
|
25
|
+
--paper-rgb: 252 251 247;
|
|
26
|
+
|
|
27
|
+
/* Semantic role + scale layer, kept as the target vocabulary for a future
|
|
28
|
+
migration. Most call sites still reference the raw primitives above and
|
|
29
|
+
hardcoded values; only a handful of these (e.g. --radius-xs, --shadow-thumb,
|
|
30
|
+
--dur-fast, --ease-out, the channel forms) are wired up so far. */
|
|
31
|
+
--surface-page: var(--bg);
|
|
32
|
+
--surface-panel: var(--panel);
|
|
33
|
+
--surface-chip: rgb(var(--paper-rgb) / 0.65);
|
|
34
|
+
--surface-control: rgb(var(--paper-rgb) / 0.55);
|
|
35
|
+
--border-default: var(--line);
|
|
36
|
+
--border-strong: var(--accent);
|
|
37
|
+
--text-primary: var(--ink);
|
|
38
|
+
/* --text-secondary/--text-tertiary/--text-accent are independent from
|
|
39
|
+
--ink-dim/--ink-faint/--accent (below) rather than aliased to them:
|
|
40
|
+
the primitives stay lighter/warmer for borders, focus rings, and
|
|
41
|
+
active-state indicators (3:1 or no minimum applies), while the
|
|
42
|
+
text-* tokens are tuned to clear WCAG AA 4.5:1 against --bg. */
|
|
43
|
+
--text-secondary: #4d5156;
|
|
44
|
+
--text-tertiary: #636657;
|
|
45
|
+
--text-accent: #8a4800;
|
|
46
|
+
--text-danger: var(--red);
|
|
47
|
+
--data-pos: var(--pos);
|
|
48
|
+
--data-neg: var(--neg);
|
|
49
|
+
--focus-ring: var(--accent);
|
|
50
|
+
|
|
51
|
+
/* type scale, anchored at the 15px body */
|
|
52
|
+
--fs-display-lg: 33px;
|
|
53
|
+
--fs-display: 22px;
|
|
54
|
+
--fs-title: 18px;
|
|
55
|
+
--fs-heading: 16px;
|
|
56
|
+
--fs-body: 15px;
|
|
57
|
+
--fs-data: 12.5px;
|
|
58
|
+
--fs-label: 12px;
|
|
59
|
+
--fs-control: 11px;
|
|
60
|
+
--fs-meta: 10px;
|
|
61
|
+
--fs-micro: 8.5px;
|
|
62
|
+
--lh-tight: 1.2;
|
|
63
|
+
--lh-snug: 1.35;
|
|
64
|
+
--lh-normal: 1.5;
|
|
65
|
+
--lh-relaxed: 1.55;
|
|
66
|
+
|
|
67
|
+
/* spacing scale */
|
|
68
|
+
--space-3xs: 2px;
|
|
69
|
+
--space-2xs: 4px;
|
|
70
|
+
--space-xs: 6px;
|
|
71
|
+
--space-sm: 8px;
|
|
72
|
+
--space-md: 10px;
|
|
73
|
+
--space-lg: 12px;
|
|
74
|
+
--space-xl: 16px;
|
|
75
|
+
--space-2xl: 20px;
|
|
76
|
+
--space-3xl: 24px;
|
|
77
|
+
|
|
78
|
+
/* radius and elevation */
|
|
79
|
+
--radius-xs: 2px;
|
|
80
|
+
--radius-sm: 3px;
|
|
81
|
+
--radius-full: 50%;
|
|
82
|
+
--elev-1: 0 2px 10px rgb(var(--ink-rgb) / 0.1);
|
|
83
|
+
--elev-2: 0 4px 24px rgb(var(--ink-rgb) / 0.08);
|
|
84
|
+
--shadow-thumb: 0 1px 4px rgb(var(--ink-rgb) / 0.3);
|
|
85
|
+
--inset-active: inset 0 -2px 0 var(--accent);
|
|
86
|
+
|
|
87
|
+
/* motion: durations and easings, zeroed under reduced-motion below */
|
|
88
|
+
--dur-fast: 0.15s;
|
|
89
|
+
--dur-med: 0.3s;
|
|
90
|
+
--dur-slow: 0.5s;
|
|
91
|
+
--delay-panel: 0.12s;
|
|
92
|
+
--delay-footer: 0.24s;
|
|
93
|
+
--dur-blink: 1.2s;
|
|
94
|
+
--dur-bob: 1.8s;
|
|
95
|
+
--ease-out: ease-out;
|
|
96
|
+
--ease-in-out: ease-in-out;
|
|
97
|
+
--ease-standard: ease;
|
|
98
|
+
|
|
99
|
+
/* z-index layers */
|
|
100
|
+
--z-chrome: 10;
|
|
101
|
+
--z-cue: 14;
|
|
102
|
+
--z-overlay: 20;
|
|
103
|
+
--z-grain: 9999;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
* {
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
html,
|
|
111
|
+
body {
|
|
112
|
+
margin: 0;
|
|
113
|
+
height: 100%;
|
|
114
|
+
background: var(--bg);
|
|
115
|
+
color: var(--ink);
|
|
116
|
+
font-family: var(--font-display);
|
|
117
|
+
font-size: 15px;
|
|
118
|
+
-webkit-font-smoothing: antialiased;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* faint grain over everything; keeps flat panels from looking sterile */
|
|
122
|
+
body::after {
|
|
123
|
+
content: '';
|
|
124
|
+
position: fixed;
|
|
125
|
+
inset: 0;
|
|
126
|
+
pointer-events: none;
|
|
127
|
+
z-index: 9999;
|
|
128
|
+
opacity: 0.04;
|
|
129
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.mono {
|
|
133
|
+
font-family: var(--font-mono);
|
|
134
|
+
font-variant-numeric: tabular-nums;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
a {
|
|
138
|
+
color: var(--text-accent);
|
|
139
|
+
text-decoration: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* chrome classes shared by more than one split component; kept global so Svelte
|
|
143
|
+
scoping does not drop them. Moved verbatim from the page <style>. */
|
|
144
|
+
.dim {
|
|
145
|
+
color: var(--text-secondary);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.arrow {
|
|
149
|
+
display: inline-block;
|
|
150
|
+
animation: bob 1.8s ease-in-out infinite alternate;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sep {
|
|
154
|
+
width: 4px;
|
|
155
|
+
height: 4px;
|
|
156
|
+
margin: 0 10px;
|
|
157
|
+
background: var(--accent-bright);
|
|
158
|
+
opacity: 0.55;
|
|
159
|
+
transform: rotate(45deg);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@media (max-width: 760px) {
|
|
163
|
+
.sep {
|
|
164
|
+
margin: 0 8px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.filedrop-ui {
|
|
168
|
+
display: none;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@media (hover: none), (pointer: coarse) {
|
|
173
|
+
.filedrop-ui {
|
|
174
|
+
display: none;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* shared animations, global so split components can reference them */
|
|
179
|
+
@keyframes drop {
|
|
180
|
+
from {
|
|
181
|
+
opacity: 0;
|
|
182
|
+
transform: translateY(-8px);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@keyframes rise {
|
|
187
|
+
from {
|
|
188
|
+
opacity: 0;
|
|
189
|
+
transform: translateY(8px);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@keyframes blink {
|
|
194
|
+
50% {
|
|
195
|
+
opacity: 0.35;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@keyframes bob {
|
|
200
|
+
to {
|
|
201
|
+
transform: translateY(2px);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@media (prefers-reduced-motion: reduce) {
|
|
206
|
+
:root {
|
|
207
|
+
--dur-fast: 0.01ms;
|
|
208
|
+
--dur-med: 0.01ms;
|
|
209
|
+
--dur-slow: 0.01ms;
|
|
210
|
+
--dur-blink: 0.01ms;
|
|
211
|
+
--dur-bob: 0.01ms;
|
|
212
|
+
--delay-panel: 0s;
|
|
213
|
+
--delay-footer: 0s;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.arrow {
|
|
217
|
+
animation: none;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* control panel regions: classes used by more than one split region component
|
|
222
|
+
(NetworkStats, FormulationSelector, SensitivityReadout, DemandSlider,
|
|
223
|
+
TopMovers, DisplayControls, SizeLegend, LocalCaseDetails) plus ControlPanel
|
|
224
|
+
itself. Kept global so Svelte scoping does not drop them. Moved verbatim from
|
|
225
|
+
ControlPanel.svelte; the .mode / .display-mode / @media source order is
|
|
226
|
+
preserved so the cascade resolves exactly as before. */
|
|
227
|
+
.region {
|
|
228
|
+
font-size: 10px;
|
|
229
|
+
font-weight: 400;
|
|
230
|
+
color: var(--text-secondary);
|
|
231
|
+
text-transform: uppercase;
|
|
232
|
+
letter-spacing: 0;
|
|
233
|
+
margin-left: 4px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.mode {
|
|
237
|
+
display: flex;
|
|
238
|
+
align-items: center;
|
|
239
|
+
gap: 10px;
|
|
240
|
+
font-size: 12px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* Kept global (not scoped into SensitivityReadout) so the @media (max-width: 760px)
|
|
244
|
+
`.mode button { margin-left: 0 }` override below wins by source order, as it did
|
|
245
|
+
before the component split. Scoping this would raise its specificity past that rule. */
|
|
246
|
+
.mode > button {
|
|
247
|
+
margin-left: auto;
|
|
248
|
+
font-size: 10.5px;
|
|
249
|
+
padding: 2px 7px;
|
|
250
|
+
background: none;
|
|
251
|
+
border: 1px solid var(--line);
|
|
252
|
+
border-radius: 2px;
|
|
253
|
+
color: var(--text-secondary);
|
|
254
|
+
cursor: pointer;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.mode > button:hover {
|
|
258
|
+
border-color: var(--accent);
|
|
259
|
+
color: var(--text-accent);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.display-mode {
|
|
263
|
+
gap: 8px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.display-mode .segment button {
|
|
267
|
+
font-size: 11px;
|
|
268
|
+
padding: 2px 9px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.small {
|
|
272
|
+
font-size: 12px;
|
|
273
|
+
line-height: 1.55;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.legend {
|
|
277
|
+
height: 6px;
|
|
278
|
+
border-radius: 3px;
|
|
279
|
+
margin-top: 6px;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.legend-labels {
|
|
283
|
+
display: flex;
|
|
284
|
+
justify-content: space-between;
|
|
285
|
+
font-size: 10.5px;
|
|
286
|
+
color: var(--text-tertiary);
|
|
287
|
+
margin-top: 4px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.legend-labels.single {
|
|
291
|
+
justify-content: center;
|
|
292
|
+
text-align: center;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.hint-dot {
|
|
296
|
+
display: inline-grid;
|
|
297
|
+
place-items: center;
|
|
298
|
+
width: 15px;
|
|
299
|
+
height: 15px;
|
|
300
|
+
border: 1px solid var(--line);
|
|
301
|
+
border-radius: 999px;
|
|
302
|
+
color: var(--text-secondary);
|
|
303
|
+
background: var(--surface-control);
|
|
304
|
+
font-size: 10px;
|
|
305
|
+
line-height: 1;
|
|
306
|
+
cursor: help;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.segment {
|
|
310
|
+
display: inline-flex;
|
|
311
|
+
border: 1px solid var(--line);
|
|
312
|
+
border-radius: 2px;
|
|
313
|
+
overflow: hidden;
|
|
314
|
+
background: var(--surface-control);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.segment button {
|
|
318
|
+
padding: 2px 8px;
|
|
319
|
+
border: 0;
|
|
320
|
+
background: transparent;
|
|
321
|
+
color: var(--text-secondary);
|
|
322
|
+
font: inherit;
|
|
323
|
+
cursor: pointer;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.segment button + button {
|
|
327
|
+
border-left: 1px solid var(--line);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.segment button.active {
|
|
331
|
+
background: var(--accent-soft);
|
|
332
|
+
color: var(--text-accent);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.reset {
|
|
336
|
+
margin-top: 10px;
|
|
337
|
+
font-size: 10.5px;
|
|
338
|
+
padding: 3px 10px;
|
|
339
|
+
background: none;
|
|
340
|
+
border: 1px solid var(--line);
|
|
341
|
+
border-radius: 2px;
|
|
342
|
+
color: var(--text-secondary);
|
|
343
|
+
cursor: pointer;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.reset:hover {
|
|
347
|
+
border-color: var(--red);
|
|
348
|
+
color: var(--red);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.blink {
|
|
352
|
+
animation: blink 1.2s steps(2) infinite;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
@media (max-width: 760px) {
|
|
356
|
+
.mode {
|
|
357
|
+
flex-wrap: wrap;
|
|
358
|
+
gap: 7px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.mode button {
|
|
362
|
+
margin-left: 0;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/* Keyboard focus ring: one accent ring for every interactive element. */
|
|
367
|
+
:focus-visible {
|
|
368
|
+
outline: 2px solid var(--focus-ring);
|
|
369
|
+
outline-offset: 2px;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Coarse pointers: comfortable hit targets for the toggle and reset controls. */
|
|
373
|
+
@media (hover: none), (pointer: coarse) {
|
|
374
|
+
.segment button {
|
|
375
|
+
min-height: 36px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.reset {
|
|
379
|
+
min-height: 36px;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* Honor reduced-motion everywhere: collapse animations and transitions. */
|
|
384
|
+
@media (prefers-reduced-motion: reduce) {
|
|
385
|
+
*,
|
|
386
|
+
*::before,
|
|
387
|
+
*::after {
|
|
388
|
+
animation-duration: 0.01ms !important;
|
|
389
|
+
animation-iteration-count: 1 !important;
|
|
390
|
+
transition-duration: 0.01ms !important;
|
|
391
|
+
scroll-behavior: auto !important;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NetworkBranch, NetworkBus } from './api.js';
|
|
2
|
+
import type { Topology } from '@tellegen/engine';
|
|
3
|
+
export interface PlacedNetwork {
|
|
4
|
+
buses: NetworkBus[];
|
|
5
|
+
branches: NetworkBranch[];
|
|
6
|
+
}
|
|
7
|
+
export interface PlacementCenter {
|
|
8
|
+
lon: number;
|
|
9
|
+
lat: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function placeSyntheticTopology(topology: Topology, center: PlacementCenter): PlacedNetwork;
|
|
12
|
+
//# sourceMappingURL=synthetic-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthetic-layout.d.ts","sourceRoot":"","sources":["../src/lib/synthetic-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACZ;AAKD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,GAAG,aAAa,CAuCjG"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { extent } from './format.js';
|
|
2
|
+
const ALL_PAIRS_LIMIT = 500;
|
|
3
|
+
export function placeSyntheticTopology(topology, center) {
|
|
4
|
+
const buses = [...topology.buses].sort((a, b) => a.id - b.id);
|
|
5
|
+
const index = new Map(buses.map((bus, i) => [bus.id, i]));
|
|
6
|
+
const edges = topology.branches
|
|
7
|
+
.filter((branch) => branch.status !== 0 && index.has(branch.from) && index.has(branch.to))
|
|
8
|
+
.map((branch) => [index.get(branch.from), index.get(branch.to)])
|
|
9
|
+
.filter(([from, to]) => from !== to);
|
|
10
|
+
const unit = forceLayout(buses.length, edges);
|
|
11
|
+
const span = Math.min(4.5, Math.max(0.32, Math.sqrt(Math.max(buses.length, 1)) * 0.08));
|
|
12
|
+
const lonScale = Math.max(Math.cos((center.lat * Math.PI) / 180), 0.25);
|
|
13
|
+
const latSpan = span;
|
|
14
|
+
const lonSpan = span / lonScale;
|
|
15
|
+
const coords = new Map();
|
|
16
|
+
for (let i = 0; i < buses.length; i++) {
|
|
17
|
+
const p = unit[i] ?? { x: 0.5, y: 0.5 };
|
|
18
|
+
coords.set(buses[i].id, [
|
|
19
|
+
center.lon + (p.x - 0.5) * lonSpan,
|
|
20
|
+
center.lat + (p.y - 0.5) * latSpan
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
buses: buses.map((bus) => {
|
|
25
|
+
const [lon, lat] = coords.get(bus.id);
|
|
26
|
+
return { id: bus.id, uid: bus.uid, lon, lat, demand_mw: bus.demand_mw, gen_mw: bus.gen_mw };
|
|
27
|
+
}),
|
|
28
|
+
branches: topology.branches
|
|
29
|
+
.filter((branch) => coords.has(branch.from) && coords.has(branch.to))
|
|
30
|
+
.map((branch) => ({
|
|
31
|
+
id: branch.id,
|
|
32
|
+
uid: branch.uid,
|
|
33
|
+
from: branch.from,
|
|
34
|
+
to: branch.to,
|
|
35
|
+
rate_mw: branch.rate_mw,
|
|
36
|
+
status: branch.status,
|
|
37
|
+
path: [coords.get(branch.from), coords.get(branch.to)]
|
|
38
|
+
}))
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function forceLayout(n, edges) {
|
|
42
|
+
if (n === 0)
|
|
43
|
+
return [];
|
|
44
|
+
if (n === 1)
|
|
45
|
+
return [{ x: 0.5, y: 0.5 }];
|
|
46
|
+
if (n > ALL_PAIRS_LIMIT)
|
|
47
|
+
return fastGraphLayout(n, edges);
|
|
48
|
+
const golden = Math.PI * (3 - Math.sqrt(5));
|
|
49
|
+
const pos = Array.from({ length: n }, (_, i) => {
|
|
50
|
+
const r = 0.44 * Math.sqrt((i + 0.5) / n);
|
|
51
|
+
const theta = i * golden;
|
|
52
|
+
return {
|
|
53
|
+
x: 0.5 + r * Math.cos(theta) + 1e-4 * Math.sin(0.7 * (i + 1)),
|
|
54
|
+
y: 0.5 + r * Math.sin(theta) + 1e-4 * Math.cos(1.3 * (i + 1))
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
const disp = Array.from({ length: n }, () => ({ x: 0, y: 0 }));
|
|
58
|
+
const k2 = 1 / n;
|
|
59
|
+
const k = Math.sqrt(k2);
|
|
60
|
+
const iters = n <= 120 ? 180 : n <= 500 ? 100 : 32;
|
|
61
|
+
for (let iter = 0; iter < iters; iter++) {
|
|
62
|
+
for (const d of disp) {
|
|
63
|
+
d.x = 0;
|
|
64
|
+
d.y = 0;
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i < n; i++) {
|
|
67
|
+
for (let j = i + 1; j < n; j++) {
|
|
68
|
+
const dx = pos[i].x - pos[j].x;
|
|
69
|
+
const dy = pos[i].y - pos[j].y;
|
|
70
|
+
const f = k2 / (dx * dx + dy * dy + 1e-6);
|
|
71
|
+
disp[i].x += dx * f;
|
|
72
|
+
disp[i].y += dy * f;
|
|
73
|
+
disp[j].x -= dx * f;
|
|
74
|
+
disp[j].y -= dy * f;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const [i, j] of edges) {
|
|
78
|
+
const dx = pos[i].x - pos[j].x;
|
|
79
|
+
const dy = pos[i].y - pos[j].y;
|
|
80
|
+
const f = Math.sqrt(dx * dx + dy * dy) / k;
|
|
81
|
+
disp[i].x -= dx * f;
|
|
82
|
+
disp[i].y -= dy * f;
|
|
83
|
+
disp[j].x += dx * f;
|
|
84
|
+
disp[j].y += dy * f;
|
|
85
|
+
}
|
|
86
|
+
const t = 0.1 * (1 - iter / iters) + 1e-3;
|
|
87
|
+
for (let i = 0; i < n; i++) {
|
|
88
|
+
const d = Math.hypot(disp[i].x, disp[i].y) + 1e-9;
|
|
89
|
+
const s = Math.min(d, t) / d;
|
|
90
|
+
pos[i].x = clamp(pos[i].x + disp[i].x * s);
|
|
91
|
+
pos[i].y = clamp(pos[i].y + disp[i].y * s);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return normalize(pos);
|
|
95
|
+
}
|
|
96
|
+
function fastGraphLayout(n, edges) {
|
|
97
|
+
const adjacency = graph(n, edges);
|
|
98
|
+
const components = connectedComponents(adjacency);
|
|
99
|
+
const cols = Math.ceil(Math.sqrt(components.length));
|
|
100
|
+
const rows = Math.ceil(components.length / cols);
|
|
101
|
+
const pos = Array.from({ length: n }, () => ({ x: 0.5, y: 0.5 }));
|
|
102
|
+
const cellScale = 0.82 / Math.max(cols, rows);
|
|
103
|
+
for (let c = 0; c < components.length; c++) {
|
|
104
|
+
const nodes = components[c];
|
|
105
|
+
const local = componentLayout(nodes, adjacency);
|
|
106
|
+
const col = c % cols;
|
|
107
|
+
const row = Math.floor(c / cols);
|
|
108
|
+
const cx = (col + 0.5) / cols;
|
|
109
|
+
const cy = (row + 0.5) / rows;
|
|
110
|
+
for (const node of nodes) {
|
|
111
|
+
const p = local.get(node) ?? { x: 0.5, y: 0.5 };
|
|
112
|
+
pos[node] = {
|
|
113
|
+
x: cx + (p.x - 0.5) * cellScale,
|
|
114
|
+
y: cy + (p.y - 0.5) * cellScale
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return normalize(pos);
|
|
119
|
+
}
|
|
120
|
+
function graph(n, edges) {
|
|
121
|
+
const adjacency = Array.from({ length: n }, () => []);
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
for (const [from, to] of edges) {
|
|
124
|
+
if (from < 0 || to < 0 || from >= n || to >= n || from === to)
|
|
125
|
+
continue;
|
|
126
|
+
const a = Math.min(from, to);
|
|
127
|
+
const b = Math.max(from, to);
|
|
128
|
+
const key = a * n + b;
|
|
129
|
+
if (seen.has(key))
|
|
130
|
+
continue;
|
|
131
|
+
seen.add(key);
|
|
132
|
+
adjacency[a].push(b);
|
|
133
|
+
adjacency[b].push(a);
|
|
134
|
+
}
|
|
135
|
+
for (const neighbors of adjacency)
|
|
136
|
+
neighbors.sort((a, b) => a - b);
|
|
137
|
+
return adjacency;
|
|
138
|
+
}
|
|
139
|
+
function connectedComponents(adjacency) {
|
|
140
|
+
const seen = new Uint8Array(adjacency.length);
|
|
141
|
+
const components = [];
|
|
142
|
+
for (let start = 0; start < adjacency.length; start++) {
|
|
143
|
+
if (seen[start])
|
|
144
|
+
continue;
|
|
145
|
+
const nodes = [];
|
|
146
|
+
const stack = [start];
|
|
147
|
+
seen[start] = 1;
|
|
148
|
+
while (stack.length > 0) {
|
|
149
|
+
const node = stack.pop();
|
|
150
|
+
nodes.push(node);
|
|
151
|
+
for (const next of adjacency[node]) {
|
|
152
|
+
if (seen[next])
|
|
153
|
+
continue;
|
|
154
|
+
seen[next] = 1;
|
|
155
|
+
stack.push(next);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
nodes.sort((a, b) => a - b);
|
|
159
|
+
components.push(nodes);
|
|
160
|
+
}
|
|
161
|
+
components.sort((a, b) => b.length - a.length || a[0] - b[0]);
|
|
162
|
+
return components;
|
|
163
|
+
}
|
|
164
|
+
function componentLayout(nodes, adjacency) {
|
|
165
|
+
if (nodes.length === 1)
|
|
166
|
+
return new Map([[nodes[0], { x: 0.5, y: 0.5 }]]);
|
|
167
|
+
const nodeToLocal = new Map(nodes.map((node, i) => [node, i]));
|
|
168
|
+
const seed = nodes.reduce((best, node) => adjacency[node].length > adjacency[best].length ||
|
|
169
|
+
(adjacency[node].length === adjacency[best].length && node < best)
|
|
170
|
+
? node
|
|
171
|
+
: best);
|
|
172
|
+
const order = bfsOrder(seed, adjacency);
|
|
173
|
+
const golden = Math.PI * (3 - Math.sqrt(5));
|
|
174
|
+
const pos = Array.from({ length: nodes.length }, () => ({ x: 0.5, y: 0.5 }));
|
|
175
|
+
const initial = Array.from({ length: nodes.length }, () => ({ x: 0.5, y: 0.5 }));
|
|
176
|
+
for (let rank = 0; rank < order.length; rank++) {
|
|
177
|
+
const local = nodeToLocal.get(order[rank]);
|
|
178
|
+
if (local === undefined)
|
|
179
|
+
continue;
|
|
180
|
+
const r = 0.47 * Math.sqrt((rank + 0.5) / nodes.length);
|
|
181
|
+
const theta = rank * golden;
|
|
182
|
+
const p = {
|
|
183
|
+
x: 0.5 + r * Math.cos(theta),
|
|
184
|
+
y: 0.5 + r * Math.sin(theta)
|
|
185
|
+
};
|
|
186
|
+
pos[local] = { ...p };
|
|
187
|
+
initial[local] = p;
|
|
188
|
+
}
|
|
189
|
+
const localEdges = [];
|
|
190
|
+
for (const node of nodes) {
|
|
191
|
+
const a = nodeToLocal.get(node);
|
|
192
|
+
for (const next of adjacency[node]) {
|
|
193
|
+
if (next <= node)
|
|
194
|
+
continue;
|
|
195
|
+
const b = nodeToLocal.get(next);
|
|
196
|
+
if (b !== undefined)
|
|
197
|
+
localEdges.push([a, b]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
relaxEdges(pos, initial, localEdges);
|
|
201
|
+
const out = new Map();
|
|
202
|
+
const normalized = normalize(pos);
|
|
203
|
+
for (const [i, node] of nodes.entries())
|
|
204
|
+
out.set(node, normalized[i]);
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
function bfsOrder(seed, adjacency) {
|
|
208
|
+
const seen = new Uint8Array(adjacency.length);
|
|
209
|
+
const order = [];
|
|
210
|
+
const queue = [seed];
|
|
211
|
+
seen[seed] = 1;
|
|
212
|
+
for (let head = 0; head < queue.length; head++) {
|
|
213
|
+
const node = queue[head];
|
|
214
|
+
order.push(node);
|
|
215
|
+
for (const next of adjacency[node]) {
|
|
216
|
+
if (seen[next])
|
|
217
|
+
continue;
|
|
218
|
+
seen[next] = 1;
|
|
219
|
+
queue.push(next);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return order;
|
|
223
|
+
}
|
|
224
|
+
function relaxEdges(pos, initial, edges) {
|
|
225
|
+
const n = pos.length;
|
|
226
|
+
const disp = Array.from({ length: n }, () => ({ x: 0, y: 0 }));
|
|
227
|
+
const rest = Math.max(0.012, Math.min(0.06, 1.4 / Math.sqrt(n)));
|
|
228
|
+
const iters = n <= 2000 ? 72 : n <= 10000 ? 42 : 24;
|
|
229
|
+
for (let iter = 0; iter < iters; iter++) {
|
|
230
|
+
for (const d of disp) {
|
|
231
|
+
d.x = 0;
|
|
232
|
+
d.y = 0;
|
|
233
|
+
}
|
|
234
|
+
for (const [i, j] of edges) {
|
|
235
|
+
const dx = pos[j].x - pos[i].x;
|
|
236
|
+
const dy = pos[j].y - pos[i].y;
|
|
237
|
+
const dist = Math.hypot(dx, dy) + 1e-9;
|
|
238
|
+
const f = (dist - rest) * 0.045;
|
|
239
|
+
const fx = (dx / dist) * f;
|
|
240
|
+
const fy = (dy / dist) * f;
|
|
241
|
+
disp[i].x += fx;
|
|
242
|
+
disp[i].y += fy;
|
|
243
|
+
disp[j].x -= fx;
|
|
244
|
+
disp[j].y -= fy;
|
|
245
|
+
}
|
|
246
|
+
for (let i = 0; i < n; i++) {
|
|
247
|
+
disp[i].x += (initial[i].x - pos[i].x) * 0.012;
|
|
248
|
+
disp[i].y += (initial[i].y - pos[i].y) * 0.012;
|
|
249
|
+
}
|
|
250
|
+
const t = 0.055 * (1 - iter / iters) + 0.002;
|
|
251
|
+
for (let i = 0; i < n; i++) {
|
|
252
|
+
const d = Math.hypot(disp[i].x, disp[i].y) + 1e-9;
|
|
253
|
+
const s = Math.min(d, t) / d;
|
|
254
|
+
pos[i].x = clamp(pos[i].x + disp[i].x * s);
|
|
255
|
+
pos[i].y = clamp(pos[i].y + disp[i].y * s);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function normalize(pos) {
|
|
260
|
+
const { min: minX, max: maxX } = extent(pos.map((p) => p.x));
|
|
261
|
+
const { min: minY, max: maxY } = extent(pos.map((p) => p.y));
|
|
262
|
+
const sx = maxX - minX || 1;
|
|
263
|
+
const sy = maxY - minY || 1;
|
|
264
|
+
return pos.map((p) => ({
|
|
265
|
+
x: 0.04 + ((p.x - minX) / sx) * 0.92,
|
|
266
|
+
y: 0.04 + ((p.y - minY) / sy) * 0.92
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
function clamp(v) {
|
|
270
|
+
return Math.max(0, Math.min(1, v));
|
|
271
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { CaseSummary, DemandDeltas, Network, NetworkBranch, NetworkBus, SensitivityColumn, Solution, SolveIteration, SolveStreamHandlers } from './api.js';
|
|
2
|
+
export type { DisplayOption } from './display.js';
|
|
3
|
+
export type { PlacedNetwork, PlacementCenter } from './synthetic-layout.js';
|
|
4
|
+
export type { DemandRangeMode, DisplayMode, FallbackTarget, LocalCaseInit, LocalSubstations, SolvableCase, SolveBackend } from './state.svelte.js';
|
|
5
|
+
export type { AppliedGeoCase, CaseFileSummary, DisplayPreview, Formulation, GeoApplyReport, IngestedCase, ParsedGeoLayer, StampedLayoutCase, Topology, TopologyBranch, TopologyBus } from '@tellegen/engine';
|
|
6
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/lib/types.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC5E,YAAY,EACX,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACX,cAAc,EACd,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,WAAW,EACX,MAAM,kBAAkB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|