@sailingrotevista/rotevista-dash 7.0.39 → 7.0.41

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 CHANGED
@@ -705,11 +705,14 @@ function startDisplayLoop() {
705
705
  "navigation.speedThroughWater": ui.stw, "navigation.speedOverGround": ui.sog,
706
706
  "navigation.headingTrue": ui.hdg, "navigation.courseOverGroundTrue": ui.cog,
707
707
  "environment.wind.speedApparent": ui.awsSvg, "environment.depth.belowTransducer": ui.depth,
708
- "environment.wind.speedTrue": ui.tws
708
+ "environment.wind.speedTrue": ui.tws,
709
+ "environment.wind.angleApparent": ui.awaAvg,
710
+ "environment.wind.angleTrueWater": ui.twaAvg,
711
+ "environment.wind.directionTrue": ui.twdAvg
709
712
  };
710
713
  for (let p in watch) {
711
714
  if (!store.timestamps[p] || (now - store.timestamps[p] > TIMEOUT_MS)) {
712
- safeSetText(watch[p], "---"); // Sostituito innerText con la funzione protetta!
715
+ if (watch[p]) safeSetText(watch[p], "---");
713
716
  delete store.raw[p];
714
717
 
715
718
  // Forza lo scorrimento dei dati fuori dallo schermo per i sensori in timeout
package/charts.js CHANGED
@@ -90,29 +90,13 @@ function calculateScale(type, data, mode) {
90
90
 
91
91
  if (mode === 'hercules') {
92
92
  const roundStep = s.hercSpan;
93
+ // Finestra di calcolo ad alta risoluzione: ancorata rigorosamente all'ultimo terzo dei dati
93
94
  const oneThirdCount = Math.max(1, Math.floor(data.length / 3));
94
95
  const recentThirdData = data.slice(-oneThirdCount);
95
96
 
96
97
  let localMin = Math.min(...recentThirdData);
97
98
  let localMax = Math.max(...recentThirdData);
98
99
 
99
- // SMART MOTORING DETECTION (Specifica per i grafici di velocità: STW, SOG, VMG)
100
- const isSpeedType = (type === 'stw' || type === 'sog' || type === 'vmg');
101
- if (isSpeedType && data.length > oneThirdCount) {
102
- const olderData = data.slice(0, data.length - oneThirdCount);
103
- const olderMin = Math.min(...olderData);
104
- const olderMax = Math.max(...olderData);
105
- const olderRange = olderMax - olderMin; // Variazione nello storico passato
106
-
107
- // Se lo storico passato non era piatto (range > 0.2 nodi) oppure eravamo fermi/all'ancora (< 1.5 nodi),
108
- // significa che il passato è rilevante per il trend. Includiamo il passato nel calcolo della scala Y.
109
- // Se invece era piatto (motore), lo ignoriamo per zoomare subito sulla vela attuale.
110
- if (olderRange > 0.2 || olderMin < 0.77) {
111
- localMin = Math.min(localMin, olderMin);
112
- localMax = Math.max(localMax, olderMax);
113
- }
114
- }
115
-
116
100
  let targetMin = Math.max(0, Math.floor(localMin / roundStep) * roundStep);
117
101
  let targetMax = Math.ceil(localMax / roundStep) * roundStep;
118
102
 
package/gauge.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * ==========================================================================
5
5
  * Gestisce l'aggiornamento grafico dei puntatori analogici (AWA, TWA),
6
6
  * dello scarroccio (Leeway), della rotta (Track) e dei trend della bussola.
7
- * file gauge,js
7
+ * file gauge.js
8
8
  */
9
9
 
10
10
  // 1. VARIABILI DI STATO DELLE ROTAZIONI (Estratte da app.js)
@@ -54,29 +54,37 @@ function updateCentralGauge(store, ui, now, isNavigating, sogKts, stwKts, rawAws
54
54
  }
55
55
  }
56
56
 
57
- // B. Rotazione dei puntatori analogici di AWA (Apparent) e TWA (True)
58
- const smAwa = getCircularAverageFromBuffer(store.smoothBuf.awa, 2000, true);
59
- const smTwa = getCircularAverageFromBuffer(store.smoothBuf.twa, 2000, true);
60
- if (smAwa) ui.awa.setAttribute('transform', `rotate(${curAwaRot = getShortestRotation(curAwaRot, radToDeg(smAwa.val))}, 200, 200)`);
61
- if (smTwa) ui.twa.setAttribute('transform', `rotate(${curTwaRot = getShortestRotation(curTwaRot, radToDeg(smTwa.val))}, 200, 200)`);
57
+ // B. Rotazione dei puntatori analogici di AWA (Apparent) e TWA (True) con passaggio di timestamp "now"
58
+ const smAwa = getCircularAverageFromBuffer(store.smoothBuf.awa, 2000, true, now);
59
+ const smTwa = getCircularAverageFromBuffer(store.smoothBuf.twa, 2000, true, now);
60
+ if (smAwa) ui.awa.setAttribute('transform', `rotate(${curAwaRot = getShortestRotation(curAwaRot, radToDeg(smAwa.val))}, 200, 200)`);
61
+ if (smTwa) ui.twa.setAttribute('transform', `rotate(${curTwaRot = getShortestRotation(curTwaRot, radToDeg(smTwa.val))}, 200, 200)`);
62
62
 
63
- // C. Calcolo dello Scarroccio (Leeway) e orientamento del vettore Track
64
- if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
65
- let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (2 * Math.PI) - Math.PI);
66
- smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
67
- curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway);
68
- ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
69
- ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#ff9800" : "";
70
- updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
71
- }
63
+ // C. Calcolo dello Scarroccio (Leeway) e orientamento del vettore Track
64
+ if (store.raw["navigation.courseOverGroundTrue"] !== undefined && store.raw["navigation.headingTrue"] !== undefined) {
65
+ let driftDeg = radToDeg((store.raw["navigation.courseOverGroundTrue"] - store.raw["navigation.headingTrue"] + Math.PI * 3) % (2 * Math.PI) - Math.PI);
66
+ smoothedLeeway = (sogKts < CONFIG.averaging.minSpeed) ? 0 : (smoothedLeeway * 0.9) + (driftDeg * 0.1);
67
+ curTrackRot = getShortestRotation(curTrackRot, smoothedLeeway);
68
+ ui.track.setAttribute('transform', `rotate(${curTrackRot}, 200, 200)`);
69
+ ui.leewayVal.style.color = (Math.abs(sogKts - stwKts) > 0.5 && Math.abs(smoothedLeeway) > 7) ? "#ff9800" : "";
70
+ updateLeewayDisplay(Math.max(-20, Math.min(20, smoothedLeeway)));
71
+ }
72
72
 
