@sailingrotevista/rotevista-dash 5.0.6 → 5.0.7

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 +93 -12
  2. package/package.json +1 -1
package/app.js CHANGED
@@ -33,7 +33,7 @@ let CONFIG = {
33
33
  };
34
34
 
35
35
  const RENDER_INTERVAL_MS = 1000;
36
- const TIMEOUT_MS = 5000;
36
+ const TIMEOUT_MS = 15000;
37
37
  const SIM_SAMPLE_INTERVAL = 1000;
38
38
  const DASH_VERSION = "3.8"; // Major Update: Smart Source Locking & Breathing Hercules Scale
39
39
 
@@ -75,6 +75,8 @@ const sourceLocks = {};
75
75
  const store = {
76
76
  raw: {},
77
77
  timestamps: {},
78
+ depthProtectedActive: false, // Memoria per lo stato della protezione profondità
79
+ herculesScales: {}, // Memoria per i limiti attivi della modalità Hercules
78
80
  smoothBuf: { hdg: [], cog: [], awa: [], twa: [], twd: [] },
79
81
  longBuf: { hdg: [], cog: [], awa: [], twa: [], twd: [] },
80
82
  histories: { stw: [], sog: [], depth: [], tws: [], vmg: [], aws: [] },
@@ -926,28 +928,107 @@ function manageHistory(type, value) {
926
928
 
927
929
  /**
928
930
  * Gestione dinamica delle scale dei grafici (Involucro Elastico e Safety Zoom)
931
+ * Implementa la logica di sicurezza disaccoppiata a 2 minuti per la profondità.
929
932
  */
930
933
  function calculateScale(type, data, mode) {
931
934
  const s = CONFIG.scales[type];
932
- let aMin = Math.min(...data), aMax = Math.max(...data);
935
+ const currentVal = data[data.length - 1];
933
936
 
934
- // --- SAFETY ZOOM PER PROFONDITÀ (FONDALE BASSO) ---
935
- if (type === 'depth' && mode !== 'hercules') {
936
- const currentDepth = data[data.length - 1];
937
- const shallowThreshold = Math.max(s.stdMax, 10);
938
- if (currentDepth <= shallowThreshold) {
939
- return { min: 0, max: shallowThreshold };
937
+ // Fallback di emergenza se il buffer è momentaneamente vuoto
938
+ if (currentVal === undefined || currentVal === null) {
939
+ return { min: 0, max: s ? s.stdMax : 10 };
940
+ }
941
+
942
+ // Inizializzazione della memoria delle scale nello store se non esiste
943
+ if (!store.herculesScales) store.herculesScales = {};
944
+ if (!store.herculesScales[type]) {
945
+ store.herculesScales[type] = { min: 0, max: s ? s.stdMax : 10 };
946
+ }
947
+ let currentScale = store.herculesScales[type];
948
+
949
+ // ==========================================================================
950
+ // SEZIONE PROFONDITÀ (REGOLA DI SICUREZZA DISACCOPPIATA A 2 MINUTI)
951
+ // ==========================================================================
952
+ if (type === 'depth') {
953
+ const shallowThreshold = Math.max(s.stdMax, 10); // Es. 20m
954
+ if (store.depthProtectedActive === undefined) store.depthProtectedActive = false;
955
+
956
+ const now = Date.now();
957
+ const depthSafetyWindowMs = 120000; // 2 minuti di stabilizzazione fissi per la sicurezza
958
+
959
+ // Estrazione dati reali degli ultimi 2 minuti con timestamp
960
+ const recentPoints = store.histories.depth.filter(p => (now - p.time) <= depthSafetyWindowMs);
961
+ const recentVals = recentPoints.map(p => p.val);
962
+
963
+ const localMax = recentVals.length > 0 ? Math.max(...recentVals) : currentVal;
964
+ const localMin = recentVals.length > 0 ? Math.min(...recentVals) : currentVal;
965
+
966
+ // --- NORMALE PROFONDITÀ (CON SOGLIA STANDARD E FILTRO 2 MINUTI) ---
967
+ if (mode !== 'hercules') {
968
+ // Entrata istantanea sotto lo Standard Max (sicurezza immediata)
969
+ if (!store.depthProtectedActive && currentVal <= shallowThreshold) {
970
+ store.depthProtectedActive = true;
971
+ }
972
+
973
+ // Uscita ritardata: usciamo solo se il minimo degli ultimi 2 minuti è sopra soglia
974
+ if (store.depthProtectedActive) {
975
+ if (localMin > shallowThreshold) {
976
+ store.depthProtectedActive = false;
977
+ }
978
+ }
979
+
980
+ if (store.depthProtectedActive) {
981
+ return { min: 0, max: shallowThreshold }; // Blocco a [0 - 20m]
982
+ }
983
+
984
+ // Se siamo fuori, scala dinamica normale basata sull'intero buffer passato
985
+ const maxHistorico = Math.max(...data);
986
+ return { min: 0, max: Math.max(s.stdMax, Math.ceil(maxHistorico / s.step) * s.step) };
987
+ }
988
+
989
+ // --- HERCULES PROFONDITÀ (0 IN BASSO, ZOOM SUL MASSIMO DEI 2 MINUTI) ---
990
+ if (mode === 'hercules') {
991
+ const padding = 1.0; // 1 metro di margine sopra il fondo
992
+
993
+ // Calcoliamo i limiti ideali basati solo sugli ultimi 2 minuti
994
+ let targetMin = 0;
995
+ let targetMax = Math.ceil(localMax + padding);
996
+
997
+ // Impediamo una scala troppo stretta (minimo 4 metri di range totale per sicurezza)
998
+ const absoluteMinSpan = 4;
999
+ if (targetMax < absoluteMinSpan) {
1000
+ targetMax = absoluteMinSpan;
1001
+ }
1002
+
1003
+ // Regola asimmetrica di aggiornamento
1004
+ if (currentVal > currentScale.max) {
1005
+ // Se andiamo verso il fondo profondo, allarghiamo istantaneamente
1006
+ currentScale.max = targetMax;
1007
+ } else {
1008
+ // Stringiamo lo zoom solo se tutti i dati degli ultimi 2 minuti sono inferiori al target
1009
+ const allStableInTarget = recentVals.every(val => val <= targetMax);
1010
+ if (allStableInTarget) {
1011
+ currentScale.max = targetMax;
1012
+ }
1013
+ }
1014
+
1015
+ currentScale.min = 0;
1016
+ return { min: currentScale.min, max: currentScale.max };
940
1017
  }
941
1018
  }
942
-
943
- // --- MODALITÀ HERCULES AGGIORNATA (INVOLUCRO DINAMICO ELASTICO) ---
1019
+
1020
+ // ==========================================================================
1021
+ // ALTRI GRAFICI (STW, SOG, TWS): MANTENGONO IL COMPORTAMENTO ORIGINALE
1022
+ // ==========================================================================
1023
+ let aMin = Math.min(...data), aMax = Math.max(...data);
1024
+
944
1025
  if (mode === 'hercules') {
945
1026
  const padding = (type === 'stw' || type === 'sog') ? 0.5 : 1.0;
946
1027
 
947
1028
  let min = Math.max(0, Math.floor(aMin - padding));
948
1029
  let max = Math.ceil(aMax + padding);
949
1030
 
950
- // Garantisce uno span minimo configurato per evitare zoom eccessivi sul rumore di fondo
1031
+ // Garantisce lo span minimo
951
1032
  const currentSpan = max - min;
952
1033
  if (currentSpan < s.hercSpan) {
953
1034
  const diff = s.hercSpan - currentSpan;
@@ -955,7 +1036,7 @@ function calculateScale(type, data, mode) {
955
1036
  max = min + s.hercSpan;
956
1037
  }
957
1038
 
958
- // Arrotonda la griglia numerica a step prefissati per evitare sfarfallamento visivo
1039
+ // Arrotonda la griglia numerica a step prefissati
959
1040
  const roundStep = (type === 'stw' || type === 'sog') ? 0.5 : 1.0;
960
1041
  min = Math.floor(min / roundStep) * roundStep;
961
1042
  max = Math.ceil(max / roundStep) * roundStep;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "5.0.6",
3
+ "version": "5.0.7",
4
4
  "description": "Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {