@sailingrotevista/rotevista-dash 7.0.32 → 7.0.34

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 (2) hide show
  1. package/app.js +65 -58
  2. package/package.json +1 -1
package/app.js CHANGED
@@ -377,17 +377,25 @@ function processIncomingData(path, val, source, timeMs) {
377
377
  store.timestamps[path] = now;
378
378
  store.raw[path] = val;
379
379
 
380
+ // Converte e aggiorna istantaneamente store.raw["navigation.headingTrue"] prima del rate limiter per evitare ritardi UI
381
+ if (path === "navigation.headingMagnetic") {
382
+ const hasNativeTrueHdg = store.timestamps["navigation.headingTrueNative"] && (now - store.timestamps["navigation.headingTrueNative"] < 5000);
383
+ if (!hasNativeTrueHdg) {
384
+ const variation = store.raw["navigation.magneticVariation"] || 0;
385
+ store.raw["navigation.headingTrue"] = (val + variation + 2 * Math.PI) % (2 * Math.PI);
386
+ store.timestamps["navigation.headingTrue"] = now;
387
+ }
388
+ }
389
+
380
390
  // Le coordinate GPS e la posizione non sono soggette alla limitazione a 1Hz
381
391
  if (path === "navigation.position") {
382
- return; // Esce subito (non richiede calcoli trigonometrici o inserimenti in smoothBuf/longBuf)
392
+ return; // Esce subito
383
393
  }
384
394
 
385
395
  // LIMITATORE DI FREQUENZA (RATE LIMITER) CLIENT-SIDE A 1HZ PER PERCORSO ATTIVO:
386
- // Evita di eseguire calcoli trigonometrici, allocare oggetti in memoria dinamica
387
- // e popolare i buffer smoothBuf/longBuf decine di volte al secondo per singolo sensore.
388
396
  if (!lastPathProcessTimes[path]) lastPathProcessTimes[path] = 0;
389
397
  if (now - lastPathProcessTimes[path] < 800) {
390
- return; // Esce subito risparmiando cicli di calcolo del browser e batteria del tablet
398
+ return; // Esce subito risparmiando cicli di calcolo
391
399
  }
392
400
  lastPathProcessTimes[path] = now;
393
401
 
@@ -805,65 +813,64 @@ function startDisplayLoop() {
805
813
  }
806
814
 
807
815
  // --- SLOW TIER (Salvataggio stato ogni 10 secondi) ---
808
- if (lastAvgUIUpdate++ % 10 === 0) {
809
- saveDashboardState();
810
- }
816
+ if (lastAvgUIUpdate++ % 10 === 0) {
817
+ saveDashboardState();
818
+ }
811
819
 
812
- // AGGIORNAMENTO FLUIDO MEDIE UI (Esecuzione a 1Hz costante ad ogni secondo)
813
- const baseThreshold = CONFIG.averaging.stabilityThreshold || 0.95;
814
- const breakout = CONFIG.averaging.stabilityBreakout || 15;
815
-
816
- // CALCOLO DIFFERENZIALE: Tolleranza del vento proporzionale alla sensibilità di base
817
- const windThreshold = Math.max(0.60, baseThreshold - 0.13);
820
+ // AGGIORNAMENTO FLUIDO MEDIE UI (Esecuzione a 1Hz costante ad ogni secondo)
821
+ const baseThreshold = CONFIG.averaging.stabilityThreshold || 0.95;
822
+ const breakout = CONFIG.averaging.stabilityBreakout || 15;
823
+
824
+ // CALCOLO DIFFERENZIALE: Tolleranza del vento proporzionale alla sensibilità di base
825
+ const windThreshold = Math.max(0.60, baseThreshold - 0.13);
818
826
 
819
- let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false, now, baseThreshold, breakout);
820
- let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false, now, baseThreshold, breakout);
821
-
822
- // Applichiamo la soglia differenziale ottimizzata per i tre dati legati al vento
823
- let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
824
- let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
825
- let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false, now, windThreshold, breakout);
826
-
827
- // --- GESTIONE DINAMICA ETICHETTA TACK/GYBE CON ISTERESI DI 10 GRADI ---
828
- if (ui.tackLabel) {
829
- const absTwa = Math.abs(radToDeg(store.raw["environment.wind.angleTrueWater"] || 0));
830
- if (currentTackLabelMode === 'TACK' && absTwa > 95) {
831
- currentTackLabelMode = 'GYBE';
832
- } else if (currentTackLabelMode === 'GYBE' && absTwa < 85) {
833
- currentTackLabelMode = 'TACK';
834
- }
835
- safeSetText(ui.tackLabel, currentTackLabelMode);
827
+ let hObj = getCircularAverageFromBuffer(store.longBuf.hdg, CONFIG.averaging.longWindow * 2, false, now, baseThreshold, breakout);
828
+ let cObj = getCircularAverageFromBuffer(store.longBuf.cog, CONFIG.averaging.longWindow, false, now, baseThreshold, breakout);
829
+
830
+ // Applichiamo la soglia differenziale ottimizzata per i tre dati legati al vento
831
+ let awObj = getCircularAverageFromBuffer(store.longBuf.awa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
832
+ let twObj = getCircularAverageFromBuffer(store.longBuf.twa, CONFIG.averaging.longWindow, true, now, windThreshold, breakout);
833
+ let twdObj = getCircularAverageFromBuffer(store.longBuf.twd, CONFIG.averaging.longWindow, false, now, windThreshold, breakout);
834
+
835
+ // --- GESTIONE DINAMICA ETICHETTA TACK/GYBE CON ISTERESI DI 10 GRADI ---
836
+ if (ui.tackLabel) {
837
+ const absTwa = Math.abs(radToDeg(store.raw["environment.wind.angleTrueWater"] || 0));
838
+ if (currentTackLabelMode === 'TACK' && absTwa > 95) {
839
+ currentTackLabelMode = 'GYBE';
840
+ } else if (currentTackLabelMode === 'GYBE' && absTwa < 85) {
841
+ currentTackLabelMode = 'TACK';
836
842
  }
843
+ safeSetText(ui.tackLabel, currentTackLabelMode);
844
+ }
837
845
 
838
- upUI(ui.hdg, hObj, store.raw["navigation.headingTrue"], true);
839
- upUI(ui.cog, cObj, store.raw["navigation.courseOverGroundTrue"], true);
840
- upUI(ui.awaAvg, awObj, store.raw["environment.wind.angleApparent"], false);
841
- upUI(ui.twaAvg, twObj, store.raw["environment.wind.angleTrueWater"], false);
842
- upUI(ui.twdAvg, twdObj, store.raw["environment.wind.directionTrue"], true);
843
-
844
- if (hObj && twdObj) {
845
- const reflectAngle = (targetRad, axisRad) => {
846
- const dS = Math.sin(axisRad - targetRad);
847
- const dC = Math.cos(axisRad - targetRad);
848
- return Math.atan2(Math.sin(axisRad) * dC + Math.cos(axisRad) * dS, Math.cos(axisRad) * dC - Math.sin(axisRad) * dS);
849
- };
850
- const unstableH = !hObj.stable || !twdObj.stable || hObj.dev > CONFIG.averaging.stabilityBreakout;
851
- if (!isNavigating) ui.tackHdg.innerHTML = "---&deg;";
852
- else if (unstableH) { ui.tackHdg.innerHTML = "---&deg;"; ui.tackHdg.classList.add('unstable-data'); }
846
+ upUI(ui.hdg, hObj, store.raw["navigation.headingTrue"], true);
847
+ upUI(ui.cog, cObj, store.raw["navigation.courseOverGroundTrue"], true);
848
+ upUI(ui.awaAvg, awObj, store.raw["environment.wind.angleApparent"], false);
849
+ upUI(ui.twaAvg, twObj, store.raw["environment.wind.angleTrueWater"], false);
850
+ upUI(ui.twdAvg, twdObj, store.raw["environment.wind.directionTrue"], true);
851
+
852
+ if (hObj && twdObj) {
853
+ const reflectAngle = (targetRad, axisRad) => {
854
+ const dS = Math.sin(axisRad - targetRad);
855
+ const dC = Math.cos(axisRad - targetRad);
856
+ return Math.atan2(Math.sin(axisRad) * dC + Math.cos(axisRad) * dS, Math.cos(axisRad) * dC - Math.sin(axisRad) * dS);
857
+ };
858
+ const unstableH = !hObj.stable || !twdObj.stable || hObj.dev > CONFIG.averaging.stabilityBreakout;
859
+ if (!isNavigating) ui.tackHdg.innerHTML = "---&deg;";
860
+ else if (unstableH) { ui.tackHdg.innerHTML = "---&deg;"; ui.tackHdg.classList.add('unstable-data'); }
861
+ else {
862
+ const rH = (radToDeg(reflectAngle(hObj.val, twdObj.val)) + 360) % 360;
863
+ ui.tackHdg.innerHTML = `${Math.round(rH).toString().padStart(3, '0')}&deg;`;
864
+ ui.tackHdg.classList.remove('unstable-data');
865
+ }
866
+ if (cObj) {
867
+ const unstableC = !cObj.stable || !twdObj.stable || cObj.dev > CONFIG.averaging.stabilityBreakout;
868
+ if (!isNavigating) ui.tackCog.innerHTML = "---&deg;";
869
+ else if (unstableC) { ui.tackCog.innerHTML = "---&deg;"; ui.tackCog.classList.add('unstable-data'); }
853
870
  else {
854
- const rH = (radToDeg(reflectAngle(hObj.val, twdObj.val)) + 360) % 360;
855
- ui.tackHdg.innerHTML = `${Math.round(rH).toString().padStart(3, '0')}&deg;`;
856
- ui.tackHdg.classList.remove('unstable-data');
857
- }
858
- if (cObj) {
859
- const unstableC = !cObj.stable || !twdObj.stable || cObj.dev > CONFIG.averaging.stabilityBreakout;
860
- if (!isNavigating) ui.tackCog.innerHTML = "---&deg;";
861
- else if (unstableC) { ui.tackCog.innerHTML = "---&deg;"; ui.tackCog.classList.add('unstable-data'); }
862
- else {
863
- const rC = (radToDeg(reflectAngle(cObj.val, twdObj.val)) + 360) % 360;
864
- ui.tackCog.innerHTML = `${Math.round(rC).toString().padStart(3, '0')}&deg;`;
865
- ui.tackCog.classList.remove('unstable-data');
866
- }
871
+ const rC = (radToDeg(reflectAngle(cObj.val, twdObj.val)) + 360) % 360;
872
+ ui.tackCog.innerHTML = `${Math.round(rC).toString().padStart(3, '0')}&deg;`;
873
+ ui.tackCog.classList.remove('unstable-data');
867
874
  }
868
875
  }
869
876
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "7.0.32",
3
+ "version": "7.0.34",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {