@sailingrotevista/rotevista-dash 7.0.38 → 7.0.40
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 +8 -14
- package/charts.js +1 -17
- package/gauge.js +19 -19
- package/package.json +1 -1
- package/utils.js +7 -3
- package/weather-radar.js +5 -3
- package/debug_sample_radar.html +0 -887
- package/debug_signalk_connection.html +0 -70
- package/debug_weather_radar.html +0 -233
package/app.js
CHANGED
|
@@ -77,6 +77,7 @@ const sourceLocks = {};
|
|
|
77
77
|
const store = {
|
|
78
78
|
raw: {},
|
|
79
79
|
timestamps: {},
|
|
80
|
+
isNavigating: false, // Stato unificato di navigazione barca in movimento
|
|
80
81
|
depthProtectedActive: false, // Memoria per lo stato della protezione profondità
|
|
81
82
|
herculesScales: {}, // Memoria per i limiti attivi della modalità Hercules
|
|
82
83
|
smoothBuf: { hdg: [], cog: [], awa: [], twa: [], twd: [] },
|
|
@@ -662,6 +663,7 @@ function startDisplayLoop() {
|
|
|
662
663
|
const sogKts = msToKts(store.raw["navigation.speedOverGround"] || 0);
|
|
663
664
|
|
|
664
665
|
isNavigating = stwKts > CONFIG.averaging.minSpeed || sogKts > CONFIG.averaging.minSpeed;
|
|
666
|
+
store.isNavigating = isNavigating; // Sincronizzazione stato nello store condiviso
|
|
665
667
|
|
|
666
668
|
// --- CALCOLO TREND VENTO & ALLARME STRAMBATA ---
|
|
667
669
|
updateWindTrend();
|
|
@@ -703,11 +705,14 @@ function startDisplayLoop() {
|
|
|
703
705
|
"navigation.speedThroughWater": ui.stw, "navigation.speedOverGround": ui.sog,
|
|
704
706
|
"navigation.headingTrue": ui.hdg, "navigation.courseOverGroundTrue": ui.cog,
|
|
705
707
|
"environment.wind.speedApparent": ui.awsSvg, "environment.depth.belowTransducer": ui.depth,
|
|
706
|
-
"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
|
|
707
712
|
};
|
|
708
713
|
for (let p in watch) {
|
|
709
714
|
if (!store.timestamps[p] || (now - store.timestamps[p] > TIMEOUT_MS)) {
|
|
710
|
-
safeSetText(watch[p], "---");
|
|
715
|
+
if (watch[p]) safeSetText(watch[p], "---");
|
|
711
716
|
delete store.raw[p];
|
|
712
717
|
|
|
713
718
|
// Forza lo scorrimento dei dati fuori dallo schermo per i sensori in timeout
|
|
@@ -1032,18 +1037,7 @@ async function fetchServerHistory() {
|
|
|
1032
1037
|
timestamp: data.futureForecast.timestamp + timeDelta
|
|
1033
1038
|
};
|
|
1034
1039
|
}
|
|
1035
|
-
|
|
1036
|
-
store.twdMinuteBuffer = data.twd.map(p => ({
|
|
1037
|
-
...p,
|
|
1038
|
-
time: p.time + timeDelta
|
|
1039
|
-
}));
|
|
1040
|
-
}
|
|
1041
|
-
if (data.tws) {
|
|
1042
|
-
store.twsMinuteBuffer = data.tws.map(p => ({
|
|
1043
|
-
...p,
|
|
1044
|
-
time: p.time + timeDelta
|
|
1045
|
-
}));
|
|
1046
|
-
}
|
|
1040
|
+
// data.twd e data.tws sono già mappati direttamente in store.histories.twd e store.histories.tws
|
|
1047
1041
|
|
|
1048
1042
|
// Sincronizziamo lo storico dei minuti per il radar, ma lasciamo che il buffer rapido 'store.longBuf.twd'
|
|
1049
1043
|
// parta pulito all'avvio. Si popolerà istantaneamente a 3Hz con i soli dati in tempo reale,
|
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
|
|
7
|
+
* file gauge.js
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
// 1. VARIABILI DI STATO DELLE ROTAZIONI (Estratte da app.js)
|
|
@@ -54,26 +54,26 @@ 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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
// D. Orientamento delle icone della barca e del vento nel Mini-Compass (TWD) con passaggio di timestamp "now"
|
|
74
|
+
const smHdgIcons = getCircularAverageFromBuffer(store.smoothBuf.hdg, 2000, false, now);
|
|
75
|
+
const smTwdIcons = getCircularAverageFromBuffer(store.smoothBuf.twd, 2000, false, now);
|
|
76
|
+
if (smHdgIcons && smTwdIcons) {
|
|
77
77
|
curWindCompassRot = getShortestRotation(curWindCompassRot, radToDeg(smTwdIcons.val));
|
|
78
78
|
ui.twdArrow.setAttribute('transform', `rotate(${curWindCompassRot}, 20, 20)`);
|
|
79
79
|
curBoatCompassRot = getShortestRotation(curBoatCompassRot, radToDeg(smHdgIcons.val));
|
package/package.json
CHANGED
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
|
-
|
|
40
|
-
const
|
|
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
|
-
|
|
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;
|
package/weather-radar.js
CHANGED
|
@@ -59,8 +59,9 @@ function calculateActive30mRing() {
|
|
|
59
59
|
const now = Date.now();
|
|
60
60
|
const start30m = now - 1800000;
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
const
|
|
62
|
+
// Lettura unificata dai buffer storici dello store
|
|
63
|
+
const twdRecent = (store.histories.twd || []).filter(p => p.time >= start30m);
|
|
64
|
+
const twsRecent = (store.histories.tws || []).filter(p => p.time >= start30m);
|
|
64
65
|
|
|
65
66
|
if (twdRecent.length === 0) return null;
|
|
66
67
|
|
|
@@ -264,7 +265,8 @@ function renderRadar() {
|
|
|
264
265
|
// Disegno del LED lampeggiante del meteo-trend
|
|
265
266
|
if (activeRing && !activeRing.isCalm) {
|
|
266
267
|
const twdNow = getCircularAverageFromBuffer(store.longBuf.twd, 60000, false);
|
|
267
|
-
const
|
|
268
|
+
const isNav = (typeof store !== 'undefined' && store.isNavigating);
|
|
269
|
+
const strategicWindowMs = (isNav ? 15 : 60) * 60000;
|
|
268
270
|
const twdRef = getCircularAverageFromBuffer(store.longBuf.twd, strategicWindowMs, false);
|
|
269
271
|
|
|
270
272
|
if (twdNow && twdRef) {
|