mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-17 00:59:29 -07:00
140 lines
3.3 KiB
JavaScript
140 lines
3.3 KiB
JavaScript
// display extended forecast graphically
|
|
// technically uses the same data as the local forecast, we'll let the browser do the caching of that
|
|
|
|
import STATUS from './status.mjs';
|
|
import WeatherDisplay from './weatherdisplay.mjs';
|
|
import { registerDisplay } from './navigation.mjs';
|
|
import getHourlyForecast from './hourly.mjs';
|
|
|
|
class MarineForecast extends WeatherDisplay {
|
|
constructor(navId, elemId) {
|
|
super(navId, elemId, 'Marine Forecast', false);
|
|
// this.showOnProgress = false;
|
|
|
|
// set timings
|
|
this.timing.totalScreens = 1;
|
|
}
|
|
|
|
async getData() {
|
|
if (!super.getData()) return;
|
|
|
|
const hourlyForecast = await getHourlyForecast(() => this.stillWaiting());
|
|
if (hourlyForecast === undefined) {
|
|
this.setStatus(STATUS.failed);
|
|
return;
|
|
}
|
|
|
|
// test for all wave heights = 0, no data for wave heights
|
|
if (hourlyForecast.every((value) => !value.waveHeight)) {
|
|
// total screens = 0 to skip this display
|
|
this.totalScreens = 0;
|
|
this.setStatus(STATUS.noData);
|
|
return;
|
|
}
|
|
|
|
this.data = hourlyForecast;
|
|
this.screenIndex = 0;
|
|
this.setStatus(STATUS.loaded);
|
|
}
|
|
|
|
async drawCanvas() {
|
|
super.drawCanvas();
|
|
|
|
// determine bounds
|
|
// grab the first three or second set of three array elements
|
|
const forecast = this.data.slice(0, 2);
|
|
|
|
// create each day template
|
|
const days = forecast.map((Day) => {
|
|
const fill = {};
|
|
const waveHeight = Math.round(Day.waveHeight * 3.281);
|
|
fill.date = Day.dayName;
|
|
fill['wind-dir'] = Day.windDirection;
|
|
fill['wind-speed'] = '10 - 15kts';
|
|
fill['wave-height'] = `${waveHeight}'`;
|
|
fill['wave-desc'] = waveDesc(waveHeight);
|
|
|
|
const { low } = Day;
|
|
if (low !== undefined) {
|
|
fill['value-lo'] = Math.round(low);
|
|
}
|
|
const { high } = Day;
|
|
fill['value-hi'] = Math.round(high);
|
|
fill.condition = Day.text;
|
|
|
|
// draw the icon
|
|
fill['wave-icon'] = { type: 'img', src: waveImage('') };
|
|
|
|
// return the filled template
|
|
return this.fillTemplate('day', fill);
|
|
});
|
|
|
|
// empty and update the container
|
|
const dayContainer = this.elem.querySelector('.day-container');
|
|
dayContainer.innerHTML = '';
|
|
dayContainer.append(...days);
|
|
this.finishDraw();
|
|
}
|
|
}
|
|
|
|
const waveImage = (conditions) => {
|
|
const color = 'rgb(172, 165, 251)';
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = 150;
|
|
canvas.height = 20;
|
|
const context = canvas.getContext('2d');
|
|
context.imageSmoothingEnabled = false;
|
|
|
|
let y = 0;
|
|
let r = 35;
|
|
let arc1 = Math.PI * 0.3;
|
|
let arc2 = Math.PI * 0.7;
|
|
|
|
switch (conditions) {
|
|
case 'CHOPPY':
|
|
y = -10;
|
|
arc1 = Math.PI * 0.2;
|
|
arc2 = Math.PI * 0.8;
|
|
r = 25;
|
|
break;
|
|
|
|
case 'ROUGH':
|
|
y = -5;
|
|
arc1 = Math.PI * 0.1;
|
|
arc2 = Math.PI * 0.9;
|
|
r = 20;
|
|
break;
|
|
|
|
case 'LIGHT':
|
|
default:
|
|
y = -20;
|
|
arc1 = Math.PI * 0.3;
|
|
arc2 = Math.PI * 0.7;
|
|
r = 35;
|
|
break;
|
|
}
|
|
|
|
context.beginPath();
|
|
context.arc(35, y, r, arc1, arc2);
|
|
context.strokeStyle = color;
|
|
context.lineWidth = 4;
|
|
context.stroke();
|
|
context.beginPath();
|
|
context.arc(75, y, r, arc1, arc2);
|
|
context.stroke();
|
|
context.beginPath();
|
|
context.arc(115, y, r, arc1, arc2);
|
|
context.stroke();
|
|
|
|
return canvas.toDataURL();
|
|
};
|
|
|
|
const waveDesc = (waveHeight) => {
|
|
if (waveHeight > 7) return 'ROUGH';
|
|
if (waveHeight > 4) return 'CHOPPY';
|
|
return 'LIGHT';
|
|
};
|
|
|
|
// register display
|
|
registerDisplay(new MarineForecast(11, 'marine-forecast'));
|