73
73
  // D. Orientamento delle icone della barca e del vento nel Mini-Compass (TWD)
74
- const smHdgIcons = getCircularAverageFromBuffer(store.smoothBuf.hdg, 2000, false);
75
- const smTwdIcons = getCircularAverageFromBuffer(store.smoothBuf.twd, 2000, false);
76
- if (smHdgIcons && smTwdIcons) {
77
- curWindCompassRot = getShortestRotation(curWindCompassRot, radToDeg(smTwdIcons.val));
74
+ // Sincronizzato con la media a 30s (longBuf) e fallback istantaneo su store.raw per allineamento al testo
75
+ const longWindow = CONFIG.averaging.longWindow || 30000;
76
+ const smHdgIcons = getCircularAverageFromBuffer(store.longBuf.hdg, longWindow * 2, false, now);
77
+ const smTwdIcons = getCircularAverageFromBuffer(store.longBuf.twd, longWindow, false, now);
78
+
79
+ const twdAngleRad = smTwdIcons ? smTwdIcons.val : store.raw["environment.wind.directionTrue"];
80
+ if (twdAngleRad !== undefined && twdAngleRad !== null) {
81
+ curWindCompassRot = getShortestRotation(curWindCompassRot, radToDeg(twdAngleRad));
78
82
  ui.twdArrow.setAttribute('transform', `rotate(${curWindCompassRot}, 20, 20)`);
79
- curBoatCompassRot = getShortestRotation(curBoatCompassRot, radToDeg(smHdgIcons.val));
83
+ }
84
+
85
+ const hdgAngleRad = smHdgIcons ? smHdgIcons.val : store.raw["navigation.headingTrue"];
86
+ if (hdgAngleRad !== undefined && hdgAngleRad !== null) {
87
+ curBoatCompassRot = getShortestRotation(curBoatCompassRot, radToDeg(hdgAngleRad));
80
88
  ui.twdBoat.setAttribute('transform', `rotate(${curBoatCompassRot}, 20, 20)`);
81
89
  }
82
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "7.0.39",
3
+ "version": "7.0.41",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
package/utils.js CHANGED
@@ -36,8 +36,11 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
36
36
  const len = bufferArray.length;
37
37
  if (len === 0) return null;
38
38
 
39
- // RIFERIMENTO TEMPORALE IMMUNE DA DESINCRONIZZAZIONE (Usa l'ultimo dato del buffer)
40
- const referenceTime = bufferArray[len - 1].time;
39
+ const currentTime = now || Date.now();
40
+ const newestSampleTime = bufferArray[len - 1].time;
41
+
42
+ // Se l'ultimo pacchetto registrato nel buffer ha più di 15 secondi di silenzio, il sensore è offline
43
+ if ((currentTime - newestSampleTime) > 15000) return null;
41
44
 
42
45
  let sSin = 0, sCos = 0, count = 0;
43
46
  let newestTime = 0, oldestTime = 0;
@@ -53,7 +56,8 @@ function getCircularAverageFromBuffer(bufferArray, windowMs, signed = false, now
53
56
 
54
57
  for (let i = len - 1; i >= 0; i--) {
55
58
  const item = bufferArray[i];
56
- if ((referenceTime - item.time) > windowMs) break;
59
+ // Decadimento temporale reale ancorato sull'orologio corrente
60
+ if ((currentTime - item.time) > windowMs) break;
57
61
 
58
62
  let diffRad = Math.atan2(Math.sin(item.val - pilotRad), Math.cos(item.val - pilotRad));
59
63
  let finalSin, finalCos;