@sailingrotevista/rotevista-dash 5.0.4 → 5.0.5
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 +82 -22
- package/package.json +1 -1
package/app.js
CHANGED
|
@@ -35,7 +35,7 @@ let CONFIG = {
|
|
|
35
35
|
const RENDER_INTERVAL_MS = 1000;
|
|
36
36
|
const TIMEOUT_MS = 5000;
|
|
37
37
|
const SIM_SAMPLE_INTERVAL = 1000;
|
|
38
|
-
const DASH_VERSION = "3.
|
|
38
|
+
const DASH_VERSION = "3.7"; // Major Update: Time-Based storage and GAP handling
|
|
39
39
|
const sourceLocks = {};
|
|
40
40
|
|
|
41
41
|
// ==========================================================================
|
|
@@ -742,37 +742,97 @@ async function watchConfigChanges() {
|
|
|
742
742
|
}
|
|
743
743
|
}
|
|
744
744
|
|
|
745
|
-
// --------------------------------------------------------------------------
|
|
746
|
-
|
|
747
745
|
/**
|
|
748
|
-
*
|
|
746
|
+
* manageHistory v3.7 - Aggregazione semantica "Pro-Grade"
|
|
747
|
+
* Integrazioni:
|
|
748
|
+
* 1. Strict undefined check per lastUpdates.
|
|
749
|
+
* 2. Anti-dropout dinamico tarato sul 50% del Reef 1.
|
|
750
|
+
* 3. Clamping di sicurezza (no negativi, no Infinity).
|
|
749
751
|
*/
|
|
750
|
-
function manageHistory(
|
|
751
|
-
|
|
752
|
-
|
|
752
|
+
function manageHistory(type, value) {
|
|
753
|
+
// --- 1. VALIDAZIONE INPUT RIGOROSA ---
|
|
754
|
+
if (value === undefined || value === null || !isFinite(value)) return;
|
|
755
|
+
|
|
756
|
+
const now = Date.now();
|
|
757
|
+
const historyMinutes = Math.max(1, CONFIG.graphs.historyMinutes || 10);
|
|
758
|
+
const samples = Math.max(2, CONFIG.graphs.samples || 60);
|
|
759
|
+
const bucketIntervalMs = (historyMinutes * 60000) / samples;
|
|
760
|
+
|
|
761
|
+
// --- 2. INIT SICURO (Strict Check) ---
|
|
762
|
+
if (!store.graphTempBuf[type]) store.graphTempBuf[type] = [];
|
|
763
|
+
if (!store.histories[type]) store.histories[type] = [];
|
|
764
|
+
if (store.lastUpdates[type] === undefined) store.lastUpdates[type] = 0;
|
|
765
|
+
|
|
766
|
+
const tempBuf = store.graphTempBuf[type];
|
|
767
|
+
|
|
768
|
+
// --- 3. ANTI-DROPOUT DINAMICO (Auto-scaling) ---
|
|
769
|
+
// Ignora cadute a zero se il valore precedente era superiore al 50% del primo Reef
|
|
770
|
+
if ((type === 'tws' || type === 'aws') && value < 0.05 && tempBuf.length > 0) {
|
|
771
|
+
const lastPoint = tempBuf[tempBuf.length - 1];
|
|
772
|
+
const glitchThreshold = (CONFIG.graphs.reef1 || 15) * 0.5;
|
|
773
|
+
if (lastPoint && lastPoint.val > glitchThreshold) return;
|
|
774
|
+
}
|
|
753
775
|
|
|
754
|
-
|
|
755
|
-
|
|
776
|
+
// --- 4. STORAGE TEMPORANEO ---
|
|
777
|
+
tempBuf.push({ val: value, time: now });
|
|
756
778
|
|
|
757
|
-
|
|
758
|
-
|
|
779
|
+
// Controllo finestra temporale
|
|
780
|
+
const bucketReady = (now - store.lastUpdates[type] > bucketIntervalMs) || store.histories[type].length === 0;
|
|
781
|
+
if (!bucketReady) return;
|
|
759
782
|
|
|
760
|
-
|
|
761
|
-
|
|
783
|
+
// --- 5. AGGREGAZIONE SEMANTICA ---
|
|
784
|
+
let finalValue = value;
|
|
762
785
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
786
|
+
if (tempBuf.length > 0) {
|
|
787
|
+
// A. VENTO -> SUSTAINED PEAK (EMA Time-Aware)
|
|
788
|
+
if (type === 'tws' || type === 'aws') {
|
|
789
|
+
const tauMs = 2500;
|
|
790
|
+
let ema = tempBuf[0].val;
|
|
791
|
+
let maxSustained = ema;
|
|
766
792
|
|
|
767
|
-
|
|
768
|
-
|
|
793
|
+
for (let i = 1; i < tempBuf.length; i++) {
|
|
794
|
+
const dt = Math.max(1, tempBuf[i].time - tempBuf[i - 1].time);
|
|
795
|
+
const alpha = 1 - Math.exp(-dt / tauMs);
|
|
796
|
+
ema = (tempBuf[i].val * alpha) + (ema * (1 - alpha));
|
|
797
|
+
if (isFinite(ema) && ema > maxSustained) maxSustained = ema;
|
|
798
|
+
}
|
|
799
|
+
finalValue = maxSustained;
|
|
800
|
+
}
|
|
801
|
+
// B. PROFONDITÀ -> MINIMO
|
|
802
|
+
else if (type === 'depth') {
|
|
803
|
+
const vals = tempBuf.map(p => p.val).filter(v => isFinite(v));
|
|
804
|
+
if (vals.length > 0) finalValue = Math.min(...vals);
|
|
805
|
+
}
|
|
806
|
+
// C. VELOCITÀ -> MEDIA
|
|
807
|
+
else {
|
|
808
|
+
const vals = tempBuf.map(p => p.val).filter(v => isFinite(v));
|
|
809
|
+
if (vals.length > 0) {
|
|
810
|
+
const sum = vals.reduce((a, b) => a + b, 0);
|
|
811
|
+
finalValue = sum / tempBuf.length;
|
|
812
|
+
}
|
|
769
813
|
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// --- 6. CLAMPING E VALIDAZIONE FINALE ---
|
|
817
|
+
// Protezione contro valori negativi (fisicamente impossibili per questi dati) e non finiti
|
|
818
|
+
if (!isFinite(finalValue)) return;
|
|
819
|
+
finalValue = Math.max(0, finalValue);
|
|
820
|
+
|
|
821
|
+
// --- 7. STORAGE STORICO (Keys: val, time) ---
|
|
822
|
+
store.histories[type].push({ val: finalValue, time: now });
|
|
770
823
|
|
|
771
|
-
|
|
772
|
-
|
|
824
|
+
// --- 8. PRUNING DINAMICO ---
|
|
825
|
+
const maxViewportMinutes = historyMinutes * 2;
|
|
826
|
+
const maxHistoryMs = (maxViewportMinutes * 60000) + 60000;
|
|
827
|
+
|
|
828
|
+
while (store.histories[type].length > 0 && (now - store.histories[type][0].time) > maxHistoryMs) {
|
|
829
|
+
store.histories[type].shift();
|
|
773
830
|
}
|
|
774
|
-
}
|
|
775
831
|
|
|
832
|
+
// Reset per il prossimo bucket
|
|
833
|
+
store.graphTempBuf[type] = [];
|
|
834
|
+
store.lastUpdates[type] = now;
|
|
835
|
+
}
|
|
776
836
|
function calculateScale(type, data, mode) {
|
|
777
837
|
const s = CONFIG.scales[type]; let aMin = Math.min(...data), aMax = Math.max(...data);
|
|
778
838
|
if (mode === 'hercules') {
|
|
@@ -1069,7 +1129,7 @@ async function init() {
|
|
|
1069
1129
|
await fetchServerConfig();
|
|
1070
1130
|
startDisplayLoop();
|
|
1071
1131
|
connect();
|
|
1072
|
-
setInterval(watchConfigChanges, 10000);
|
|
1132
|
+
setInterval(watchConfigChanges, 10000);
|
|
1073
1133
|
}
|
|
1074
1134
|
|
|
1075
1135
|
window.addEventListener('load', init);
|