@sailingrotevista/rotevista-dash 7.0.17 → 7.0.19

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.
Files changed (4) hide show
  1. package/app.js +26 -12
  2. package/index.html +97 -90
  3. package/package.json +1 -1
  4. package/style.css +41 -0
package/app.js CHANGED
@@ -744,11 +744,20 @@ function startDisplayLoop() {
744
744
  }
745
745
 
746
746
  if (lastAvgUIUpdate % 3 === 0) {
747
- let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false);
748
- let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false);
749
- let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true);
750
- let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true);
751
- let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false);
747
+ const baseThreshold = CONFIG.averaging.stabilityThreshold || 0.95;
748
+ const breakout = CONFIG.averaging.stabilityBreakout || 15;
749
+
750
+ // CALCOLO DIFFERENZIALE: Tolleranza del vento proporzionale alla sensibilità di base.
751
+ // Rilassiamo la soglia del vento di 0.13 rispetto alla prua (es. se la prua richiede 0.95, il vento richiede 0.82)
752
+ const windThreshold = Math.max(0.60, baseThreshold - 0.13);
753
+
754
+ let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false, now, baseThreshold, breakout);
755
+ let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false, now, baseThreshold, breakout);
756
+
757
+ // Applichiamo la soglia differenziale ottimizzata per i tre dati legati al vento
758
+ let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
759
+ let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
760
+ let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false, now, windThreshold, breakout);
752
761
 
753
762
  // --- GESTIONE DINAMICA ETICHETTA TACK/GYBE CON ISTERESI DI 10 GRADI ---
754
763
  if (ui.tackLabel) {
@@ -1255,11 +1264,14 @@ async function init() {
1255
1264
  if (activeInstrument === 'gauge') {
1256
1265
  twdPressTimer = setTimeout(() => {
1257
1266
  activeInstrument = 'radar';
1258
- document.getElementById('wind-gauge').style.display = 'none';
1267
+
1268
+ // Spegne l'INTERO contenitore multilivello della bussola analogica
1269
+ document.querySelector('.wind-gauge-container').style.display = 'none';
1259
1270
  document.getElementById('wind-radar').style.display = 'block';
1271
+
1260
1272
  renderRadar(); // Disegna immediatamente il radar all'attivazione
1261
1273
  twdPressTimer = null;
1262
- longPressTriggered = true; // Segnala che la transizione al radar è avvenuta con successo
1274
+ longPressTriggered = true;
1263
1275
  }, 1000);
1264
1276
  }
1265
1277
  });
@@ -1271,13 +1283,13 @@ async function init() {
1271
1283
  }
1272
1284
  } else if (activeInstrument === 'radar') {
1273
1285
  if (longPressTriggered) {
1274
- // Se l'evento di rilascio appartiene al tocco prolungato che ha appena attivato il radar, lo ignoriamo
1275
1286
  longPressTriggered = false;
1276
1287
  } else {
1277
- // Altrimenti è un tocco rapido indipendente: torna alla bussola analogica
1278
1288
  activeInstrument = 'gauge';
1279
1289
  document.getElementById('wind-radar').style.display = 'none';
1280
- document.getElementById('wind-gauge').style.display = 'block';
1290
+
1291
+ // Riaccende l'intero contenitore multilivello della bussola analogica
1292
+ document.querySelector('.wind-gauge-container').style.display = 'flex';
1281
1293
  }
1282
1294
  }
1283
1295
  });
@@ -1289,7 +1301,7 @@ async function init() {
1289
1301
  longPressTriggered = false;
1290
1302
  });
1291
1303
  }
1292
-
1304
+
1293
1305
  // 2. COMANDO TATTICO: Click in qualsiasi punto del radar per tornare all'analogico
1294
1306
  const windRadarSvg = document.getElementById('wind-radar');
1295
1307
  if (windRadarSvg) {
@@ -1297,7 +1309,9 @@ async function init() {
1297
1309
  if (activeInstrument === 'radar') {
1298
1310
  activeInstrument = 'gauge';
1299
1311
  windRadarSvg.style.display = 'none';
1300
- document.getElementById('wind-gauge').style.display = 'block';
1312
+
1313
+ // Riaccende l'intero contenitore multilivello della bussola analogica
1314
+ document.querySelector('.wind-gauge-container').style.display = 'flex';
1301
1315
  }
1302
1316
  });
1303
1317
  }
