// 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 getExtendedForecast from './extendedforecast.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 [extendedForecast, hourlyForecast] = await Promise.all([ getExtendedForecast(() => this.stillWaiting()), getHourlyForecast(() => this.stillWaiting()), ]); if (extendedForecast === undefined || 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 = { extendedForecast, 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 = {}; fill.date = Day.dayName; fill['wind-dir'] = 'NW'; fill['wind-speed'] = '10 - 15kts'; fill['wave-height'] = '1\''; fill['wave-desc'] = ''; 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(); }; // register display registerDisplay(new MarineForecast(11, 'marine-forecast'));