signalk-polar-performance-plugin 0.0.59 → 0.0.60

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-polar-performance-plugin",
3
- "version": "0.0.59",
3
+ "version": "0.0.60",
4
4
  "description": "A plugin that calculates performance information based on a (CSV) polar diagram.",
5
5
  "main": "plugin/index.js",
6
6
  "scripts": {
package/plugin/index.js CHANGED
@@ -116,13 +116,25 @@ module.exports = function (app) {
116
116
  plugin.registerWithRouter = function (router) {
117
117
  // Will appear here; plugins/signalk-polar-performance-plugin/
118
118
  app.debug('registerWithRouter')
119
+ // Middleware to set Origin-Agent-Cluster on every response from this plugin
120
+ router.use((req, res, next) => {
121
+ res.set('Origin-Agent-Cluster', '?1')
122
+ next()
123
+ })
119
124
  router.get('/polar', (req, res) => {
120
125
  res.contentType('application/json')
121
126
  res.send(JSON.stringify(polar))
122
127
  })
123
128
  router.get('/chartData', (req, res) => {
124
- res.contentType('application/json')
125
- res.send(JSON.stringify(getChartData()))
129
+ const chart = getChartData();
130
+ if (!chart || !chart.datasets || chart.datasets.length === 0) {
131
+ return res.status(500).json({
132
+ error: "No polar data",
133
+ reason: "Polar CSV is empty or invalid. Please configure a valid polar in plugin settings."
134
+ })
135
+ }
136
+ res.contentType('application/json');
137
+ res.send(JSON.stringify(chart));
126
138
  })
127
139
  }
128
140
 
package/public/index.html CHANGED
@@ -35,6 +35,26 @@
35
35
  padding: 4px;
36
36
  font-size: 14px;
37
37
  }
38
+
39
+ #error-banner {
40
+ position: fixed;
41
+ bottom: 0;
42
+ left: 0;
43
+ right: 0;
44
+ background: rgba(220, 60, 60, 0.95);
45
+ color: white;
46
+ text-align: center;
47
+ padding: 14px 20px;
48
+ font-size: 15px;
49
+ z-index: 1000;
50
+ box-shadow: 0 -2px 8px rgba(0,0,0,0.3);
51
+ display: none;
52
+ }
53
+
54
+ #error-banner.show {
55
+ display: block;
56
+ }
57
+
38
58
  </style>
39
59
  </head>
40
60
  <body>
@@ -47,12 +67,17 @@
47
67
  <label for="labelPos">Place polar wind speed label at TWA:</label>
48
68
  <input type="number" id="labelPos" value="135" min="0" max="180" onchange="updateLabelPos(this.value)">
49
69
  </div>
70
+
71
+ <div id="error-banner"></div>
50
72
  </div>
51
73
 
52
74
  <script>
53
75
 
54
- var polarSpeed, boatSpeed, TWA, TWS
55
76
  var myChart, chartData
77
+ let ws
78
+ let polarSpeed = 0, boatSpeed = 0, TWA = 0, TWS = 0
79
+ let dataReceived = { polar: false, boatSpeed: false, twa: false }
80
+ let dataTimeout
56
81
 
57
82
  // GLOBAL CONFIG: Load from storage or default to 135
58
83
  window.labelTWA = localStorage.getItem('polarLabelTWA') || 135;
@@ -143,41 +168,80 @@ Chart.plugins.register({
143
168
  }
144
169
  });
145
170
 
146
- $.getJSON("/plugins/signalk-polar-performance-plugin/chartData", function(json) {
147
-
148
- // 1. Add actual values dots to the BEGINNING (Indices 0 and 1)
149
- json.datasets.unshift({
150
- label: 'Polar Speed',
151
- backgroundColor: 'rgba(0,255,0,0.7)',
152
- borderColor: 'rgba(0,255,0,0.2)',
153
- borderWidth: 1,
154
- radius: 10,
155
- pointStyle: 'circle',
156
- data: [{ y: 0, x: 0, r: 10 }]
157
- },
158
- {
159
- label: 'Boat Speed',
160
- backgroundColor: 'rgba(0,150,255,0.7)',
161
- borderColor: 'rgba(0,150,255,0.2)',
162
- borderWidth: 1,
163
- radius: 10,
164
- pointStyle: 'circle',
165
- data: [{ y: 0, x: 0, r: 10 }]
166
- })
171
+ $.getJSON("/plugins/signalk-polar-performance-plugin/chartData")
172
+ .done(function(json) {
173
+ if (!json || !json.datasets || json.datasets.length < 3) {
174
+ showError("No polar diagram data available.<br><br>Make sure you have entered a valid polar CSV in the plugin settings.");
175
+ return;
176
+ }
167
177
 
168
- // 2. BACKUP ORIGINAL COLORS
169
- for (var i = 2; i < json.datasets.length; i++) {
178
+ // Add actual values dots (Polar Speed + Boat Speed)
179
+ json.datasets.unshift({
180
+ label: 'Polar Speed',
181
+ backgroundColor: 'rgba(0,255,0,0.7)',
182
+ borderColor: 'rgba(0,255,0,0.2)',
183
+ borderWidth: 1,
184
+ radius: 10,
185
+ pointStyle: 'circle',
186
+ data: [{ y: 0, x: 0, r: 10 }]
187
+ },
188
+ {
189
+ label: 'Boat Speed',
190
+ backgroundColor: 'rgba(0,150,255,0.7)',
191
+ borderColor: 'rgba(0,150,255,0.2)',
192
+ borderWidth: 1,
193
+ radius: 10,
194
+ pointStyle: 'circle',
195
+ data: [{ y: 0, x: 0, r: 10 }]
196
+ });
197
+
198
+ // Backup original colors
199
+ for (var i = 2; i < json.datasets.length; i++) {
170
200
  if (!json.datasets[i].borderColor) {
171
- json.datasets[i].borderColor = 'rgba(100, 100, 100, 0.5)';
201
+ json.datasets[i].borderColor = 'rgba(100, 100, 100, 0.5)';
172
202
  }
173
203
  json.datasets[i]._originalColor = json.datasets[i].borderColor;
174
204
  json.datasets[i].borderWidth = 1;
175
- }
205
+ }
176
206
 
177
- chartData = json
178
- showChart(chartData)
179
- })
207
+ chartData = json;
208
+ showChart(chartData);
209
+ })
210
+ .fail(function(jqXHR, textStatus, errorThrown) {
211
+ let reason = "Unknown error";
212
+
213
+ if (jqXHR.status === 404) {
214
+ reason = "Plugin endpoint not found — is the plugin enabled?";
215
+ } else if (jqXHR.status === 500) {
216
+ reason = "Server error — check plugin configuration (invalid CSV polar?)";
217
+ } else if (textStatus === "parsererror") {
218
+ reason = "Invalid data received from server";
219
+ }
220
+
221
+ showError(`Failed to load polar data.<br><br>Reason: ${reason}`);
222
+ });
180
223
 