package/index.html CHANGED
@@ -67,101 +67,108 @@
67
67
  <!-- STATO CONNESSIONE -->
68
68
  <div id="status" class="offline">OFFLINE</div>
69
69
 
70
- <!-- BUSSOLA 1: ANALOGICA STANDARD (Visibile all'avvio) -->
71
- <svg id="wind-gauge" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet">
72
- <defs>
73
- <clipPath id="boat-clip"><circle cx="200" cy="200" r="50" /></clipPath>
74
- <linearGradient id="axiom-grad" x1="0%" y1="0%" x2="0%" y2="100%">
75
- <stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
76
- <stop offset="100%" style="stop-color:#888888;stop-opacity:1" />
77
- </linearGradient>
78
- <linearGradient id="leeway-grad" x1="0%" y1="0%" x2="100%" y2="0%">
79
- <stop offset="0%" style="stop-color:#ff0000;stop-opacity:1" />
80
- <stop offset="25%" style="stop-color:#ff8800;stop-opacity:1" />
81
- <stop offset="50%" style="stop-color:#00ff00;stop-opacity:1" />
82
- <stop offset="75%" style="stop-color:#ff8800;stop-opacity:1" />
83
- <stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" />
84
- </linearGradient>
85
- <linearGradient id="leeway-night-grad" x1="0%" y1="0%" x2="100%" y2="0%">
86
- <stop offset="0%" style="stop-color:#ff0000;stop-opacity:1" />
87
- <stop offset="50%" style="stop-color:#330000;stop-opacity:1" />
88
- <stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" />
89
- </linearGradient>
90
- <clipPath id="leeway-clip">
91
- <rect id="leeway-mask-rect" x="125" y="0" width="0" height="12" rx="2" />
92
- </clipPath>
93
- <filter id="center-glow" x="-20%" y="-20%" width="140%" height="140%">
94
- <feDropShadow dx="0" dy="0" stdDeviation="8" flood-color="#aaaaaa" flood-opacity="0.5" />
95
- </filter>
96
- </defs>
97
-
98
- <circle cx="200" cy="200" r="160" fill="#050505" />
99
- <circle cx="200" cy="200" r="125" fill="#121212" />
100
-
101
- <path d="M 82.0 101.0 A 154 154 0 0 1 142.3 57.2" fill="none" stroke="#ff0000" stroke-width="12" />
102
- <path d="M 257.7 57.2 A 154 154 0 0 1 318.0 101.0" fill="none" stroke="#00ff00" stroke-width="12" />
103
- <path d="M 265.1 339.6 A 154 154 0 0 1 134.9 339.6" fill="none" stroke="#ff8800" stroke-width="12" />
104
-
105
- <g id="ticks"></g>
106
-
107
- <g id="tick-labels" fill="#bbb" text-anchor="middle" dominant-baseline="middle" font-family="Arial" font-weight="bold">
108
- <text font-size="16" transform="translate(200, 74)">0</text>
109
- <text font-size="16" transform="translate(326, 200) rotate(90)">90</text>
110
- <text font-size="16" transform="translate(74, 200) rotate(-90)">90</text>
111
- <text font-size="16" transform="translate(200, 326) rotate(180)">180</text>
112
- <text font-size="11" transform="translate(262.5, 91.7) rotate(30)">30</text>
113
- <text font-size="11" transform="translate(308.3, 137.5) rotate(60)">60</text>
114
- <text font-size="11" transform="translate(308.3, 262.5) rotate(120)">120</text>
115
- <text font-size="11" transform="translate(262.5, 308.3) rotate(150)">150</text>
116
- <text font-size="11" transform="translate(137.5, 91.7) rotate(-30)">30</text>
117
- <text font-size="11" transform="translate(91.7, 137.5) rotate(-60)">60</text>
118
- <text font-size="11" transform="translate(91.7, 262.5) rotate(-120)">120</text>
119
- <text font-size="11" transform="translate(137.5, 308.3) rotate(-150)">150</text>
120
- </g>
121
-
122
- <g id="track-pointer" transform="rotate(0, 200, 200)">
123
- <path d="M200,42 L194,58 L206,58 Z" fill="#007aff" stroke="#fff" stroke-width="0.5" />
124
- </g>
70
+ <!-- BUSSOLA 1: ANALOGICA STANDARD (Struttura Multilivello a Risparmio Energetico) -->
71
+ <div class="wind-gauge-container">
125
72
 
126
- <circle id="fullscreen-hotspot" cx="200" cy="200" r="55" fill="#181818" stroke="#333" stroke-width="1" filter="url(#center-glow)" cursor="pointer" />
127
-
128
- <path id="boat-icon" d="M200,150 Q165,185 170,250 Q165,190 200,173 Q235,190 230,250 Q235,185 200,150 Z"
129
- fill="url(#axiom-grad)" transform="translate(0, 5)" clip-path="url(#boat-clip)" style="pointer-events: none;" />
130
-
131
- <g id="aws-display-group" transform="translate(200, 265)">
132
- <text x="0" y="0" fill="#777" font-size="10" font-weight="bold" text-anchor="middle" text-transform="uppercase">Apparent Wind kts</text>
133
- <text id="aws-val-svg" x="0" y="42" fill="#fff" font-size="52" font-weight="bold" text-anchor="middle">0.0</text>
134
- </g>
73
+ <!-- LIVELLO 1: SFONDO COMPLETAMENTE STATICO (CPU a riposo 0% per i ricalcoli di layout) -->
74
+ <svg id="wind-gauge" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet">
75
+ <defs>
76
+ <clipPath id="boat-clip"><circle cx="200" cy="200" r="50" /></clipPath>
77
+ <linearGradient id="axiom-grad" x1="0%" y1="0%" x2="0%" y2="100%">
78
+ <stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
79
+ <stop offset="100%" style="stop-color:#888888;stop-opacity:1" />
80
+ </linearGradient>
81
+ <linearGradient id="leeway-grad" x1="0%" y1="0%" x2="100%" y2="0%">
82
+ <stop offset="0%" style="stop-color:#ff0000;stop-opacity:1" />
83
+ <stop offset="25%" style="stop-color:#ff8800;stop-opacity:1" />
84
+ <stop offset="50%" style="stop-color:#00ff00;stop-opacity:1" />
85
+ <stop offset="75%" style="stop-color:#ff8800;stop-opacity:1" />
86
+ <stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" />
87
+ </linearGradient>
88
+ <linearGradient id="leeway-night-grad" x1="0%" y1="0%" x2="100%" y2="0%">
89
+ <stop offset="0%" style="stop-color:#ff0000;stop-opacity:1" />
90
+ <stop offset="50%" style="stop-color:#330000;stop-opacity:1" />
91
+ <stop offset="100%" style="stop-color:#ff0000;stop-opacity:1" />
92
+ </linearGradient>
93
+ <clipPath id="leeway-clip">
94
+ <rect id="leeway-mask-rect" x="125" y="0" width="0" height="12" rx="2" />
95
+ </clipPath>
96
+ <filter id="center-glow" x="-20%" y="-20%" width="140%" height="140%">
97
+ <feDropShadow dx="0" dy="0" stdDeviation="8" flood-color="#aaaaaa" flood-opacity="0.5" />
98
+ </filter>
99
+ </defs>
100
+
101
+ <circle cx="200" cy="200" r="160" fill="#050505" />
102
+ <circle cx="200" cy="200" r="125" fill="#121212" />
103
+
104
+ <path d="M 82.0 101.0 A 154 154 0 0 1 142.3 57.2" fill="none" stroke="#ff0000" stroke-width="12" />
105
+ <path d="M 257.7 57.2 A 154 154 0 0 1 318.0 101.0" fill="none" stroke="#00ff00" stroke-width="12" />
106
+ <path d="M 265.1 339.6 A 154 154 0 0 1 134.9 339.6" fill="none" stroke="#ff8800" stroke-width="12" />
107
+
108
+ <g id="ticks"></g>
109
+
110
+ <g id="tick-labels" fill="#bbb" text-anchor="middle" dominant-baseline="middle" font-family="Arial" font-weight="bold">
111
+ <text font-size="16" transform="translate(200, 74)">0</text>
112
+ <text font-size="16" transform="translate(326, 200) rotate(90)">90</text>
113
+ <text font-size="16" transform="translate(74, 200) rotate(-90)">90</text>
114
+ <text font-size="16" transform="translate(200, 326) rotate(180)">180</text>
115
+ <text font-size="11" transform="translate(262.5, 91.7) rotate(30)">30</text>
116
+ <text font-size="11" transform="translate(308.3, 137.5) rotate(60)">60</text>
117
+ <text font-size="11" transform="translate(308.3, 262.5) rotate(120)">120</text>
118
+ <text font-size="11" transform="translate(262.5, 308.3) rotate(150)">150</text>
119
+ <text font-size="11" transform="translate(137.5, 91.7) rotate(-30)">30</text>
120
+ <text font-size="11" transform="translate(91.7, 137.5) rotate(-60)">60</text>
121
+ <text font-size="11" transform="translate(91.7, 262.5) rotate(-120)">120</text>
122
+ <text font-size="11" transform="translate(137.5, 308.3) rotate(-150)">150</text>
123
+ </g>
124
+
125
+ <circle id="fullscreen-hotspot" cx="200" cy="200" r="55" fill="#181818" stroke="#333" stroke-width="1" filter="url(#center-glow)" cursor="pointer" />
126
+
127
+ <path id="boat-icon" d="M200,150 Q165,185 170,250 Q165,190 200,173 Q235,190 230,250 Q235,185 200,150 Z"
128
+ fill="url(#axiom-grad)" transform="translate(0, 5)" clip-path="url(#boat-clip)" style="pointer-events: none;" />
129
+
130
+ <g id="aws-display-group" transform="translate(200, 265)">
131
+ <text x="0" y="0" fill="#777" font-size="10" font-weight="bold" text-anchor="middle" text-transform="uppercase">Apparent Wind kts</text>
132
+ <text id="aws-val-svg" x="0" y="42" fill="#fff" font-size="52" font-weight="bold" text-anchor="middle">0.0</text>
133
+ </g>
134
+
135
+ <g transform="translate(75, 395)">
136
+ <text x="125" y="-12" id="leeway-val" fill="#aaa" font-size="11" text-anchor="middle" font-weight="bold">LEEWAY: 0.0&deg;</text>
137
+ <rect x="0" y="0" width="250" height="12" fill="#222" rx="3" />
138
+ <rect x="0" y="0" width="250" height="12" fill="url(#leeway-grad)" clip-path="url(#leeway-clip)" rx="3" />
139
+ <g stroke="#555" stroke-width="1">
140
+ <line x1="0" y1="-2" x2="0" y2="14" /><line x1="62.5" y1="2" x2="62.5" y2="10" />
141
+ <line x1="125" y1="-2" x2="125" y2="14" /><line x1="187.5" y1="2" x2="187.5" y2="10" />
142
+ <line x1="250" y1="-2" x2="250" y2="14" />
143
+ </g>
144
+ <g fill="#555" font-size="8" text-anchor="middle" font-weight="bold">
145
+ <text x="0" y="24">-20&deg;</text><text x="62.5" y="24">-10</text>
146
+ <text x="125" y="24">0&deg;</text><text x="187.5" y="24">10</text>
147
+ <text x="250" y="24">20&deg;</text>
148
+ </g>
149
+ </g>
150
+ </svg>
135
151
 
136
- <g id="awa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
137
- <path d="M 200,70 L 213,95 L 200,145 L 187,95 Z" fill="#ff8c00" stroke="#000" stroke-width="1" />
138
- <text x="200" y="90" fill="#000" font-size="10" font-weight="900" text-anchor="middle" font-family="Arial Black">A</text>
139
- </g>
152
+ <!-- LIVELLO 2: OVERLAY LANGETTE (Leggerissimo, promosso alla GPU hardware a 60fps con micro-layouts/sec) -->
153
+ <svg id="wind-gauge-pointers" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet">
154
+ <g id="track-pointer" transform="rotate(0, 200, 200)">
155
+ <path d="M200,42 L194,58 L206,58 Z" fill="#007aff" stroke="#fff" stroke-width="0.5" />
156
+ </g>
140
157
 
141
- <g id="twa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
142
- <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"
143
- fill="#ffff00" stroke="#000" stroke-width="0.8" />
144
- <text x="200" y="106" fill="#000" font-size="9" font-weight="900" text-anchor="middle" font-family="Arial Black">T</text>
145
- <circle id="trend-gauge-cw" cx="215" cy="110" r="4" fill="#bbb" />
146
- <circle id="trend-gauge-ccw" cx="185" cy="110" r="4" fill="#bbb" />
147
- </g>
148
-
149
- <g transform="translate(75, 395)">
150
- <text x="125" y="-12" id="leeway-val" fill="#aaa" font-size="11" text-anchor="middle" font-weight="bold">LEEWAY: 0.0&deg;</text>
151
- <rect x="0" y="0" width="250" height="12" fill="#222" rx="3" />
152
- <rect x="0" y="0" width="250" height="12" fill="url(#leeway-grad)" clip-path="url(#leeway-clip)" rx="3" />
153
- <g stroke="#555" stroke-width="1">
154
- <line x1="0" y1="-2" x2="0" y2="14" /><line x1="62.5" y1="2" x2="62.5" y2="10" />
155
- <line x1="125" y1="-2" x2="125" y2="14" /><line x1="187.5" y1="2" x2="187.5" y2="10" />
156
- <line x1="250" y1="-2" x2="250" y2="14" />
158
+ <g id="awa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
159
+ <path d="M 200,70 L 213,95 L 200,145 L 187,95 Z" fill="#ff8c00" stroke="#000" stroke-width="1" />
160
+ <text x="200" y="90" fill="#000" font-size="10" font-weight="900" text-anchor="middle" font-family="Arial Black">A</text>
157
161
  </g>
158
- <g fill="#555" font-size="8" text-anchor="middle" font-weight="bold">
159
- <text x="0" y="24">-20&deg;</text><text x="62.5" y="24">-10</text>
160
- <text x="125" y="24">0&deg;</text><text x="187.5" y="24">10</text>
161
- <text x="250" y="24">20&deg;</text>
162
+
163
+ <g id="twa-pointer" transform="rotate(0, 200, 200)" opacity="0.9">
164
+ <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"
165
+ fill="#ffff00" stroke="#000" stroke-width="0.8" />
166
+ <text x="200" y="106" fill="#000" font-size="9" font-weight="900" text-anchor="middle" font-family="Arial Black">T</text>
167
+ <circle id="trend-gauge-cw" cx="215" cy="110" r="4" fill="#bbb" />
168
+ <circle id="trend-gauge-ccw" cx="185" cy="110" r="4" fill="#bbb" />
162
169
  </g>
163
- </g>
164
- </svg>
170
+ </svg>
171
+ </div>
165
172
 
166
173
  <!-- BUSSOLA 2: RADAR HISTORICAL (Nascosto all'avvio) -->
167
174
  <svg id="wind-radar" viewBox="35 38 330 395" preserveAspectRatio="xMidYMid meet" style="display: none;">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "7.0.17",
3
+ "version": "7.0.19",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
package/style.css CHANGED
@@ -601,3 +601,44 @@ body.night-mode {
601
601
  .night-mode #wind-radar circle[stroke="#b0bec5"] {
602
602
  stroke: #440000 !important;
603
603
  }
604
+
605
+ /* ==========================================================================
606
+ 13. ARCHITETTURA MULTILIVELLO GPU (60FPS EXTRA LOW-POWER NEEDLES)
607
+ ========================================================================== */
608
+
609
+ /* Contenitore di posizionamento assoluto speculare per i due livelli */
610
+ .wind-gauge-container {
611
+ position: relative;
612
+ width: 100%;
613
+ height: 100%;
614
+ max-height: 100%;
615
+ display: flex;
616
+ align-items: center;
617
+ justify-content: center;
618
+ }
619
+
620
+ /* Forziamo l'overlay delle sole lancette ad allinearsi perfettamente sopra lo sfondo */
621
+ #wind-gauge-pointers {
622
+ position: absolute;
623
+ top: 0; left: 0;
624
+ width: 100%; height: 100%;
625
+ object-fit: contain;
626
+ pointer-events: none; /* Cruciale: permette ai clic del mouse/tocco di passare sotto su #fullscreen-hotspot */
627
+ will-change: transform; /* Promuove l'intero overlay a livello GPU composited */
628
+ }
629
+
630
+ /* Applichiamo lo smorzamento fluido a 60fps solo alle frecce ultra-leggere */
631
+ #awa-pointer, #twa-pointer, #track-pointer {
632
+ transition: transform 0.9s cubic-bezier(0.15, 0.85, 0.3, 1);
633
+ }
634
+
635
+ /* ==========================================================================
636
+ 13. SMORZAMENTO FLUIDO AGHI A 60FPS (DAMPING HARDWARE) non utilizzato consuma troppa cpu
637
+ ==========================================================================
638
+
639
+ Applichiamo la transizione fluida a tutti i puntatori mantenendo i perni nativi dell'SVG
640
+ #awa-pointer, #twa-pointer, #track-pointer, #twd-arrow, #twd-boat-wrap {
641
+ transition: transform 0.9s cubic-bezier(0.25, 0.8, 0.25, 1);
642
+ }
643
+
644
+ */