@sailingrotevista/rotevista-dash 2.0.12 → 2.0.13
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 +103 -3
- package/index.html +14 -2
- package/package.json +1 -1
- package/style.css +123 -26
package/app.js
CHANGED
|
@@ -333,7 +333,48 @@ function toggleFocusMode(type, element) {
|
|
|
333
333
|
el.addEventListener('pointerleave', () => clearTimeout(pressTimer));
|
|
334
334
|
});
|
|
335
335
|
|
|
336
|
-
|
|
336
|
+
// ==========================================================================
|
|
337
|
+
// GESTIONE HOTSPOT: Click (Fullscreen) e Long Press (Night Mode)
|
|
338
|
+
// ==========================================================================
|
|
339
|
+
if (ui.hotspot) {
|
|
340
|
+
let pressTimer;
|
|
341
|
+
const HOLD_DURATION = 1000; // 1 secondo di pressione per attivare Night Mode
|
|
342
|
+
|
|
343
|
+
ui.hotspot.addEventListener('pointerdown', (e) => {
|
|
344
|
+
// Avvia il timer al tocco
|
|
345
|
+
pressTimer = setTimeout(() => {
|
|
346
|
+
document.body.classList.toggle('night-mode');
|
|
347
|
+
// Feedback visivo immediato al cambio modalità
|
|
348
|
+
ui.hotspot.style.opacity = "0.5";
|
|
349
|
+
setTimeout(() => ui.hotspot.style.opacity = "1", 200);
|
|
350
|
+
pressTimer = null; // Reset per evitare che il click scatti dopo
|
|
351
|
+
}, HOLD_DURATION);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
ui.hotspot.addEventListener('pointerup', (e) => {
|
|
355
|
+
if (pressTimer) {
|
|
356
|
+
clearTimeout(pressTimer);
|
|
357
|
+
pressTimer = null;
|
|
358
|
+
// Se arriviamo qui, è stato un click rapido -> Fullscreen
|
|
359
|
+
const doc = document.documentElement;
|
|
360
|
+
const isF = document.fullscreenElement || document.webkitFullscreenElement;
|
|
361
|
+
if (!isF) {
|
|
362
|
+
if (doc.requestFullscreen) doc.requestFullscreen();
|
|
363
|
+
else if (doc.webkitRequestFullscreen) doc.webkitRequestFullscreen();
|
|
364
|
+
} else {
|
|
365
|
+
if (document.exitFullscreen) document.exitFullscreen();
|
|
366
|
+
else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
ui.hotspot.addEventListener('pointerleave', () => {
|
|
372
|
+
if (pressTimer) {
|
|
373
|
+
clearTimeout(pressTimer);
|
|
374
|
+
pressTimer = null;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
337
378
|
(function genTicks() { const c = document.getElementById('ticks'); if (c) { for (let i = 0; i < 360; i += 10) { const l = document.createElementNS("http://www.w3.org/2000/svg", "line"); const m = i % 30 === 0; l.setAttribute("x1", "200"); l.setAttribute("y1", "40"); l.setAttribute("x2", "200"); l.setAttribute("y2", (m ? 60 : 50)); l.setAttribute("stroke", m ? "#fff" : "#666"); l.setAttribute("stroke-width", m ? "2" : "1"); l.setAttribute("transform", `rotate(${i}, 200, 200)`); c.appendChild(l); } } })();
|
|
338
379
|
|
|
339
380
|
async function init() { await fetchServerConfig(); startDisplayLoop(); connect(); }
|
|
@@ -341,7 +382,66 @@ window.addEventListener('load', init);
|
|
|
341
382
|
function checkDepthAlarm(m) { ui.depth.classList.remove('alarm-warning', 'alarm-danger'); if (m < CONFIG.alarms.depthDanger) { ui.depth.classList.add('alarm-danger'); playBingBing(); } else if (m < CONFIG.alarms.depthWarning) ui.depth.classList.add('alarm-warning'); }
|
|
342
383
|
function playBingBing() { if (!audioCtx) return; const n = Date.now(); if (n - lastAlarmTime < 3000) return; lastAlarmTime = n; function b(f, s) { const o = audioCtx.createOscillator(); const g = audioCtx.createGain(); o.connect(g); g.connect(audioCtx.destination); o.frequency.value = f; g.gain.setValueAtTime(0.1, s); g.gain.exponentialRampToValueAtTime(0.01, s + 0.4); o.start(s); o.stop(s + 0.5); } b(880, audioCtx.currentTime); b(880, audioCtx.currentTime + 0.6); }
|
|
343
384
|
|
|
344
|
-
// Simulatore
|
|
385
|
+
// Simulatore su Depth (3 click rapidi)
|
|
345
386
|
ui.depth.closest('.data-box').addEventListener('click', (function() {
|
|
346
|
-
let dC = 0, lC = 0;
|
|
387
|
+
let dC = 0, lC = 0;
|
|
388
|
+
return function() {
|
|
389
|
+
const n = Date.now();
|
|
390
|
+
if (n - lC < 500) dC++; else dC = 1;
|
|
391
|
+
lC = n;
|
|
392
|
+
if (dC === 3) {
|
|
393
|
+
simulationMode = !simulationMode;
|
|
394
|
+
if (simulationMode) {
|
|
395
|
+
if (socket) socket.close();
|
|
396
|
+
startDynamicSimulation(); // Chiama la nuova funzione
|
|
397
|
+
} else {
|
|
398
|
+
location.reload();
|
|
399
|
+
}
|
|
400
|
+
dC = 0;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
347
403
|
})());
|
|
404
|
+
|
|
405
|
+
// ==========================================================================
|
|
406
|
+
// 9. MOTORE SIMULAZIONE DINAMICA
|
|
407
|
+
// ==========================================================================
|
|
408
|
+
function startDynamicSimulation() {
|
|
409
|
+
ui.status.innerText = "SIM ATTIVO";
|
|
410
|
+
|
|
411
|
+
// Parametri base iniziali
|
|
412
|
+
let baseTws = 60, baseDepth = 12, baseHdg = 45;
|
|
413
|
+
|
|
414
|
+
simInterval = setInterval(() => {
|
|
415
|
+
// T rappresenta il progresso nel ciclo di 10 minuti (da 0 a 1)
|
|
416
|
+
const t = (Date.now() % 600000) / 600000;
|
|
417
|
+
const radT = t * 2 * Math.PI;
|
|
418
|
+
|
|
419
|
+
// Oscillazioni fluide (Sinusoidali)
|
|
420
|
+
const tws = baseTws + Math.sin(radT) * 5; // Oscilla +- 5 kts
|
|
421
|
+
const depth = baseDepth + Math.sin(radT) * 3; // Oscilla +- 3 m
|
|
422
|
+
const twa = 40 + Math.sin(radT * 2) * 10; // Oscilla angolo +- 10°
|
|
423
|
+
|
|
424
|
+
// Calcoli Vettoriali (Nautica)
|
|
425
|
+
const stw = Math.min(tws * 0.7, 8); // Velocità barca legata al vento
|
|
426
|
+
const twaRad = degToRad(twa);
|
|
427
|
+
|
|
428
|
+
// AWS = radq(stw² + tws² + 2*stw*tws*cos(twa))
|
|
429
|
+
const aws = Math.sqrt(Math.pow(stw, 2) + Math.pow(tws, 2) + 2 * stw * tws * Math.cos(twaRad));
|
|
430
|
+
// AWA = atan2(tws*sin(twa), stw + tws*cos(twa))
|
|
431
|
+
const awa = radToDeg(Math.atan2(tws * Math.sin(twaRad), stw + tws * Math.cos(twaRad)));
|
|
432
|
+
|
|
433
|
+
// Calcolo Leeway (Scarroccio): più forte il vento, più scarroccia
|
|
434
|
+
const leeway = (tws > 5) ? Math.sin(twaRad) * (tws * 0.2) : 0;
|
|
435
|
+
|
|
436
|
+
// Invio dati al sistema
|
|
437
|
+
processIncomingData("environment.wind.speedTrue", ktsToMs(tws));
|
|
438
|
+
processIncomingData("environment.wind.angleTrueWater", degToRad(twa));
|
|
439
|
+
processIncomingData("environment.wind.speedApparent", ktsToMs(aws));
|
|
440
|
+
processIncomingData("environment.wind.angleApparent", degToRad(awa));
|
|
441
|
+
processIncomingData("environment.depth.belowTransducer", depth);
|
|
442
|
+
processIncomingData("navigation.headingTrue", degToRad(baseHdg));
|
|
443
|
+
processIncomingData("navigation.speedThroughWater", ktsToMs(stw));
|
|
444
|
+
processIncomingData("navigation.courseOverGroundTrue", degToRad(baseHdg + leeway));
|
|
445
|
+
}, 1000);
|
|
446
|
+
}
|
|
447
|
+
|
package/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<title>Sailing Dashboard Pro</title>
|
|
10
10
|
<link rel="stylesheet" href="style.css">
|
|
11
11
|
</head>
|
|
12
|
-
<body
|
|
12
|
+
<body>
|
|
13
13
|
|
|
14
14
|
<!-- Etichetta stato connessione SignalK -->
|
|
15
15
|
<div id="status" class="offline">OFFLINE</div>
|
|
@@ -89,6 +89,8 @@
|
|
|
89
89
|
<!-- ViewBox ottimizzato per ingrandire il diametro (Zoom in) -->
|
|
90
90
|
<svg id="wind-gauge" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet">
|
|
91
91
|
<defs>
|
|
92
|
+
<!-- Maschera per tagliare la barca esattamente sul bordo del cerchio r=50 -->
|
|
93
|
+
<clipPath id="boat-clip"><circle cx="200" cy="200" r="50" /></clipPath>
|
|
92
94
|
<!-- Gradienti e Maschere per i settori del vento -->
|
|
93
95
|
<linearGradient id="axiom-grad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
94
96
|
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
|
|
@@ -101,6 +103,12 @@
|
|
|
101
103
|
<stop offset="75%" style="stop-color:#ff8800;stop-opacity:1" />
|
|
102
104
|
<stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" />
|
|
103
105
|
</linearGradient>
|
|
106
|
+
<!-- Gradiente Leeway per la Night Mode (Rosso cupo al centro, Rosso vivo ai lati) -->
|
|
107
|
+
<linearGradient id="leeway-night-grad" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
108
|
+
<stop offset="0%" style="stop-color:#ff0000;stop-opacity:1" /> <!-- Estremo SX: Rosso vivo -->
|
|
109
|
+
<stop offset="50%" style="stop-color:#330000;stop-opacity:1" /> <!-- Centro: Rosso cupo -->
|
|
110
|
+
<stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" /> <!-- Estremo DX: Rosso vivo -->
|
|
111
|
+
</linearGradient>
|
|
104
112
|
<clipPath id="leeway-clip">
|
|
105
113
|
<rect id="leeway-mask-rect" x="125" y="0" width="0" height="12" rx="2" />
|
|
106
114
|
</clipPath>
|
|
@@ -150,7 +158,11 @@
|
|
|
150
158
|
<circle id="fullscreen-hotspot" cx="200" cy="200" r="55" fill="#181818" stroke="#333" stroke-width="1" filter="url(#center-glow)" cursor="pointer" />
|
|
151
159
|
|
|
152
160
|
<!-- Icona Barca Centrale (Spinta Y+5 per centratura visiva perfetta) -->
|
|
153
|
-
<path id="boat-icon" d="M200,150 Q165,185 170,250 Q165,190 200,173 Q235,190 230,250 Q235,185 200,150 Z"
|
|
161
|
+
<path id="boat-icon" d="M200,150 Q165,185 170,250 Q165,190 200,173 Q235,190 230,250 Q235,185 200,150 Z"
|
|
162
|
+
fill="url(#axiom-grad)"
|
|
163
|
+
transform="translate(0, 5)"
|
|
164
|
+
clip-path="url(#boat-clip)"
|
|
165
|
+
style="pointer-events: none;" />
|
|
154
166
|
|
|
155
167
|
<!-- Display Centrale Numerico: Vento Apparente -->
|
|
156
168
|
<g id="aws-display-group" transform="translate(200, 265)">
|
package/package.json
CHANGED
package/style.css
CHANGED
|
@@ -309,49 +309,146 @@ body {
|
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
/* ==========================================================================
|
|
312
|
-
10. NIGHT MODE (RED ON BLACK)
|
|
312
|
+
10. NIGHT MODE (RED ON BLACK - TACTICAL)
|
|
313
313
|
========================================================================== */
|
|
314
314
|
body.night-mode {
|
|
315
315
|
background-color: #000 !important;
|
|
316
|
-
color: #ff0000 !important;
|
|
316
|
+
color: #ff0000 !important;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
/* Pannelli e Box */
|
|
320
|
-
.night-mode .side-panel {
|
|
321
|
-
|
|
319
|
+
/* --- Pannelli e Box --- */
|
|
320
|
+
.night-mode .side-panel {
|
|
321
|
+
background: rgba(20, 0, 0, 0.4);
|
|
322
|
+
border: 1px solid #330000;
|
|
323
|
+
}
|
|
324
|
+
.night-mode .data-box {
|
|
325
|
+
border-bottom-color: #260000;
|
|
326
|
+
}
|
|
322
327
|
|
|
323
|
-
/*
|
|
324
|
-
.night-mode .label,
|
|
325
|
-
|
|
328
|
+
/* --- Tipografia Secondaria (Titoli, Unità, TACK Labels) --- */
|
|
329
|
+
.night-mode .label,
|
|
330
|
+
.night-mode .unit,
|
|
331
|
+
.night-mode .dual-label {
|
|
332
|
+
color: #800000 !important; /* Rosso cupo per non affaticare la vista */
|
|
326
333
|
}
|
|
327
334
|
|
|
328
|
-
/* Valori Numerici */
|
|
329
|
-
.night-mode .value,
|
|
335
|
+
/* --- Valori Numerici --- */
|
|
336
|
+
.night-mode .value,
|
|
337
|
+
.night-mode .value-large {
|
|
330
338
|
color: #ff3333 !important;
|
|
331
|
-
text-shadow: 0 0
|
|
339
|
+
text-shadow: 0 0 8px rgba(255, 0, 0, 0.4); /* Bagliore per profondità */
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* --- Grafici Sparkline (Solo Linea, No Riempimento) --- */
|
|
343
|
+
.night-mode .graph-wrapper {
|
|
344
|
+
background: rgba(30, 0, 0, 0.3) !important;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/* Nasconde l'area di riempimento sotto la linea */
|
|
348
|
+
.night-mode .sparkline path:first-of-type {
|
|
349
|
+
display: none !important;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* Rende la linea del tracciato molto più visibile */
|
|
353
|
+
.night-mode .sparkline path {
|
|
354
|
+
fill: none !important;
|
|
355
|
+
stroke: #ff3333 !important;
|
|
356
|
+
stroke-width: 1.8px !important;
|
|
357
|
+
opacity: 1 !important;
|
|
358
|
+
filter: drop-shadow(0 0 2px rgba(255, 0, 0, 0.4));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* Griglie interne (Orizzontali e Verticali) uniformi */
|
|
362
|
+
.night-mode .sparkline line {
|
|
363
|
+
stroke: #4d0000 !important;
|
|
364
|
+
stroke-width: 0.7px !important;
|
|
365
|
+
opacity: 1 !important;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Forza i segmenti colorati del TWS alla stessa luminosità della linea */
|
|
369
|
+
.night-mode #tws-graph line:not([stroke*="rgba"]) {
|
|
370
|
+
stroke: #ff3333 !important;
|
|
371
|
+
stroke-width: 1.8px !important;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* Numeri delle scale a lato dei grafici */
|
|
375
|
+
.night-mode .scale-labels {
|
|
376
|
+
color: #660000 !important;
|
|
332
377
|
}
|
|
333
378
|
|
|
334
|
-
/*
|
|
335
|
-
.night-mode .
|
|
336
|
-
|
|
337
|
-
|
|
379
|
+
/* --- Hercules Mode in Night Mode --- */
|
|
380
|
+
.night-mode .box-hercules {
|
|
381
|
+
background: rgba(60, 0, 0, 0.2) !important;
|
|
382
|
+
}
|
|
383
|
+
.night-mode .line-hercules {
|
|
384
|
+
filter: drop-shadow(0 0 6px #ff0000) !important;
|
|
385
|
+
}
|
|
338
386
|
|
|
339
|
-
/*
|
|
340
|
-
.night-mode
|
|
387
|
+
/* Scritta Hercules in alto (Colore personalizzato #f60000) */
|
|
388
|
+
.night-mode .box-hercules .unit::before,
|
|
389
|
+
.night-mode .box-hercules .unit::after,
|
|
390
|
+
.night-mode .box-hercules .label::before,
|
|
391
|
+
.night-mode .box-hercules .label::after {
|
|
392
|
+
color: #f60000 !important;
|
|
393
|
+
font-weight: 700;
|
|
394
|
+
opacity: 0.9;
|
|
395
|
+
letter-spacing: 1px;
|
|
396
|
+
}
|
|
341
397
|
|
|
342
|
-
/* Strumento Centrale (
|
|
398
|
+
/* --- Strumento Centrale (Wind Gauge) --- */
|
|
343
399
|
.night-mode #wind-gauge circle { stroke: #330000; }
|
|
344
|
-
.night-mode #ticks line { stroke: #
|
|
345
|
-
.night-mode #tick-labels { fill: #
|
|
346
|
-
.night-mode #boat-icon { fill: #
|
|
400
|
+
.night-mode #ticks line { stroke: #4d0000 !important; }
|
|
401
|
+
.night-mode #tick-labels { fill: #800000 !important; }
|
|
402
|
+
.night-mode #boat-icon { fill: #330000 !important; opacity: 0.6; }
|
|
347
403
|
.night-mode #aws-val-svg { fill: #ff3333 !important; }
|
|
348
404
|
|
|
349
|
-
/*
|
|
405
|
+
/* Settori Vento (Distinguibili per stile, non per colore) */
|
|
406
|
+
.night-mode #wind-gauge path[stroke="#ff0000"] { stroke: #660000 !important; opacity: 0.8; } /* Sx Solid */
|
|
407
|
+
.night-mode #wind-gauge path[stroke="#00ff00"] {
|
|
408
|
+
stroke: #660000 !important;
|
|
409
|
+
stroke-dasharray: 4, 3; /* Dx Dashed */
|
|
410
|
+
opacity: 0.8;
|
|
411
|
+
}
|
|
412
|
+
.night-mode #wind-gauge path[stroke="#ff8800"] { stroke: #330000 !important; stroke-width: 8; } /* Poppa Dark */
|
|
413
|
+
|
|
414
|
+
/* Lancette Wind Gauge */
|
|
350
415
|
.night-mode #awa-pointer path { fill: #ff0000; stroke: #000; }
|
|
351
|
-
.night-mode #twa-pointer path { fill: #
|
|
416
|
+
.night-mode #twa-pointer path { fill: #800000; stroke: #000; }
|
|
352
417
|
.night-mode #track-pointer path { fill: #ff0000; stroke: #fff; stroke-width: 0.5; }
|
|
353
418
|
|
|
354
|
-
/*
|
|
355
|
-
.night-mode
|
|
356
|
-
.night-mode
|
|
419
|
+
/* --- Blocco Leeway (Scarroccio) --- */
|
|
420
|
+
.night-mode rect[fill="url(#leeway-grad)"] { fill: url(#leeway-night-grad) !important; }
|
|
421
|
+
.night-mode #leeway-val { fill: #ff3333 !important; }
|
|
422
|
+
.night-mode g[stroke="#555"] line { stroke: #4d0000 !important; }
|
|
423
|
+
.night-mode g[fill="#555"] text { fill: #660000 !important; }
|
|
424
|
+
.night-mode rect[fill="#222"] { fill: #0a0000 !important; stroke: #200000; }
|
|
425
|
+
|
|
426
|
+
/* --- Bussola TWD --- */
|
|
427
|
+
.night-mode .mini-compass { border-color: #330000; background: #000; }
|
|
428
|
+
.night-mode .mini-compass text { fill: #800000 !important; }
|
|
357
429
|
.night-mode #twd-arrow path { fill: #ff0000 !important; stroke: #000 !important; }
|
|
430
|
+
.night-mode #twd-boat-wrap path { fill: #ff0000 !important; opacity: 0.15; }
|
|
431
|
+
|
|
432
|
+
.night-mode #center-glow feDropShadow {
|
|
433
|
+
flood-color: #ff0000 !important;
|
|
434
|
+
flood-opacity: 0.6 !important;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.night-mode #aws-display-group text {
|
|
438
|
+
fill: #ff3333 !important;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* --- Modifica: Miglioramento visibilità TWD in Night Mode --- */
|
|
442
|
+
.night-mode #twd-arrow #twd-wind-chevron {
|
|
443
|
+
stroke: #ff3333 !important; /* Rosso più brillante */
|
|
444
|
+
stroke-width: 3px !important; /* Più spesso */
|
|
445
|
+
opacity: 1 !important; /* Piena opacità */
|
|
446
|
+
filter: drop-shadow(0 0 4px #ff0000); /* Effetto neon per staccarsi dallo sfondo */
|
|
447
|
+
transform-origin: center; /* Forza il centro corretto */
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/* Assicuriamoci che anche la punta della barca sia visibile */
|
|
451
|
+
.night-mode #twd-boat-wrap path {
|
|
452
|
+
fill: #ff3333 !important;
|
|
453
|
+
opacity: 0.4 !important;
|
|
454
|
+
}
|