224
+ // New error display function
225
+ function showError(message) {
226
+ let banner = document.getElementById('error-banner');
227
+
228
+ if (!banner) {
229
+ // Fallback: create banner dynamically if missing
230
+ banner = document.createElement('div');
231
+ banner.id = 'error-banner';
232
+ document.body.appendChild(banner);
233
+ }
234
+
235
+ banner.innerHTML = `
236
+ ⚠️ ${message}
237
+ &nbsp;&nbsp;
238
+ <button onclick="location.reload()" style="background:white; color:#c33; border:none; padding:4px 10px; border-radius:4px; cursor:pointer;">
239
+ Reload
240
+ </button>
241
+ `;
242
+
243
+ banner.classList.add('show');
244
+ }
181
245
  function showChart (data) {
182
246
  console.log(data)
183
247
  myChart = new Chart("myChart", {
@@ -293,6 +357,11 @@ function startListeners () {
293
357
  }
294
358
 
295
359
  ws.send(JSON.stringify(subscriptionObject));
360
+
361
+ // Start timeout to detect missing data
362
+ dataReceived = { polar: false, boatSpeed: false, twa: false, tws: false };
363
+ clearTimeout(dataTimeout);
364
+ dataTimeout = setTimeout(checkDataReceived, 20000);
296
365
  }
297
366
 
298
367
  function handleData (data) {
@@ -304,18 +373,51 @@ function handleData (data) {
304
373
  if (path == 'performance.polarSpeed') {
305
374
  polarSpeed = roundDec(msToKts(value), 1)
306
375
  chartData.datasets[0].data[0].y = polarSpeed
307
- } else if (path == 'environment.wind.angleTrueWaterDamped') {
376
+ dataReceived.polar = true;
377
+ } else if (path === 'environment.wind.angleTrueWaterDamped') {
308
378
  TWA = roundDec(Math.abs(radToDeg(value)),1)
309
379
  chartData.datasets[0].data[0].x = TWA
310
380
  chartData.datasets[1].data[0].x = TWA
381
+ dataReceived.twa = true;
311
382
  } else if (path == 'performance.boatSpeedDamped') {
312
383
  boatSpeed = roundDec(msToKts(value),1)
313
384
  chartData.datasets[1].data[0].y = boatSpeed
385
+ dataReceived.boatSpeed = true;
314
386
  } else if (path == 'environment.wind.speedTrue') {
315
387
  TWS = msToKts(value);
388
+ dataReceived.tws = true;
316
389
  }
317
390
  }
318
391
 
392
+ function checkDataReceived() {
393
+ let missing = [];
394
+
395
+ if (!dataReceived.polar) missing.push("Polar Speed (performance.polarSpeed)");
396
+ if (!dataReceived.boatSpeed) missing.push("Boat Speed (performance.boatSpeedDamped)");
397
+ if (!dataReceived.twa) missing.push("True Wind Angle (environment.wind.angleTrueWater)");
398
+ if (!dataReceived.tws) missing.push("True Wind Speed (environment.wind.speedTrue)");
399
+
400
+ if (missing.length > 0) {
401
+ showError(`Missing data: ${missing.join(', ')}. Check your instruments and polar settings.`);
402
+ }
403
+ }
404
+
405
+ // Enhanced error display
406
+ function showError(message) {
407
+ const container = document.querySelector('.chart-container');
408
+ container.innerHTML = `
409
+ <div style="padding: 40px 20px; text-align: center; color: #ff7777;">
410
+ <h2 style="color: #ff6666;">⚠️ Cannot display Polar Performance</h2>
411
+ <div style="margin: 25px 0; line-height: 1.6; font-size: 17px;">
412
+ ${message}
413
+ </div>
414
+ <button onclick="location.reload()"
415
+ style="padding: 12px 24px; font-size: 16px; background: #333; color: white; border: 1px solid #666; border-radius: 6px; cursor: pointer;">
416
+ Reload Page
417
+ </button>
418
+ </div>
419
+ `;
420
+ }
319
421
 
320
422
  connect()
321
423