@sailingrotevista/rotevista-dash 2.0.23 → 3.0.1
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/app.js +66 -37
- package/index.html +90 -160
- package/package.json +1 -1
- package/style.css +335 -231
package/app.js
CHANGED
|
@@ -308,10 +308,14 @@ function startDisplayLoop() {
|
|
|
308
308
|
if (tick % 2 === 0) { refreshGraph('stw'); refreshGraph(displayModeSog === 'VMG' ? 'vmg' : 'sog'); refreshGraph('depth'); refreshGraph('tws'); }
|
|
309
309
|
|
|
310
310
|
// SLOW TIER (3s)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
if (tick % 3 === 0) {
|
|
312
|
+
// Utilizziamo CONFIG.averages.longWindow (che ora è 30000ms)
|
|
313
|
+
// In questo modo, se cambi il tempo su Signal K, la dashboard si aggiorna da sola.
|
|
314
|
+
let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averages.longWindow, false),
|
|
315
|
+
cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averages.longWindow, false),
|
|
316
|
+
awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averages.longWindow, true),
|
|
317
|
+
twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averages.longWindow, true),
|
|
318
|
+
twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averages.longWindow, false);
|
|
315
319
|
|
|
316
320
|
const upUI = (el, obj, isCompass = false) => {
|
|
317
321
|
if (!obj || obj.val === null) { el.innerHTML = "---°"; el.classList.remove('unstable-data'); }
|
|
@@ -418,47 +422,72 @@ function drawGraph(d, id, min, max, isTws, isHercules) {
|
|
|
418
422
|
// 8. INTERAZIONI E RETE
|
|
419
423
|
// ==========================================================================
|
|
420
424
|
function toggleFocusMode(type, element) {
|
|
421
|
-
const container = document.querySelector('.main-container');
|
|
425
|
+
const container = document.querySelector('.main-container');
|
|
426
|
+
|
|
427
|
+
// Con la nuova struttura Flat HTML, non abbiamo più '.left-panel'.
|
|
428
|
+
// Dobbiamo determinare il lato guardando il tipo di box.
|
|
429
|
+
const leftBoxes = ['stw', 'sog', 'hdg', 'cog', 'tack'];
|
|
430
|
+
const isLeft = leftBoxes.includes(type);
|
|
431
|
+
|
|
422
432
|
isFocusActive = !isFocusActive;
|
|
423
|
-
|
|
424
|
-
|
|
433
|
+
|
|
434
|
+
if (isFocusActive) {
|
|
435
|
+
container.classList.add('focus-active', isLeft ? 'focus-side-left' : 'focus-side-right');
|
|
436
|
+
element.classList.add('is-focused');
|
|
437
|
+
} else {
|
|
438
|
+
container.classList.remove('focus-active', 'focus-side-left', 'focus-side-right');
|
|
439
|
+
document.querySelectorAll('.data-box').forEach(b => b.classList.remove('is-focused'));
|
|
440
|
+
}
|
|
425
441
|
}
|
|
426
442
|
|
|
427
443
|
['stw', 'sog', 'tws', 'depth'].forEach(type => {
|
|
444
|
+
// Risale dal grafico al contenitore principale (funziona con la nuova struttura)
|
|
428
445
|
const el = document.getElementById(type + '-graph').closest('.data-box');
|
|
429
446
|
let lastTapTime = 0, tapTimeout, isLongPressActive = false;
|
|
430
|
-
|
|
431
|
-
el.addEventListener('
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
clearTimeout(tapTimeout); // Cancella l'azione del tap singolo (uscita dal focus)
|
|
438
|
-
|
|
439
|
-
// Permette il toggle Hercules sempre, sia in vista normale che in Focus
|
|
440
|
-
graphModes[type] = graphModes[type] === 'standard' ? 'hercules' : 'standard';
|
|
441
|
-
localStorage.setItem('mode_' + type, graphModes[type]);
|
|
442
|
-
|
|
447
|
+
|
|
448
|
+
el.addEventListener('pointerdown', (e) => {
|
|
449
|
+
isLongPressActive = false;
|
|
450
|
+
pressTimer = setTimeout(() => {
|
|
451
|
+
if (!isFocusActive) {
|
|
452
|
+
isLongPressActive = true;
|
|
453
|
+
toggleFocusMode(type, el);
|
|
443
454
|
lastTapTime = 0;
|
|
444
455
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
456
|
+
}, 1000);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
el.addEventListener('pointerup', (e) => {
|
|
460
|
+
clearTimeout(pressTimer);
|
|
461
|
+
if (isLongPressActive) return; // Se era focus, ignora l'up
|
|
462
|
+
|
|
463
|
+
const currentTime = new Date().getTime(), tapDelay = currentTime - lastTapTime;
|
|
464
|
+
|
|
465
|
+
// DOPPIO TAP: Toggle Hercules Mode (Funziona anche in Focus)
|
|
466
|
+
if (tapDelay < 300 && tapDelay > 0) {
|
|
467
|
+
clearTimeout(tapTimeout); // Cancella l'uscita dal Focus
|
|
468
|
+
graphModes[type] = graphModes[type] === 'standard' ? 'hercules' : 'standard';
|
|
469
|
+
localStorage.setItem('mode_' + type, graphModes[type]);
|
|
470
|
+
refreshGraph(type); // Mostra istantaneamente
|
|
471
|
+
lastTapTime = 0;
|
|
472
|
+
}
|
|
473
|
+
// TAP SINGOLO (con ritardo di 250ms per aspettare l'eventuale doppio tap)
|
|
474
|
+
else {
|
|
475
|
+
lastTapTime = currentTime;
|
|
476
|
+
tapTimeout = setTimeout(() => {
|
|
477
|
+
// Uscita Focus
|
|
478
|
+
if (isFocusActive && el.classList.contains('is-focused')) {
|
|
479
|
+
toggleFocusMode(type, el);
|
|
480
|
+
}
|
|
481
|
+
// Toggle SOG/VMG (solo se non in focus)
|
|
482
|
+
else if (!isFocusActive && type === 'sog') {
|
|
483
|
+
displayModeSog = (displayModeSog === 'SOG') ? 'VMG' : 'SOG';
|
|
484
|
+
el.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
|
|
485
|
+
setTimeout(() => el.style.backgroundColor = "", 150);
|
|
486
|
+
}
|
|
487
|
+
}, 250); // Attesa critica per il doppio tap
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
462
491
|
el.addEventListener('pointerleave', () => clearTimeout(pressTimer));
|
|
463
492
|
});
|
|
464
493
|
|
package/index.html
CHANGED
|
@@ -12,80 +12,54 @@
|
|
|
12
12
|
<body>
|
|
13
13
|
|
|
14
14
|
<div class="main-container">
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<!-- COLONNA SINISTRA: Dati Rotta e Velocità -->
|
|
18
|
-
<!-- ======================================================= -->
|
|
19
|
-
<div class="side-panel left-panel">
|
|
20
|
-
|
|
21
|
-
<!-- STW: Velocità attraverso l'acqua -->
|
|
22
|
-
<div class="data-box">
|
|
23
|
-
<div class="label-row">
|
|
24
|
-
<span class="label">STW</span>
|
|
25
|
-
<span class="unit">kts</span>
|
|
26
|
-
</div>
|
|
27
|
-
<span class="value" id="stw">0.0</span>
|
|
28
|
-
<div class="graph-wrapper">
|
|
29
|
-
<svg class="sparkline" id="stw-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
30
|
-
<div class="scale-labels" id="stw-scale"></div>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
15
|
+
<!-- STATO CONNESSIONE -->
|
|
16
|
+
<div id="status" class="offline">OFFLINE</div>
|
|
33
17
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
<div class="graph-wrapper">
|
|
42
|
-
<svg class="sparkline" id="sog-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
43
|
-
<div class="scale-labels" id="sog-scale"></div>
|
|
44
|
-
</div>
|
|
18
|
+
<!-- COLONNA SINISTRA -->
|
|
19
|
+
<div class="data-box box-stw">
|
|
20
|
+
<div class="label-row"><span class="label">STW</span><span class="unit">kts</span></div>
|
|
21
|
+
<span class="value" id="stw">0.0</span>
|
|
22
|
+
<div class="graph-wrapper">
|
|
23
|
+
<svg class="sparkline" id="stw-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
24
|
+
<div class="scale-labels" id="stw-scale"></div>
|
|
45
25
|
</div>
|
|
26
|
+
</div>
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
<div class="
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<
|
|
28
|
+
<div class="data-box box-sog">
|
|
29
|
+
<div class="label-row"><span class="label" id="sog-vmg-label">SOG</span><span class="unit">kts</span></div>
|
|
30
|
+
<span class="value" id="sog">0.0</span>
|
|
31
|
+
<div class="graph-wrapper">
|
|
32
|
+
<svg class="sparkline" id="sog-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
33
|
+
<div class="scale-labels" id="sog-scale"></div>
|
|
53
34
|
</div>
|
|
35
|
+
</div>
|
|
54
36
|
|
|
55
|
-
|
|
56
|
-
<div class="
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</div>
|
|
37
|
+
<div class="data-box box-hdg">
|
|
38
|
+
<div class="label-row"><span class="label">HEADING (MEAN)</span></div>
|
|
39
|
+
<span class="value-large" id="hdg">000°</span>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="data-box box-cog">
|
|
43
|
+
<div class="label-row"><span class="label">COG (MEAN)</span></div>
|
|
44
|
+
<span class="value-large" id="cog">000°</span>
|
|
45
|
+
</div>
|
|
62
46
|
|
|
63
|
-
|
|
64
|
-
<div class="
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
<div class="data-box box-tack">
|
|
48
|
+
<div class="label-row"><span class="label">TACK</span></div>
|
|
49
|
+
<div class="dual-value-container">
|
|
50
|
+
<div class="dual-value-col tack-hdg-col">
|
|
51
|
+
<span class="dual-label">HDG</span>
|
|
52
|
+
<span class="value dual-val" id="tack-hdg">---°</span>
|
|
67
53
|
</div>
|
|
68
|
-
<div class="dual-value-
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
<span class="value dual-val" id="tack-hdg">---°</span>
|
|
72
|
-
</div>
|
|
73
|
-
<div class="dual-value-col right-col">
|
|
74
|
-
<span class="dual-label">COG</span>
|
|
75
|
-
<span class="value dual-val" id="tack-cog">---°</span>
|
|
76
|
-
</div>
|
|
54
|
+
<div class="dual-value-col tack-cog-col">
|
|
55
|
+
<span class="dual-label">COG</span>
|
|
56
|
+
<span class="value dual-val" id="tack-cog">---°</span>
|
|
77
57
|
</div>
|
|
78
58
|
</div>
|
|
79
|
-
|
|
80
59
|
</div>
|
|
81
60
|
|
|
82
|
-
<!--
|
|
83
|
-
|
|
84
|
-
<!-- ======================================================= -->
|
|
85
|
-
<div class="center-panel">
|
|
86
|
-
<!-- Stato Connessione integrato nell'angolo del pannello centrale -->
|
|
87
|
-
<div id="status" class="offline">OFFLINE</div>
|
|
88
|
-
|
|
61
|
+
<!-- BUSSOLA CENTRALE -->
|
|
62
|
+
<div class="box-gauge">
|
|
89
63
|
<svg id="wind-gauge" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet">
|
|
90
64
|
<defs>
|
|
91
65
|
<clipPath id="boat-clip"><circle cx="200" cy="200" r="50" /></clipPath>
|
|
@@ -116,26 +90,21 @@
|
|
|
116
90
|
<circle cx="200" cy="200" r="160" fill="#050505" />
|
|
117
91
|
<circle cx="200" cy="200" r="125" fill="#121212" />
|
|
118
92
|
|
|
119
|
-
<path d="M 82.0 101.0 A 154 154 0 0 1 142.3 57.2" fill="none" stroke="#ff0000" stroke-width="12"
|
|
120
|
-
<path d="M 257.7 57.2 A 154 154 0 0 1 318.0 101.0" fill="none" stroke="#00ff00" stroke-width="12"
|
|
121
|
-
<path d="M 265.1 339.6 A 154 154 0 0 1 134.9 339.6" fill="none" stroke="#ff8800" stroke-width="12"
|
|
93
|
+
<path d="M 82.0 101.0 A 154 154 0 0 1 142.3 57.2" fill="none" stroke="#ff0000" stroke-width="12" />
|
|
94
|
+
<path d="M 257.7 57.2 A 154 154 0 0 1 318.0 101.0" fill="none" stroke="#00ff00" stroke-width="12" />
|
|
95
|
+
<path d="M 265.1 339.6 A 154 154 0 0 1 134.9 339.6" fill="none" stroke="#ff8800" stroke-width="12" />
|
|
122
96
|
|
|
123
97
|
<g id="ticks"></g>
|
|
124
98
|
|
|
125
|
-
<!-- Etichette riposizionate con raggio ridotto per un contatto perfetto con la ghiera -->
|
|
126
99
|
<g id="tick-labels" fill="#bbb" text-anchor="middle" dominant-baseline="middle" font-family="Arial" font-weight="bold">
|
|
127
|
-
<!-- Etichette Principali (Distanza 126px) -->
|
|
128
100
|
<text font-size="16" transform="translate(200, 74)">0</text>
|
|
129
101
|
<text font-size="16" transform="translate(326, 200) rotate(90)">90</text>
|
|
130
102
|
<text font-size="16" transform="translate(74, 200) rotate(-90)">90</text>
|
|
131
103
|
<text font-size="16" transform="translate(200, 326) rotate(180)">180</text>
|
|
132
|
-
|
|
133
|
-
<!-- Etichette Intermedie (Distanza 125px) -->
|
|
134
104
|
<text font-size="11" transform="translate(262.5, 91.7) rotate(30)">30</text>
|
|
135
105
|
<text font-size="11" transform="translate(308.3, 137.5) rotate(60)">60</text>
|
|
136
106
|
<text font-size="11" transform="translate(308.3, 262.5) rotate(120)">120</text>
|
|
137
107
|
<text font-size="11" transform="translate(262.5, 308.3) rotate(150)">150</text>
|
|
138
|
-
|
|
139
108
|
<text font-size="11" transform="translate(137.5, 91.7) rotate(-30)">30</text>
|
|
140
109
|
<text font-size="11" transform="translate(91.7, 137.5) rotate(-60)">60</text>
|
|
141
110
|
<text font-size="11" transform="translate(91.7, 262.5) rotate(-120)">120</text>
|
|
@@ -149,131 +118,92 @@
|
|
|
149
118
|
<circle id="fullscreen-hotspot" cx="200" cy="200" r="55" fill="#181818" stroke="#333" stroke-width="1" filter="url(#center-glow)" cursor="pointer" />
|
|
150
119
|
|
|
151
120
|
<path id="boat-icon" d="M200,150 Q165,185 170,250 Q165,190 200,173 Q235,190 230,250 Q235,185 200,150 Z"
|
|
152
|
-
fill="url(#axiom-grad)"
|
|
153
|
-
transform="translate(0, 5)"
|
|
154
|
-
clip-path="url(#boat-clip)"
|
|
155
|
-
style="pointer-events: none;" />
|
|
121
|
+
fill="url(#axiom-grad)" transform="translate(0, 5)" clip-path="url(#boat-clip)" style="pointer-events: none;" />
|
|
156
122
|
|
|
157
123
|
<g id="aws-display-group" transform="translate(200, 265)">
|
|
158
124
|
<text x="0" y="0" fill="#777" font-size="10" font-weight="bold" text-anchor="middle" text-transform="uppercase">Apparent Wind kts</text>
|
|
159
125
|
<text id="aws-val-svg" x="0" y="42" fill="#fff" font-size="52" font-weight="bold" text-anchor="middle">0.0</text>
|
|
160
126
|
</g>
|
|
161
127
|
|
|
162
|
-
<!-- Lancetta Apparente (AWA) - Versione allungata -->
|
|
163
128
|
<g id="awa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
|
|
164
|
-
|
|
165
|
-
<path d="M 200,70 L 213,95 L 200,145 L 187,95 Z"
|
|
166
|
-
fill="#ff8c00" stroke="#000" stroke-width="1" />
|
|
129
|
+
<path d="M 200,70 L 213,95 L 200,145 L 187,95 Z" fill="#ff8c00" stroke="#000" stroke-width="1" />
|
|
167
130
|
<text x="200" y="90" fill="#000" font-size="10" font-weight="900" text-anchor="middle" font-family="Arial Black">A</text>
|
|
168
131
|
</g>
|
|
169
132
|
|
|
170
|
-
<!-- Lancetta Reale (TWA) - FORMA A GOCCIA (Secondaria/Piccola) -->
|
|
171
133
|
<g id="twa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
|
|
172
|
-
<!-- Goccia piccola: inizia a y=92, punta a y=128 -->
|
|
173
134
|
<path d="M 200,92 A 8,8 0 0 1 208,100 C 208,108 200,128 200,128 C 200,128 192,108 192,100 A 8,8 0 0 1 200,92 Z"
|
|
174
135
|
fill="#ffff00" stroke="#000" stroke-width="0.8" />
|
|
175
136
|
<text x="200" y="106" fill="#000" font-size="9" font-weight="900" text-anchor="middle" font-family="Arial Black">T</text>
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<circle id="trend-gauge-cw" cx="215" cy="110" r="4" fill="#ffffff" />
|
|
179
|
-
<circle id="trend-gauge-ccw" cx="185" cy="110" r="4" fill="#ffffff" />
|
|
137
|
+
<circle id="trend-gauge-cw" cx="215" cy="110" r="4" fill="#bbb" />
|
|
138
|
+
<circle id="trend-gauge-ccw" cx="185" cy="110" r="4" fill="#bbb" />
|
|
180
139
|
</g>
|
|
181
140
|
|
|
182
141
|
<g transform="translate(75, 395)">
|
|
183
142
|
<text x="125" y="-12" id="leeway-val" fill="#aaa" font-size="11" text-anchor="middle" font-weight="bold">LEEWAY: 0.0°</text>
|
|
184
143
|
<rect x="0" y="0" width="250" height="12" fill="#222" rx="3" />
|
|
185
144
|
<rect x="0" y="0" width="250" height="12" fill="url(#leeway-grad)" clip-path="url(#leeway-clip)" rx="3" />
|
|
186
|
-
|
|
187
|
-
<!-- RIPRISTINO SCALA: Tacche ogni 5 gradi (31.25px per intervallo) -->
|
|
188
145
|
<g stroke="#555" stroke-width="1">
|
|
189
|
-
<line x1="0" y1="-2" x2="0" y2="14"
|
|
190
|
-
<line x1="
|
|
191
|
-
<line x1="
|
|
192
|
-
<line x1="93.75" y1="3" x2="93.75" y2="9" /> <!-- -5° -->
|
|
193
|
-
<line x1="125" y1="-2" x2="125" y2="14" /> <!-- 0° centrale -->
|
|
194
|
-
<line x1="156.25" y1="3" x2="156.25" y2="9" /> <!-- +5° -->
|
|
195
|
-
<line x1="187.5" y1="2" x2="187.5" y2="10" /> <!-- +10° -->
|
|
196
|
-
<line x1="218.75" y1="2" x2="218.75" y2="10" /> <!-- +15° -->
|
|
197
|
-
<line x1="250" y1="-2" x2="250" y2="14" /> <!-- +20° -->
|
|
146
|
+
<line x1="0" y1="-2" x2="0" y2="14" /><line x1="62.5" y1="2" x2="62.5" y2="10" />
|
|
147
|
+
<line x1="125" y1="-2" x2="125" y2="14" /><line x1="187.5" y1="2" x2="187.5" y2="10" />
|
|
148
|
+
<line x1="250" y1="-2" x2="250" y2="14" />
|
|
198
149
|
</g>
|
|
199
|
-
|
|
200
|
-
<!-- Etichette numeriche riallineate -->
|
|
201
150
|
<g fill="#555" font-size="8" text-anchor="middle" font-weight="bold">
|
|
202
|
-
<text x="0" y="24">-20°</text>
|
|
203
|
-
<text x="
|
|
204
|
-
<text x="125" y="24">0°</text>
|
|
205
|
-
<text x="187.5" y="24">10</text>
|
|
151
|
+
<text x="0" y="24">-20°</text><text x="62.5" y="24">-10</text>
|
|
152
|
+
<text x="125" y="24">0°</text><text x="187.5" y="24">10</text>
|
|
206
153
|
<text x="250" y="24">20°</text>
|
|
207
154
|
</g>
|
|
208
155
|
</g>
|
|
209
156
|
</svg>
|
|
210
157
|
</div>
|
|
211
158
|
|
|
212
|
-
<!--
|
|
213
|
-
<!--
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
<div class="
|
|
218
|
-
<div class="
|
|
219
|
-
|
|
220
|
-
<span class="label">DEPTH</span>
|
|
221
|
-
</div>
|
|
222
|
-
<span class="value" id="depth">--.-</span>
|
|
223
|
-
<div class="graph-wrapper">
|
|
224
|
-
<div class="scale-labels" id="depth-scale"></div>
|
|
225
|
-
<svg class="sparkline" id="depth-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
226
|
-
</div>
|
|
159
|
+
<!-- COLONNA DESTRA -->
|
|
160
|
+
<!-- NOTA: Etichetta a SX e Unità a DX nel codice, il CSS usa row-reverse per specchiarli sul bordo -->
|
|
161
|
+
<div class="data-box box-depth">
|
|
162
|
+
<div class="label-row"><span class="label">DEPTH</span><span class="unit">m</span></div>
|
|
163
|
+
<span class="value" id="depth">--.-</span>
|
|
164
|
+
<div class="graph-wrapper">
|
|
165
|
+
<div class="scale-labels" id="depth-scale"></div>
|
|
166
|
+
<svg class="sparkline" id="depth-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
227
167
|
</div>
|
|
168
|
+
</div>
|
|
228
169
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
<
|
|
235
|
-
<div class="graph-wrapper">
|
|
236
|
-
<div class="scale-labels" id="tws-scale"></div>
|
|
237
|
-
<svg class="sparkline" id="tws-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
238
|
-
</div>
|
|
170
|
+
<div class="data-box box-tws">
|
|
171
|
+
<div class="label-row"><span class="label">TWS</span><span class="unit">kts</span></div>
|
|
172
|
+
<span class="value" id="tws">0.0</span>
|
|
173
|
+
<div class="graph-wrapper">
|
|
174
|
+
<div class="scale-labels" id="tws-scale"></div>
|
|
175
|
+
<svg class="sparkline" id="tws-graph" viewBox="0 0 200 40" preserveAspectRatio="none"></svg>
|
|
239
176
|
</div>
|
|
177
|
+
</div>
|
|
240
178
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<span class="value value-large" id="twa-avg">---°</span>
|
|
246
|
-
</div>
|
|
179
|
+
<div class="data-box box-twa">
|
|
180
|
+
<div class="label-row"><span class="label">TWA (MEAN)</span></div>
|
|
181
|
+
<span class="value-large" id="twa-avg">---°</span>
|
|
182
|
+
</div>
|
|
247
183
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<span class="value value-large" id="awa-avg">---°</span>
|
|
253
|
-
</div>
|
|
184
|
+
<div class="data-box box-awa">
|
|
185
|
+
<div class="label-row"><span class="label">AWA (MEAN)</span></div>
|
|
186
|
+
<span class="value-large" id="awa-avg">---°</span>
|
|
187
|
+
</div>
|
|
254
188
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
<
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
</svg>
|
|
273
|
-
<span class="value value-large" id="twd-avg">---°</span>
|
|
274
|
-
</div>
|
|
189
|
+
<div class="data-box box-twd">
|
|
190
|
+
<div class="label-row"><span class="label">TWD (MEAN)</span></div>
|
|
191
|
+
<div class="value-with-compass">
|
|
192
|
+
<svg class="mini-compass" viewBox="0 0 40 40">
|
|
193
|
+
<circle cx="20" cy="20" r="18.5" fill="none" stroke="rgba(0,0,0,0.1)" stroke-width="1.2"/>
|
|
194
|
+
<text x="20" y="8" fill="#e74c3c" font-size="5.5" text-anchor="middle" font-weight="900">N</text>
|
|
195
|
+
<text x="20" y="36" fill="#000" font-size="5.5" text-anchor="middle" font-weight="900">S</text>
|
|
196
|
+
<g id="twd-boat-wrap" transform="rotate(0, 20, 20)">
|
|
197
|
+
<path d="M 20,17 L 17,26 L 20,24.5 L 23,26 Z" fill="#000" opacity="0.3" />
|
|
198
|
+
</g>
|
|
199
|
+
<g id="twd-arrow" transform="rotate(0, 20, 20)">
|
|
200
|
+
<path id="twd-wind-chevron" d="M 17,5 L 20,7.5 L 23,5" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" />
|
|
201
|
+
<circle id="trend-dot-cw" cx="24" cy="7.5" r="1.5" fill="#bbb" />
|
|
202
|
+
<circle id="trend-dot-ccw" cx="16" cy="7.5" r="1.5" fill="#bbb" />
|
|
203
|
+
</g>
|
|
204
|
+
</svg>
|
|
205
|
+
<span class="value-large" id="twd-avg">---°</span>
|
|
275
206
|
</div>
|
|
276
|
-
|
|
277
207
|
</div>
|
|
278
208
|
</div>
|
|
279
209
|
|
package/package.json
CHANGED
package/style.css
CHANGED
|
@@ -2,235 +2,351 @@
|
|
|
2
2
|
1. BASE E RESET DI SISTEMA
|
|
3
3
|
========================================================================== */
|
|
4
4
|
body {
|
|
5
|
-
background-color: #fff;
|
|
6
|
-
color: #000;
|
|
5
|
+
background-color: #fff;
|
|
6
|
+
color: #000;
|
|
7
7
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
|
8
|
-
margin: 0;
|
|
9
|
-
|
|
10
|
-
height: 100vh;
|
|
11
|
-
width: 100vw;
|
|
8
|
+
margin: 0; padding: 0;
|
|
9
|
+
height: 100vh; width: 100vw;
|
|
12
10
|
overflow: hidden;
|
|
13
|
-
|
|
14
|
-
-webkit-touch-callout: none;
|
|
15
|
-
-webkit-user-select: none;
|
|
16
|
-
user-select: none;
|
|
17
|
-
touch-action: none;
|
|
11
|
+
-webkit-touch-callout: none; -webkit-user-select: none; user-select: none; touch-action: none;
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
/* ==========================================================================
|
|
21
|
-
2. LAYOUT PRINCIPALE (
|
|
15
|
+
2. LAYOUT PRINCIPALE (GRID AREAS)
|
|
22
16
|
========================================================================== */
|
|
23
17
|
.main-container {
|
|
24
18
|
display: grid;
|
|
25
|
-
width: 100%;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
width: 100%; height: 100%;
|
|
20
|
+
padding: 5px; box-sizing: border-box; gap: 8px;
|
|
21
|
+
grid-template-areas:
|
|
22
|
+
"stw gauge depth"
|
|
23
|
+
"sog gauge tws"
|
|
24
|
+
"hdg gauge twa"
|
|
25
|
+
"cog gauge awa"
|
|
26
|
+
"tack gauge twd";
|
|
27
|
+
grid-template-rows: 1.75fr 1.75fr 0.75fr 0.75fr 1.25fr;
|
|
28
|
+
grid-template-columns: 1fr 1.5fr 1fr;
|
|
33
29
|
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
34
|
-
justify-content: stretch;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.side-panel {
|
|
38
|
-
display: flex;
|
|
39
|
-
flex-direction: column;
|
|
40
|
-
background: rgba(0, 0, 0, 0.03); /* Sfondo Day Mode */
|
|
41
|
-
border-radius: 12px;
|
|
42
|
-
height: 100%;
|
|
43
|
-
overflow: hidden;
|
|
44
|
-
gap: 2px; /* Massimizza lo spazio per i 5 box verticali */
|
|
45
30
|
}
|
|
46
31
|
|
|
47
|
-
.
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
overflow: hidden;
|
|
59
|
-
}
|
|
32
|
+
.box-stw { grid-area: stw; }
|
|
33
|
+
.box-sog { grid-area: sog; }
|
|
34
|
+
.box-hdg { grid-area: hdg; }
|
|
35
|
+
.box-cog { grid-area: cog; }
|
|
36
|
+
.box-tack { grid-area: tack; }
|
|
37
|
+
.box-gauge { grid-area: gauge; display: flex; align-items: center; justify-content: center; position: relative; }
|
|
38
|
+
.box-depth { grid-area: depth; }
|
|
39
|
+
.box-tws { grid-area: tws; }
|
|
40
|
+
.box-twa { grid-area: twa; }
|
|
41
|
+
.box-awa { grid-area: awa; }
|
|
42
|
+
.box-twd { grid-area: twd; }
|
|
60
43
|
|
|
61
44
|
/* ==========================================================================
|
|
62
|
-
3. DATA-BOX E
|
|
45
|
+
3. DATA-BOX: STRUTTURA E ALLINEAMENTO (Bordi Schermo & Display Curvi)
|
|
63
46
|
========================================================================== */
|
|
64
47
|
.data-box {
|
|
65
|
-
position: relative;
|
|
66
|
-
|
|
67
|
-
padding:
|
|
68
|
-
display: flex;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
container-type: size; /* Permette l'uso di cqh per i font */
|
|
73
|
-
min-height: 0;
|
|
74
|
-
overflow: hidden;
|
|
48
|
+
position: relative; border-bottom: 1px solid #eee;
|
|
49
|
+
/* Padding alto (1.2rem) per non far toccare il numero al titolo assoluto */
|
|
50
|
+
padding: 1.2rem 8px 4px 8px;
|
|
51
|
+
display: flex; flex-direction: column; width: 100%;
|
|
52
|
+
box-sizing: border-box; container-type: size;
|
|
53
|
+
min-height: 0; overflow: hidden;
|
|
54
|
+
background: rgba(0, 0, 0, 0.03); border-radius: 12px;
|
|
75
55
|
transition: background-color 0.2s ease;
|
|
56
|
+
/* Forza la centratura verticale del valore per display curvi */
|
|
57
|
+
justify-content: center !important;
|
|
76
58
|
}
|
|
77
59
|
|
|
78
|
-
/*
|
|
79
|
-
.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.right-panel .label-row { flex-direction: row-reverse !important; }
|
|
84
|
-
|
|
85
|
-
/* NUOVE PROPORZIONI VERTICALI 1.75 / 0.75 / 1.25 */
|
|
86
|
-
.data-box:nth-child(1), .data-box:nth-child(2) { flex: 1.75 1 0px; }
|
|
87
|
-
.data-box:nth-child(3), .data-box:nth-child(4) { flex: 0.75 0.75 0px; }
|
|
88
|
-
.data-box:nth-child(5) { flex: 1.25 1 0px; border-bottom: none; }
|
|
60
|
+
/* Titoli ancorati sempre in alto */
|
|
61
|
+
.label-row {
|
|
62
|
+
position: absolute; top: 4px; left: 8px; right: 8px;
|
|
63
|
+
display: flex; align-items: baseline; z-index: 10;
|
|
64
|
+
}
|
|
89
65
|
|
|
90
|
-
.label-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2px; width: 100%; }
|
|
91
66
|
.label { color: #888; font-size: 0.65rem; font-weight: bold; text-transform: uppercase; }
|
|
92
67
|
.unit { color: #aaa; font-size: 0.6rem; font-weight: bold; }
|
|
93
68
|
|
|
94
|
-
/*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
letter-spacing: -1px;
|
|
101
|
-
padding-bottom: 5px;
|
|
69
|
+
/* --- ALLINEAMENTO SPECULARE RIGIDO --- */
|
|
70
|
+
|
|
71
|
+
/* COLONNA SINISTRA: Titolo a SX (bordo), Unità a DX */
|
|
72
|
+
.box-stw, .box-sog, .box-hdg, .box-cog, .box-tack { align-items: flex-start !important; text-align: left !important; }
|
|
73
|
+
.box-stw .label-row, .box-sog .label-row, .box-hdg .label-row, .box-cog .label-row, .box-tack .label-row {
|
|
74
|
+
flex-direction: row !important; justify-content: space-between !important;
|
|
102
75
|
}
|
|
103
76
|
|
|
104
|
-
/*
|
|
105
|
-
.
|
|
106
|
-
|
|
107
|
-
|
|
77
|
+
/* COLONNA DESTRA: Titolo a DX (bordo), Unità a SX */
|
|
78
|
+
.box-depth, .box-tws, .box-twa, .box-awa, .box-twd { align-items: flex-end !important; text-align: right !important; }
|
|
79
|
+
.box-depth .label-row, .box-tws .label-row, .box-twa .label-row, .box-awa .label-row, .box-twd .label-row {
|
|
80
|
+
flex-direction: row-reverse !important; justify-content: space-between !important;
|
|
108
81
|
}
|
|
109
82
|
|
|
110
|
-
|
|
83
|
+
/* ==========================================================================
|
|
84
|
+
4. TIPOGRAFIA GERARCHICA (REGOLE BASE)
|
|
85
|
+
========================================================================== */
|
|
86
|
+
.value { color: #000; font-size: clamp(1.2rem, 32cqw, 3.5rem); font-weight: 600; line-height: 0.9; letter-spacing: -1.5px; }
|
|
111
87
|
|
|
112
|
-
/*
|
|
113
|
-
.value-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
align-items: center;
|
|
117
|
-
width: 100%;
|
|
118
|
-
align-self: stretch; /* Impedisce al pannello DX di schiacciare il widget a destra */
|
|
119
|
-
gap: 5px;
|
|
88
|
+
/* Valore MASSIVO (Dati reali): 55% altezza box, larghezza protetta a 22% schermo */
|
|
89
|
+
.value-large {
|
|
90
|
+
font-size: clamp(1.5rem, 55cqh, 22cqw) !important;
|
|
91
|
+
font-weight: 600; line-height: 0.8; margin: 0 !important;
|
|
120
92
|
}
|
|
121
93
|
|
|
122
|
-
/*
|
|
123
|
-
.
|
|
124
|
-
.
|
|
125
|
-
.
|
|
126
|
-
|
|
94
|
+
/* BOX TWD: Bussola a SX, Valore a DX, centrati verticalmente */
|
|
95
|
+
.value-with-compass { display: flex; flex-direction: row; justify-content: space-between; align-items: center; width: 100%; height: 85%; }
|
|
96
|
+
.box-twd .mini-compass { height: 85cqh !important; width: auto !important; aspect-ratio: 1/1; flex-shrink: 0; }
|
|
97
|
+
.box-twd #twd-avg { font-size: clamp(1.5rem, 55cqh, 20cqw) !important; text-align: right; line-height: 1; }
|
|
98
|
+
|
|
99
|
+
/* BOX TACK: HDG a SX, COG a DX, Titoli sopra (Default Landscape/Portrait) */
|
|
100
|
+
.box-tack .dual-value-container { display: flex; flex-direction: row; justify-content: space-between; align-items: center; width: 100%; height: 100%; }
|
|
101
|
+
.box-tack .dual-value-col { display: flex; flex-direction: column; justify-content: center; }
|
|
102
|
+
.box-tack .dual-value-col:first-child { align-items: flex-start; }
|
|
103
|
+
.box-tack .dual-value-col:last-child { align-items: flex-end; }
|
|
104
|
+
.box-tack .dual-label { color: #888; font-size: 0.5rem; font-weight: 800; margin-bottom: -2px; }
|
|
105
|
+
.box-tack .value.dual-val { font-size: clamp(1rem, 35cqh, 12cqw) !important; line-height: 0.9; }
|
|
106
|
+
|
|
107
|
+
/* Tag HERCULES: Allineato all'unità (lato interno schermo) */
|
|
108
|
+
.box-hercules { background: rgba(255, 0, 0, 0.05) !important; }
|
|
109
|
+
.box-hercules .unit::before { font-size: 7px; color: #ff4444; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; content: "HERCULES "; }
|
|
127
110
|
|
|
128
111
|
/* ==========================================================================
|
|
129
|
-
|
|
112
|
+
5. TACTICAL FOCUS MODE
|
|
130
113
|
========================================================================== */
|
|
131
|
-
.focus-active .
|
|
132
|
-
|
|
133
|
-
/* Split: 60% per il grafico scelto, 40% per il vento centrale */
|
|
134
|
-
.focus-active.focus-side-left { grid-template-columns: 3fr 2fr !important; }
|
|
135
|
-
.focus-active.focus-side-left .side-panel.has-focus { grid-column: 1 !important; }
|
|
136
|
-
.focus-active.focus-side-left .center-panel { grid-column: 2 !important; justify-content: center !important; align-items: center !important; }
|
|
114
|
+
.focus-active .data-box:not(.is-focused),
|
|
115
|
+
.focus-active .box-gauge { display: none !important; }
|
|
137
116
|
|
|
138
|
-
.focus-active.focus-side-
|
|
139
|
-
|
|
140
|
-
|
|
117
|
+
.focus-active.focus-side-left {
|
|
118
|
+
grid-template-columns: 3fr 2fr !important;
|
|
119
|
+
grid-template-areas: "focused gauge" !important;
|
|
120
|
+
grid-template-rows: 100% !important;
|
|
121
|
+
}
|
|
122
|
+
.focus-active.focus-side-right {
|
|
123
|
+
grid-template-columns: 2fr 3fr !important;
|
|
124
|
+
grid-template-areas: "gauge focused" !important;
|
|
125
|
+
grid-template-rows: 100% !important;
|
|
126
|
+
}
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
.focus-active .has-focus .data-box.is-focused {
|
|
128
|
+
.focus-active .is-focused {
|
|
129
|
+
grid-area: focused !important;
|
|
145
130
|
height: 100vh !important;
|
|
146
|
-
|
|
147
|
-
background: rgba(0, 0, 0, 0.02);
|
|
131
|
+
background: rgba(0, 0, 0, 0.02) !important;
|
|
148
132
|
padding: 2vw 3vw !important;
|
|
149
|
-
|
|
150
|
-
|
|
133
|
+
justify-content: center !important;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* PRIORITÀ COLORE HERCULES IN FOCUS:
|
|
137
|
+
Forza lo sfondo rosso anche quando il box è ingrandito */
|
|
138
|
+
.focus-active .is-focused.box-hercules {
|
|
139
|
+
background: rgba(255, 0, 0, 0.12) !important;
|
|
140
|
+
box-shadow: inset 0 0 30px rgba(255, 0, 0, 0.1);
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
.focus-active .is-focused .value { font-size: clamp(4rem, 25cqh,
|
|
154
|
-
.focus-active .
|
|
155
|
-
.focus-active .is-focused .label-row .label { font-size: 2rem !important; }
|
|
156
|
-
.focus-active .is-focused .label-row .unit { font-size: 2rem !important; }
|
|
157
|
-
.focus-active .is-focused .sparkline path { stroke-width: 2.5px !important; }
|
|
143
|
+
.focus-active .is-focused .value { font-size: clamp(4rem, 25cqh, 15rem) !important; margin-top: 20px; }
|
|
144
|
+
.focus-active .box-gauge { display: flex !important; grid-area: gauge !important; }
|
|
158
145
|
|
|
159
|
-
|
|
146
|
+
/* ==========================================================================
|
|
147
|
+
6. VIEWPORT QUADRATA (U-SHAPE) - LOGICA ANTI-COLLISIONE
|
|
148
|
+
========================================================================== */
|
|
149
|
+
@media screen and (min-aspect-ratio: 0.86/1) and (max-aspect-ratio: 1.25/1) {
|
|
150
|
+
.main-container {
|
|
151
|
+
grid-template-columns: 1fr 1fr 1fr 1fr !important;
|
|
152
|
+
grid-template-areas:
|
|
153
|
+
"stw gauge gauge depth"
|
|
154
|
+
"sog gauge gauge tws"
|
|
155
|
+
"hdg gauge gauge twa"
|
|
156
|
+
"cog tack twd awa" !important;
|
|
157
|
+
grid-template-rows: 1.75fr 1.75fr 0.75fr 1.25fr !important;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Sfondo per distinguere la riga tattica inferiore */
|
|
161
|
+
.box-cog, .box-tack, .box-twd, .box-awa {
|
|
162
|
+
border-top: 1px solid #eee;
|
|
163
|
+
background: rgba(0, 0, 0, 0.04) !important;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* --- TACK: Impilamento Verticale Rigido in U-Shape --- */
|
|
167
|
+
.box-tack .dual-value-container {
|
|
168
|
+
flex-direction: column !important; /* Forza HDG sopra COG */
|
|
169
|
+
justify-content: center !important;
|
|
170
|
+
align-items: flex-start !important; /* Tutto a sinistra */
|
|
171
|
+
gap: 8px !important; /* Spazio tra i due blocchi */
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.box-tack .dual-value-col {
|
|
175
|
+
display: flex !important;
|
|
176
|
+
flex-direction: column !important; /* Forza Titolo sopra Numero */
|
|
177
|
+
align-items: flex-start !important;
|
|
178
|
+
text-align: left !important;
|
|
179
|
+
width: 100% !important;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Font calibrato per non uscire dal box stretto */
|
|
183
|
+
.box-tack .value.dual-val {
|
|
184
|
+
font-size: clamp(1rem, 30cqh, 15cqw) !important;
|
|
185
|
+
line-height: 1 !important;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.box-tack .dual-label {
|
|
189
|
+
margin-bottom: 0px !important;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* --- TWD: Calibrazione per box stretto --- */
|
|
193
|
+
.box-twd .value-with-compass { justify-content: center; gap: 5px; }
|
|
194
|
+
.box-twd .mini-compass { height: 60cqh !important; }
|
|
195
|
+
.box-twd #twd-avg { font-size: clamp(1.2rem, 50cqh, 20cqw) !important; }
|
|
196
|
+
|
|
197
|
+
/* NOTA: COG e AWA non vengono toccati qui, così restano massivi
|
|
198
|
+
ereditando la regola generale della Sezione 4 */
|
|
199
|
+
}
|
|
160
200
|
|
|
161
201
|
/* ==========================================================================
|
|
162
|
-
|
|
202
|
+
7. GRAFICI, SCALE E TAG HERCULES
|
|
163
203
|
========================================================================== */
|
|
164
204
|
.graph-wrapper {
|
|
165
|
-
position: relative;
|
|
166
|
-
|
|
167
|
-
|
|
205
|
+
position: relative;
|
|
206
|
+
width: 100%;
|
|
207
|
+
flex-grow: 1;
|
|
208
|
+
min-height: 0;
|
|
209
|
+
margin-top: 5px;
|
|
210
|
+
display: flex;
|
|
211
|
+
flex-direction: row; /* Forza l'allineamento orizzontale dei componenti */
|
|
212
|
+
align-items: stretch;
|
|
213
|
+
background: rgba(0, 0, 0, 0.04);
|
|
214
|
+
border-radius: 4px;
|
|
168
215
|
}
|
|
169
216
|
|
|
170
|
-
.
|
|
171
|
-
|
|
217
|
+
.sparkline {
|
|
218
|
+
flex-grow: 1;
|
|
219
|
+
height: 100%;
|
|
220
|
+
width: 100% !important;
|
|
221
|
+
background: transparent !important;
|
|
222
|
+
}
|
|
172
223
|
|
|
173
|
-
|
|
174
|
-
.sparkline path,
|
|
224
|
+
/* Forza tutte le linee dei grafici (linee dati e griglie) a 1px per un look chirurgico */
|
|
225
|
+
.sparkline path,
|
|
226
|
+
.sparkline line {
|
|
227
|
+
stroke-width: 1px !important;
|
|
228
|
+
transition: all 0.3s ease;
|
|
229
|
+
}
|
|
175
230
|
|
|
176
231
|
.scale-labels {
|
|
177
|
-
display: flex;
|
|
178
|
-
|
|
179
|
-
|
|
232
|
+
display: flex;
|
|
233
|
+
flex-direction: column;
|
|
234
|
+
justify-content: space-between;
|
|
235
|
+
font-size: 9px;
|
|
236
|
+
color: #666;
|
|
237
|
+
font-weight: 800;
|
|
238
|
+
min-width: 22px;
|
|
239
|
+
height: 100%;
|
|
240
|
+
line-height: 1;
|
|
241
|
+
z-index: 5;
|
|
180
242
|
}
|
|
181
243
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
.
|
|
185
|
-
|
|
244
|
+
/* --- COLONNA SINISTRA (STW, SOG) --- */
|
|
245
|
+
/* Ordine desiderato: [Grafico] [Scala] -> Scala verso il centro schermo */
|
|
246
|
+
.box-stw .sparkline, .box-sog .sparkline {
|
|
247
|
+
order: 1;
|
|
248
|
+
}
|
|
249
|
+
.box-stw .scale-labels, .box-sog .scale-labels {
|
|
250
|
+
order: 2;
|
|
251
|
+
text-align: left;
|
|
252
|
+
padding-left: 4px;
|
|
253
|
+
}
|
|
186
254
|
|
|
187
|
-
/*
|
|
188
|
-
|
|
255
|
+
/* --- COLONNA DESTRA (DEPTH, TWS) --- */
|
|
256
|
+
/* Ordine desiderato: [Scala] [Grafico] -> Scala verso il centro schermo */
|
|
257
|
+
.box-depth .scale-labels, .box-tws .scale-labels {
|
|
258
|
+
order: 1;
|
|
259
|
+
text-align: right;
|
|
260
|
+
padding-right: 4px;
|
|
261
|
+
}
|
|
262
|
+
.box-depth .sparkline, .box-tws .sparkline {
|
|
263
|
+
order: 2;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* --- REGOLE HERCULES (Zoom) --- */
|
|
189
267
|
.box-hercules { background: rgba(255, 0, 0, 0.05) !important; }
|
|
190
268
|
.box-hercules .scale-labels { color: #ff5555; }
|
|
191
|
-
.box-hercules .unit::before
|
|
192
|
-
font-size: 7px; color: #ff4444; font-weight: 900;
|
|
269
|
+
.box-hercules .unit::before {
|
|
270
|
+
font-size: 7px; color: #ff4444; font-weight: 900;
|
|
271
|
+
letter-spacing: 1px; text-transform: uppercase; content: "HERCULES ";
|
|
193
272
|
}
|
|
194
|
-
.left-panel .box-hercules .unit::before { content: "HERCULES "; }
|
|
195
|
-
.right-panel .box-hercules .unit::after { content: " HERCULES"; }
|
|
196
|
-
.right-panel .box-hercules .label:only-child::after { content: " HERCULES"; }
|
|
197
273
|
|
|
198
|
-
/*
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
274
|
+
/* Anche in modalità Hercules manteniamo 1px per coerenza, affidandoci al filtro per lo stacco visivo */
|
|
275
|
+
.line-hercules {
|
|
276
|
+
filter: drop-shadow(0 0 5px #ff0000);
|
|
277
|
+
stroke-width: 1px !important;
|
|
278
|
+
}
|
|
203
279
|
|
|
204
280
|
/* ==========================================================================
|
|
205
|
-
|
|
281
|
+
8. RESPONSIVE (PORTRAIT MODE)
|
|
206
282
|
========================================================================== */
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
283
|
+
@media screen and (max-aspect-ratio: 0.85/1) {
|
|
284
|
+
.main-container {
|
|
285
|
+
grid-template-areas:
|
|
286
|
+
"gauge gauge"
|
|
287
|
+
"stw depth"
|
|
288
|
+
"sog tws"
|
|
289
|
+
"hdg twa"
|
|
290
|
+
"cog awa"
|
|
291
|
+
"tack twd" !important;
|
|
292
|
+
grid-template-columns: 1fr 1fr !important;
|
|
293
|
+
grid-template-rows: 40vh 1.75fr 1.75fr 0.75fr 0.75fr 1.25fr !important;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Impedisce ai box di collassare in altezza in verticale */
|
|
297
|
+
.data-box { height: auto !important; }
|
|
298
|
+
|
|
299
|
+
/* --- FOCUS MODE IN VERTICALE (STACKED) --- */
|
|
300
|
+
/* Quando siamo in verticale e attiviamo il focus, impiliamo Sopra/Sotto */
|
|
301
|
+
.main-container.focus-active {
|
|
302
|
+
grid-template-columns: 1fr !important; /* Colonna singola */
|
|
303
|
+
grid-template-rows: 65vh 35vh !important; /* 65% Altezza al dato, 35% alla bussola */
|
|
304
|
+
grid-template-areas:
|
|
305
|
+
"focused"
|
|
306
|
+
"gauge" !important;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Correzione dimensioni box in Focus Verticale */
|
|
310
|
+
.focus-active .is-focused {
|
|
311
|
+
height: 65vh !important;
|
|
312
|
+
width: 100vw !important;
|
|
313
|
+
padding: 5vh 5vw !important; /* Più respiro per display curvi */
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Correzione Bussola in Focus Verticale */
|
|
317
|
+
.focus-active .box-gauge {
|
|
318
|
+
height: 35vh !important;
|
|
319
|
+
width: 100vw !important;
|
|
320
|
+
display: flex !important;
|
|
321
|
+
align-items: center;
|
|
322
|
+
justify-content: center;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Ridimensionamento font per Focus Verticale (per non sbordare) */
|
|
326
|
+
.focus-active .is-focused .value {
|
|
327
|
+
font-size: clamp(4rem, 20cqh, 12rem) !important;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* In verticale il box TACK è largo: forziamo i due valori ai bordi */
|
|
331
|
+
.box-tack .dual-value-container {
|
|
332
|
+
flex-direction: row !important;
|
|
333
|
+
justify-content: space-between !important;
|
|
334
|
+
align-items: center !important;
|
|
335
|
+
}
|
|
213
336
|
}
|
|
337
|
+
|
|
338
|
+
/* ==========================================================================
|
|
339
|
+
9. WIDGETS E OVERRIDE SVG (GIORNO)
|
|
340
|
+
========================================================================== */
|
|
341
|
+
#status { position: absolute; top: 10px; right: 10px; font-size: 0.6rem; font-weight: 900; text-transform: uppercase; z-index: 1000; background: rgba(0,0,0,0.05); padding: 2px 6px; border-radius: 4px; }
|
|
214
342
|
.online { color: #27ae60; opacity: 0.8; }
|
|
215
343
|
.offline { color: #c0392b; font-weight: bold; }
|
|
216
344
|
|
|
217
|
-
.mini-compass {
|
|
218
|
-
width: min(80cqh, 42cqw); height: min(80cqh, 42cqw); aspect-ratio: 1 / 1;
|
|
219
|
-
flex-shrink: 0; background: #f0f0f0; border-radius: 50%; border: 1.5px solid #ddd;
|
|
220
|
-
box-shadow: inset 0 0 10px rgba(0,0,0,0.05); transition: all 0.4s ease;
|
|
221
|
-
}
|
|
222
|
-
|
|
345
|
+
.mini-compass { background: #f0f0f0; border-radius: 50%; border: 1.5px solid #ddd; }
|
|
223
346
|
.mini-compass text:last-of-type { fill: #000 !important; opacity: 0.4; }
|
|
224
347
|
#twd-boat-wrap path { fill: #000 !important; opacity: 0.3; }
|
|
225
348
|
#twd-wind-chevron { stroke: #000 !important; }
|
|
226
349
|
|
|
227
|
-
#awa-pointer, #twa-pointer, #track-pointer, #twd-arrow, #twd-boat-wrap {
|
|
228
|
-
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
#wind-gauge { width: 100%; height: 100%; max-height: 100%; object-fit: contain; }
|
|
232
|
-
|
|
233
|
-
/* Quadrante Vento Centrale - Giorno */
|
|
234
350
|
#wind-gauge circle[fill="#050505"] { fill: #fcfcfc; }
|
|
235
351
|
#wind-gauge circle[fill="#121212"] { fill: #f0f0f0; }
|
|
236
352
|
#boat-icon { fill: #000 !important; opacity: 1; }
|
|
@@ -240,85 +356,88 @@ body {
|
|
|
240
356
|
#fullscreen-hotspot { fill: #eee !important; stroke: #ccc !important; }
|
|
241
357
|
#ticks line[stroke="#fff"] { stroke: #000 !important; }
|
|
242
358
|
#ticks line[stroke="#666"] { stroke: #bbb !important; }
|
|
243
|
-
|
|
244
|
-
/* Leeway Container - Giorno */
|
|
245
359
|
rect[fill="#222"] { fill: #eee !important; }
|
|
246
360
|
#leeway-val { color: #000 !important; }
|
|
247
361
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
========================================================================== */
|
|
251
|
-
.unstable-data { animation: blink-unstable 1.5s infinite ease-in-out; color: #e67e22 !important; }
|
|
252
|
-
.alarm-warning { color: #f39c12 !important; }
|
|
253
|
-
.alarm-danger { color: #e74c3c !important; font-weight: 900; animation: blink-unstable 1s infinite; }
|
|
254
|
-
@keyframes blink-unstable { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
|
|
255
|
-
|
|
256
|
-
/* ==========================================================================
|
|
257
|
-
8. RESPONSIVE (PORTRAIT MODE)
|
|
258
|
-
========================================================================== */
|
|
259
|
-
@media (max-aspect-ratio: 0.9 / 1) {
|
|
260
|
-
.main-container { grid-template-columns: 1fr 1fr !important; grid-template-rows: 45vh calc(55vh - 8px) !important; }
|
|
261
|
-
.center-panel { grid-row: 1 !important; grid-column: 1 / span 2 !important; }
|
|
262
|
-
.left-panel { grid-row: 2 !important; grid-column: 1 !important; }
|
|
263
|
-
.right-panel { grid-row: 2 !important; grid-column: 2 !important; }
|
|
264
|
-
.main-container.focus-active { display: flex !important; flex-direction: column !important; }
|
|
265
|
-
.focus-active .center-panel { flex: 0 0 45vh !important; }
|
|
266
|
-
.focus-active .side-panel.has-focus { flex: 0 0 calc(55vh - 8px) !important; display: flex !important; }
|
|
267
|
-
.data-box { height: auto !important; }
|
|
268
|
-
}
|
|
362
|
+
#awa-pointer, #twa-pointer, #track-pointer, #twd-arrow, #twd-boat-wrap { transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
363
|
+
#wind-gauge { width: 100%; height: 100%; max-height: 100%; object-fit: contain; }
|
|
269
364
|
|
|
270
365
|
/* ==========================================================================
|
|
271
|
-
|
|
366
|
+
10. NIGHT MODE (TACTICAL RED - INTEGRALE E RIFINITO)
|
|
272
367
|
========================================================================== */
|
|
273
368
|
body.night-mode { background-color: #000 !important; color: #ff0000 !important; }
|
|
274
|
-
.night-mode .side-panel { background: rgba(20, 0, 0, 0.4) !important; border: 1px solid #330000; }
|
|
275
|
-
.night-mode .data-box { border-bottom-color: #260000; }
|
|
276
|
-
.night-mode .label, .night-mode .unit, .night-mode .dual-label { color: #800000 !important; }
|
|
277
|
-
.night-mode .value, .night-mode .value-large { color: #ff3333 !important; text-shadow: 0 0 8px rgba(255, 0, 0, 0.4); }
|
|
278
369
|
|
|
279
|
-
/*
|
|
280
|
-
.night-mode .
|
|
281
|
-
.night-mode .
|
|
282
|
-
.night-mode .
|
|
370
|
+
/* Pannelli e Box */
|
|
371
|
+
.night-mode .data-box { background: rgba(20, 0, 0, 0.4) !important; border-color: #330000; }
|
|
372
|
+
.night-mode .label,
|
|
373
|
+
.night-mode .unit,
|
|
374
|
+
.night-mode .dual-label { color: #800000 !important; }
|
|
283
375
|
|
|
284
|
-
|
|
285
|
-
.night-mode .
|
|
286
|
-
|
|
376
|
+
.night-mode .value,
|
|
377
|
+
.night-mode .value-large {
|
|
378
|
+
color: #ff3333 !important;
|
|
379
|
+
text-shadow: 0 0 8px rgba(255, 0, 0, 0.4);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* --- GRAFICI NIGHT MODE: Solo linee, zero abbagliamento --- */
|
|
383
|
+
.night-mode .graph-wrapper { background: rgba(30, 0, 0, 0.3) !important; border: 1px solid #330000; }
|
|
384
|
+
.night-mode .sparkline path:first-of-type { display: none !important; }
|
|
385
|
+
.night-mode .sparkline path {
|
|
386
|
+
fill: none !important;
|
|
387
|
+
stroke: #ff3333 !important;
|
|
388
|
+
stroke-width: 1px !important;
|
|
389
|
+
filter: drop-shadow(0 0 2px rgba(255, 0, 0, 0.4));
|
|
390
|
+
}
|
|
391
|
+
.night-mode .sparkline line { stroke: rgba(150, 0, 0, 0.1) !important; }
|
|
392
|
+
.night-mode #tws-graph line:not([stroke*="rgba"]) {
|
|
393
|
+
stroke: #ff3333 !important;
|
|
394
|
+
stroke-width: 1px !important;
|
|
395
|
+
}
|
|
287
396
|
.night-mode .scale-labels { color: #660000 !important; }
|
|
288
397
|
|
|
398
|
+
/* Hercules in Night Mode */
|
|
289
399
|
.night-mode .box-hercules { background: rgba(60, 0, 0, 0.2) !important; }
|
|
290
400
|
.night-mode .line-hercules { filter: drop-shadow(0 0 6px #ff0000) !important; }
|
|
291
401
|
|
|
292
|
-
/*
|
|
293
|
-
.night-mode #wind-gauge circle
|
|
294
|
-
.night-mode #wind-gauge circle[fill="#
|
|
295
|
-
|
|
402
|
+
/* --- WIND GAUGE NIGHT: Scurimento settori e icone --- */
|
|
403
|
+
.night-mode #wind-gauge circle[fill="#050505"],
|
|
404
|
+
.night-mode #wind-gauge circle[fill="#fcfcfc"] { fill: #050505 !important; }
|
|
405
|
+
|
|
406
|
+
.night-mode #wind-gauge circle[fill="#121212"],
|
|
407
|
+
.night-mode #wind-gauge circle[fill="#f0f0f0"] { fill: #0a0000 !important; }
|
|
408
|
+
|
|
409
|
+
/* Glow e Hotspot centrale */
|
|
296
410
|
.night-mode #fullscreen-hotspot { fill: #000 !important; stroke: #330000 !important; }
|
|
411
|
+
.night-mode #center-glow feDropShadow { flood-color: #ff0000 !important; flood-opacity: 0.6 !important; }
|
|
297
412
|
|
|
298
|
-
.night-mode #ticks line { stroke: #4d0000 !important; }
|
|
299
|
-
.night-mode #tick-labels { fill: #800000 !important; }
|
|
300
413
|
.night-mode #boat-icon { fill: #330000 !important; opacity: 0.6 !important; }
|
|
301
414
|
.night-mode #aws-val-svg { fill: #ff3333 !important; }
|
|
302
|
-
.night-mode #aws-display-group text { fill: #
|
|
303
|
-
|
|
415
|
+
.night-mode #aws-display-group text { fill: #660000 !important; }
|
|
416
|
+
|
|
417
|
+
/* SCALA GRADUATA BUSSOLA: Tacche e numeri rosso cupo */
|
|
418
|
+
.night-mode #ticks line { stroke: #4d0000 !important; }
|
|
419
|
+
.night-mode #tick-labels { fill: #800000 !important; }
|
|
304
420
|
|
|
305
|
-
/*
|
|
421
|
+
/* SETTORI VENTO: Il verde diventa un rosso scuro trattteggiato */
|
|
306
422
|
.night-mode #wind-gauge path[stroke="#ff0000"] { stroke: #660000 !important; opacity: 0.8; }
|
|
307
|
-
.night-mode #wind-gauge path[stroke="#00ff00"] { stroke: #
|
|
423
|
+
.night-mode #wind-gauge path[stroke="#00ff00"] { stroke: #440000 !important; stroke-dasharray: 4, 3; opacity: 0.6; }
|
|
308
424
|
.night-mode #wind-gauge path[stroke="#ff8800"] { stroke: #330000 !important; stroke-width: 8; }
|
|
309
425
|
|
|
310
|
-
/*
|
|
426
|
+
/* --- LEEWAY & POINTERS NIGHT --- */
|
|
311
427
|
.night-mode rect[fill="url(#leeway-grad)"] { fill: url(#leeway-night-grad) !important; }
|
|
312
428
|
.night-mode #leeway-val { fill: #ff3333 !important; }
|
|
429
|
+
.night-mode rect[fill="#222"], .night-mode rect[fill="#eee"] { fill: #0a0000 !important; stroke: #200000; }
|
|
430
|
+
|
|
431
|
+
/* Scala graduata Leeway: tacche e numeri */
|
|
313
432
|
.night-mode g[stroke="#555"] line { stroke: #4d0000 !important; }
|
|
314
433
|
.night-mode g[fill="#555"] text { fill: #660000 !important; }
|
|
315
|
-
.night-mode rect[fill="#222"], .night-mode rect[fill="#eee"] { fill: #0a0000 !important; stroke: #200000; }
|
|
316
434
|
|
|
435
|
+
/* Lancette */
|
|
317
436
|
.night-mode #awa-pointer path { fill: #ff0000; stroke: #000; }
|
|
318
437
|
.night-mode #twa-pointer path { fill: #800000; stroke: #000; }
|
|
319
438
|
.night-mode #track-pointer path { fill: #ff0000; stroke: #fff; stroke-width: 0.5; }
|
|
320
439
|
|
|
321
|
-
/*
|
|
440
|
+
/* --- MINI BUSSOLA TWD NIGHT --- */
|
|
322
441
|
.night-mode .mini-compass { border-color: #330000; background: #000; }
|
|
323
442
|
.night-mode .mini-compass text { fill: #800000 !important; }
|
|
324
443
|
.night-mode .mini-compass text:last-of-type { fill: #800000 !important; opacity: 1; }
|
|
@@ -326,25 +445,10 @@ body.night-mode { background-color: #000 !important; color: #ff0000 !important;
|
|
|
326
445
|
.night-mode #twd-arrow #twd-wind-chevron { stroke: #ff3333 !important; filter: drop-shadow(0 0 4px #ff0000); }
|
|
327
446
|
|
|
328
447
|
/* ==========================================================================
|
|
329
|
-
11. TREND
|
|
448
|
+
11. TREND E ANIMAZIONI
|
|
330
449
|
========================================================================== */
|
|
331
450
|
@keyframes blink-trend { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
transition: opacity 0.3s ease;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/* Quando attivi: brillano al 100% e lampeggiano */
|
|
340
|
-
.is-trending {
|
|
341
|
-
opacity: 1 !important;
|
|
342
|
-
animation: blink-trend 1s infinite !important;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/* Allarme Strambata: Rosso fisso con bagliore neon massimo */
|
|
346
|
-
.is-gybing {
|
|
347
|
-
opacity: 1 !important;
|
|
348
|
-
animation: none !important;
|
|
349
|
-
filter: drop-shadow(0 0 8px #ff0000) !important;
|
|
350
|
-
}
|
|
451
|
+
#trend-dot-cw, #trend-dot-ccw, #trend-gauge-cw, #trend-gauge-ccw { opacity: 0.3; transition: opacity 0.3s ease; }
|
|
452
|
+
.is-trending { opacity: 1 !important; animation: blink-trend 1s infinite !important; }
|
|
453
|
+
.is-gybing { opacity: 1 !important; animation: none !important; filter: drop-shadow(0 0 8px #ff0000) !important; }
|
|
454
|
+
.unstable-data { animation: blink-trend 1.5s infinite ease-in-out; color: #e67e22 !important; }
|