@sailingrotevista/rotevista-dash 2.0.22 → 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 +65 -11
- package/index.html +90 -160
- package/package.json +1 -1
- package/style.css +347 -222
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,22 +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
|
-
|
|
447
|
+
|
|
448
|
+
el.addEventListener('pointerdown', (e) => {
|
|
449
|
+
isLongPressActive = false;
|
|
450
|
+
pressTimer = setTimeout(() => {
|
|
451
|
+
if (!isFocusActive) {
|
|
452
|
+
isLongPressActive = true;
|
|
453
|
+
toggleFocusMode(type, el);
|
|
454
|
+
lastTapTime = 0;
|
|
455
|
+
}
|
|
456
|
+
}, 1000);
|
|
457
|
+
});
|
|
458
|
+
|
|
431
459
|
el.addEventListener('pointerup', (e) => {
|
|
432
|
-
clearTimeout(pressTimer);
|
|
460
|
+
clearTimeout(pressTimer);
|
|
461
|
+
if (isLongPressActive) return; // Se era focus, ignora l'up
|
|
462
|
+
|
|
433
463
|
const currentTime = new Date().getTime(), tapDelay = currentTime - lastTapTime;
|
|
434
|
-
|
|
435
|
-
|
|
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
|
+
}
|
|
436
489
|
});
|
|
490
|
+
|
|
437
491
|
el.addEventListener('pointerleave', () => clearTimeout(pressTimer));
|
|
438
492
|
});
|
|
439
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
|
@@ -1,222 +1,352 @@
|
|
|
1
1
|
/* ==========================================================================
|
|
2
|
-
1. BASE E RESET DI SISTEMA
|
|
2
|
+
1. BASE E RESET DI SISTEMA
|
|
3
3
|
========================================================================== */
|
|
4
4
|
body {
|
|
5
5
|
background-color: #fff;
|
|
6
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
|
-
-webkit-touch-callout: none;
|
|
14
|
-
-webkit-user-select: none;
|
|
15
|
-
user-select: none;
|
|
16
|
-
touch-action: none;
|
|
11
|
+
-webkit-touch-callout: none; -webkit-user-select: none; user-select: none; touch-action: none;
|
|
17
12
|
}
|
|
18
13
|
|
|
19
14
|
/* ==========================================================================
|
|
20
|
-
2. LAYOUT PRINCIPALE (
|
|
15
|
+
2. LAYOUT PRINCIPALE (GRID AREAS)
|
|
21
16
|
========================================================================== */
|
|
22
17
|
.main-container {
|
|
23
18
|
display: grid;
|
|
24
|
-
width: 100%;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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;
|
|
31
29
|
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
32
|
-
justify-content: stretch;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.side-panel {
|
|
36
|
-
display: flex;
|
|
37
|
-
flex-direction: column;
|
|
38
|
-
background: rgba(0, 0, 0, 0.03);
|
|
39
|
-
border-radius: 12px;
|
|
40
|
-
height: 100%;
|
|
41
|
-
overflow: hidden;
|
|
42
|
-
gap: 2px;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.left-panel { grid-column: 1; }
|
|
46
|
-
|
|
47
|
-
.center-panel {
|
|
48
|
-
grid-column: 2;
|
|
49
|
-
position: relative;
|
|
50
|
-
display: flex;
|
|
51
|
-
flex-direction: column;
|
|
52
|
-
align-items: center;
|
|
53
|
-
justify-content: center;
|
|
54
|
-
height: 100%;
|
|
55
|
-
overflow: hidden;
|
|
56
30
|
}
|
|
57
31
|
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
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; }
|
|
63
43
|
|
|
64
44
|
/* ==========================================================================
|
|
65
|
-
3. DATA-BOX E
|
|
45
|
+
3. DATA-BOX: STRUTTURA E ALLINEAMENTO (Bordi Schermo & Display Curvi)
|
|
66
46
|
========================================================================== */
|
|
67
47
|
.data-box {
|
|
68
|
-
position: relative;
|
|
69
|
-
|
|
70
|
-
padding:
|
|
71
|
-
display: flex;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
container-type: size;
|
|
76
|
-
flex: 1 1 0px;
|
|
77
|
-
min-height: 0;
|
|
78
|
-
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;
|
|
79
55
|
transition: background-color 0.2s ease;
|
|
56
|
+
/* Forza la centratura verticale del valore per display curvi */
|
|
57
|
+
justify-content: center !important;
|
|
80
58
|
}
|
|
81
59
|
|
|
82
|
-
|
|
83
|
-
.
|
|
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
|
+
}
|
|
84
65
|
|
|
85
|
-
.label-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2px; width: 100%; }
|
|
86
66
|
.label { color: #888; font-size: 0.65rem; font-weight: bold; text-transform: uppercase; }
|
|
87
67
|
.unit { color: #aaa; font-size: 0.6rem; font-weight: bold; }
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
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;
|
|
96
75
|
}
|
|
97
76
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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;
|
|
101
81
|
}
|
|
102
82
|
|
|
103
|
-
|
|
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; }
|
|
104
87
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
width: 100%;
|
|
110
|
-
align-self: stretch;
|
|
111
|
-
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;
|
|
112
92
|
}
|
|
113
93
|
|
|
114
|
-
|
|
115
|
-
.
|
|
116
|
-
.
|
|
117
|
-
.
|
|
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 "; }
|
|
118
110
|
|
|
119
111
|
/* ==========================================================================
|
|
120
|
-
|
|
112
|
+
5. TACTICAL FOCUS MODE
|
|
121
113
|
========================================================================== */
|
|
122
|
-
.focus-active .
|
|
123
|
-
.focus-active.
|
|
124
|
-
|
|
125
|
-
.focus-active.focus-side-left
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
.focus-active
|
|
131
|
-
|
|
114
|
+
.focus-active .data-box:not(.is-focused),
|
|
115
|
+
.focus-active .box-gauge { display: none !important; }
|
|
116
|
+
|
|
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
|
+
}
|
|
127
|
+
|
|
128
|
+
.focus-active .is-focused {
|
|
129
|
+
grid-area: focused !important;
|
|
132
130
|
height: 100vh !important;
|
|
133
|
-
|
|
134
|
-
background: rgba(0, 0, 0, 0.02);
|
|
131
|
+
background: rgba(0, 0, 0, 0.02) !important;
|
|
135
132
|
padding: 2vw 3vw !important;
|
|
136
|
-
|
|
137
|
-
flex-direction: column;
|
|
133
|
+
justify-content: center !important;
|
|
138
134
|
}
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.focus-active .is-focused
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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);
|
|
141
|
+
}
|
|
142
|
+
|
|
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; }
|
|
146
145
|
|
|
147
146
|
/* ==========================================================================
|
|
148
|
-
|
|
149
|
-
|
|
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
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ==========================================================================
|
|
202
|
+
7. GRAFICI, SCALE E TAG HERCULES
|
|
203
|
+
========================================================================== */
|
|
150
204
|
.graph-wrapper {
|
|
151
|
-
position: relative;
|
|
152
|
-
|
|
153
|
-
|
|
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;
|
|
154
215
|
}
|
|
155
216
|
|
|
156
|
-
.
|
|
157
|
-
|
|
217
|
+
.sparkline {
|
|
218
|
+
flex-grow: 1;
|
|
219
|
+
height: 100%;
|
|
220
|
+
width: 100% !important;
|
|
221
|
+
background: transparent !important;
|
|
222
|
+
}
|
|
158
223
|
|
|
159
|
-
|
|
160
|
-
.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
|
+
}
|
|
161
230
|
|
|
162
231
|
.scale-labels {
|
|
163
|
-
display: flex;
|
|
164
|
-
|
|
165
|
-
|
|
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;
|
|
242
|
+
}
|
|
243
|
+
|
|
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;
|
|
166
253
|
}
|
|
167
254
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
.
|
|
171
|
-
|
|
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
|
+
}
|
|
172
265
|
|
|
173
|
-
|
|
266
|
+
/* --- REGOLE HERCULES (Zoom) --- */
|
|
174
267
|
.box-hercules { background: rgba(255, 0, 0, 0.05) !important; }
|
|
175
268
|
.box-hercules .scale-labels { color: #ff5555; }
|
|
176
|
-
.box-hercules .unit::before
|
|
177
|
-
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 ";
|
|
178
272
|
}
|
|
179
|
-
.left-panel .box-hercules .unit::before { content: "HERCULES "; }
|
|
180
|
-
.right-panel .box-hercules .unit::after { content: " HERCULES"; }
|
|
181
|
-
.right-panel .box-hercules .label:only-child::after { content: " HERCULES"; }
|
|
182
273
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
+
}
|
|
187
279
|
|
|
188
280
|
/* ==========================================================================
|
|
189
|
-
|
|
281
|
+
8. RESPONSIVE (PORTRAIT MODE)
|
|
190
282
|
========================================================================== */
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
+
}
|
|
197
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; }
|
|
198
342
|
.online { color: #27ae60; opacity: 0.8; }
|
|
199
343
|
.offline { color: #c0392b; font-weight: bold; }
|
|
200
344
|
|
|
201
|
-
.mini-compass {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
box-shadow: inset 0 0 10px rgba(0,0,0,0.05); transition: all 0.4s ease;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* Inversione elementi Mini Bussola TWD - Giorno */
|
|
209
|
-
.mini-compass text:last-of-type { fill: #000 !important; opacity: 0.4; } /* La "S" nera */
|
|
210
|
-
#twd-boat-wrap path { fill: #000 !important; opacity: 0.3; } /* Barca interna nera */
|
|
211
|
-
#twd-wind-chevron { stroke: #000 !important; } /* Forza il triangolino vento a nero in giorno */
|
|
212
|
-
|
|
213
|
-
#awa-pointer, #twa-pointer, #track-pointer, #twd-arrow, #twd-boat-wrap {
|
|
214
|
-
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
|
215
|
-
}
|
|
345
|
+
.mini-compass { background: #f0f0f0; border-radius: 50%; border: 1.5px solid #ddd; }
|
|
346
|
+
.mini-compass text:last-of-type { fill: #000 !important; opacity: 0.4; }
|
|
347
|
+
#twd-boat-wrap path { fill: #000 !important; opacity: 0.3; }
|
|
348
|
+
#twd-wind-chevron { stroke: #000 !important; }
|
|
216
349
|
|
|
217
|
-
#wind-gauge { width: 100%; height: 100%; max-height: 100%; object-fit: contain; }
|
|
218
|
-
|
|
219
|
-
/* Quadrante Vento Centrale - Giorno */
|
|
220
350
|
#wind-gauge circle[fill="#050505"] { fill: #fcfcfc; }
|
|
221
351
|
#wind-gauge circle[fill="#121212"] { fill: #f0f0f0; }
|
|
222
352
|
#boat-icon { fill: #000 !important; opacity: 1; }
|
|
@@ -226,104 +356,99 @@ body {
|
|
|
226
356
|
#fullscreen-hotspot { fill: #eee !important; stroke: #ccc !important; }
|
|
227
357
|
#ticks line[stroke="#fff"] { stroke: #000 !important; }
|
|
228
358
|
#ticks line[stroke="#666"] { stroke: #bbb !important; }
|
|
229
|
-
|
|
230
|
-
/* Leeway Container - Giorno */
|
|
231
359
|
rect[fill="#222"] { fill: #eee !important; }
|
|
232
360
|
#leeway-val { color: #000 !important; }
|
|
233
361
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
========================================================================== */
|
|
237
|
-
.unstable-data { animation: blink-unstable 1.5s infinite ease-in-out; color: #e67e22 !important; }
|
|
238
|
-
.alarm-warning { color: #f39c12 !important; }
|
|
239
|
-
.alarm-danger { color: #e74c3c !important; font-weight: 900; animation: blink-unstable 1s infinite; }
|
|
240
|
-
@keyframes blink-unstable { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
|
|
241
|
-
|
|
242
|
-
/* ==========================================================================
|
|
243
|
-
8. RESPONSIVE
|
|
244
|
-
========================================================================== */
|
|
245
|
-
@media (max-aspect-ratio: 0.9 / 1) {
|
|
246
|
-
.main-container { grid-template-columns: 1fr 1fr !important; grid-template-rows: 45vh calc(55vh - 8px) !important; }
|
|
247
|
-
.center-panel { grid-row: 1 !important; grid-column: 1 / span 2 !important; }
|
|
248
|
-
.left-panel { grid-row: 2 !important; grid-column: 1 !important; }
|
|
249
|
-
.right-panel { grid-row: 2 !important; grid-column: 2 !important; }
|
|
250
|
-
.main-container.focus-active { display: flex !important; flex-direction: column !important; }
|
|
251
|
-
.focus-active .center-panel { flex: 0 0 45vh !important; }
|
|
252
|
-
.focus-active .side-panel.has-focus { flex: 0 0 calc(55vh - 8px) !important; display: flex !important; }
|
|
253
|
-
.data-box { height: auto !important; flex: 1 !important; }
|
|
254
|
-
}
|
|
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; }
|
|
255
364
|
|
|
256
365
|
/* ==========================================================================
|
|
257
|
-
|
|
366
|
+
10. NIGHT MODE (TACTICAL RED - INTEGRALE E RIFINITO)
|
|
258
367
|
========================================================================== */
|
|
259
368
|
body.night-mode { background-color: #000 !important; color: #ff0000 !important; }
|
|
260
|
-
.night-mode .side-panel { background: rgba(20, 0, 0, 0.4) !important; border: 1px solid #330000; }
|
|
261
|
-
.night-mode .data-box { border-bottom-color: #260000; }
|
|
262
|
-
.night-mode .label, .night-mode .unit, .night-mode .dual-label { color: #800000 !important; }
|
|
263
|
-
.night-mode .value, .night-mode .value-large { color: #ff3333 !important; text-shadow: 0 0 8px rgba(255, 0, 0, 0.4); }
|
|
264
369
|
|
|
265
|
-
|
|
266
|
-
.night-mode .
|
|
267
|
-
.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; }
|
|
375
|
+
|
|
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
|
+
}
|
|
268
381
|
|
|
269
|
-
|
|
270
|
-
.night-mode
|
|
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
|
+
}
|
|
271
396
|
.night-mode .scale-labels { color: #660000 !important; }
|
|
272
397
|
|
|
398
|
+
/* Hercules in Night Mode */
|
|
273
399
|
.night-mode .box-hercules { background: rgba(60, 0, 0, 0.2) !important; }
|
|
274
400
|
.night-mode .line-hercules { filter: drop-shadow(0 0 6px #ff0000) !important; }
|
|
275
401
|
|
|
276
|
-
/*
|
|
277
|
-
.night-mode #wind-gauge circle
|
|
278
|
-
.night-mode #wind-gauge circle[fill="#
|
|
279
|
-
|
|
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 */
|
|
280
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; }
|
|
281
412
|
|
|
282
|
-
.night-mode #ticks line { stroke: #4d0000 !important; }
|
|
283
|
-
.night-mode #tick-labels { fill: #800000 !important; }
|
|
284
413
|
.night-mode #boat-icon { fill: #330000 !important; opacity: 0.6 !important; }
|
|
285
414
|
.night-mode #aws-val-svg { fill: #ff3333 !important; }
|
|
286
|
-
.night-mode #aws-display-group text { fill: #
|
|
287
|
-
.night-mode #center-glow feDropShadow { flood-color: #ff0000 !important; flood-opacity: 0.6 !important; }
|
|
415
|
+
.night-mode #aws-display-group text { fill: #660000 !important; }
|
|
288
416
|
|
|
289
|
-
/*
|
|
290
|
-
.night-mode
|
|
291
|
-
.night-mode
|
|
292
|
-
.night-mode .mini-compass text:last-of-type { fill: #800000 !important; opacity: 1; } /* La "S" torna rossa */
|
|
293
|
-
.night-mode #twd-boat-wrap path { fill: #ff3333 !important; opacity: 0.4 !important; } /* Barca torna rossa */
|
|
294
|
-
.night-mode #twd-arrow #twd-wind-chevron { stroke: #ff3333 !important; stroke-width: 3px !important; opacity: 1 !important; filter: drop-shadow(0 0 4px #ff0000); transform-origin: center; }
|
|
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; }
|
|
295
420
|
|
|
296
|
-
/*
|
|
421
|
+
/* SETTORI VENTO: Il verde diventa un rosso scuro trattteggiato */
|
|
297
422
|
.night-mode #wind-gauge path[stroke="#ff0000"] { stroke: #660000 !important; opacity: 0.8; }
|
|
298
|
-
.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; }
|
|
299
424
|
.night-mode #wind-gauge path[stroke="#ff8800"] { stroke: #330000 !important; stroke-width: 8; }
|
|
425
|
+
|
|
426
|
+
/* --- LEEWAY & POINTERS NIGHT --- */
|
|
300
427
|
.night-mode rect[fill="url(#leeway-grad)"] { fill: url(#leeway-night-grad) !important; }
|
|
301
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 */
|
|
302
432
|
.night-mode g[stroke="#555"] line { stroke: #4d0000 !important; }
|
|
303
433
|
.night-mode g[fill="#555"] text { fill: #660000 !important; }
|
|
304
|
-
.night-mode rect[fill="#222"] { fill: #0a0000 !important; stroke: #200000; }
|
|
305
434
|
|
|
435
|
+
/* Lancette */
|
|
306
436
|
.night-mode #awa-pointer path { fill: #ff0000; stroke: #000; }
|
|
307
437
|
.night-mode #twa-pointer path { fill: #800000; stroke: #000; }
|
|
308
438
|
.night-mode #track-pointer path { fill: #ff0000; stroke: #fff; stroke-width: 0.5; }
|
|
309
439
|
|
|
440
|
+
/* --- MINI BUSSOLA TWD NIGHT --- */
|
|
441
|
+
.night-mode .mini-compass { border-color: #330000; background: #000; }
|
|
442
|
+
.night-mode .mini-compass text { fill: #800000 !important; }
|
|
443
|
+
.night-mode .mini-compass text:last-of-type { fill: #800000 !important; opacity: 1; }
|
|
444
|
+
.night-mode #twd-boat-wrap path { fill: #ff3333 !important; opacity: 0.4 !important; }
|
|
445
|
+
.night-mode #twd-arrow #twd-wind-chevron { stroke: #ff3333 !important; filter: drop-shadow(0 0 4px #ff0000); }
|
|
446
|
+
|
|
310
447
|
/* ==========================================================================
|
|
311
|
-
|
|
448
|
+
11. TREND E ANIMAZIONI
|
|
312
449
|
========================================================================== */
|
|
313
450
|
@keyframes blink-trend { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
.is-trending {
|
|
321
|
-
opacity: 1 !important;
|
|
322
|
-
animation: blink-trend 1s infinite !important;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
.is-gybing {
|
|
326
|
-
opacity: 1 !important;
|
|
327
|
-
animation: none !important;
|
|
328
|
-
filter: drop-shadow(0 0 8px #ff0000) !important;
|
|
329
|
-
}
|
|
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; }
|