diff --git a/server/scripts/modules/almanac.js b/server/scripts/modules/almanac.js index 3bc80ee..b014782 100644 --- a/server/scripts/modules/almanac.js +++ b/server/scripts/modules/almanac.js @@ -9,7 +9,6 @@ class Almanac extends WeatherDisplay { // pre-load background images (returns promises) this.backgroundImage0 = utils.image.load('images/BackGround3_1.png'); - this.backgroundImage1 = utils.image.load('images/BackGround1_1.png'); // load all images in parallel (returns promises) this.moonImages = [ @@ -19,32 +18,20 @@ class Almanac extends WeatherDisplay { utils.image.load('images/2/First-Quarter.gif'), ]; - this.timing.totalScreens = 2; + this.timing.totalScreens = 1; } async getData(_weatherParameters) { super.getData(_weatherParameters); const weatherParameters = _weatherParameters ?? this.weatherParameters; - // get images for outlook - const imagePromises = [ - utils.image.load('https://www.cpc.ncep.noaa.gov/products/predictions/30day/off14_temp.gif', true), - utils.image.load('https://www.cpc.ncep.noaa.gov/products/predictions/30day/off14_prcp.gif', true), - ]; - // get sun/moon data const { sun, moon } = this.calcSunMoonData(weatherParameters); - // process images for outlook - const [outlookTemp, outlookPrecip] = await Promise.all(imagePromises); - - const outlook = Almanac.parseOutlooks(weatherParameters.latitude, weatherParameters.longitude, outlookTemp, outlookPrecip); - // store the data this.data = { sun, moon, - outlook, }; // update status this.setStatus(STATUS.loaded); @@ -127,115 +114,6 @@ class Almanac extends WeatherDisplay { return { phase: phaseName, date: moonDate }; } - // use the color of the pixel to determine the outlook - static parseOutlooks(lat, lon, temp, precip) { - const { DateTime } = luxon; - const month = DateTime.local(); - const thisMonth = month.toLocaleString({ month: 'short' }); - const nextMonth = month.plus({ months: 1 }).toLocaleString({ month: 'short' }); - - // draw the images on the canvases - const tempContext = utils.image.drawLocalCanvas(temp); - const precipContext = utils.image.drawLocalCanvas(precip); - - // get the color from each canvas - const tempColor = Almanac.getOutlookColor(lat, lon, tempContext); - const precipColor = Almanac.getOutlookColor(lat, lon, precipContext); - - return { - thisMonth, - nextMonth, - temperature: Almanac.getOutlookTemperatureIndicator(tempColor), - precipitation: Almanac.getOutlookPrecipitationIndicator(precipColor), - }; - } - - static getOutlookColor(lat, lon, context) { - let x = 0; - let y = 0; - - // The height is in the range of latitude 75'N (top) - 15'N (bottom) - y = ((75 - lat) / 53) * 707; - - if (lat < 48.83) { - y -= Math.abs(48.83 - lat) * 2.9; - } - if (lon < -100.46) { - y -= Math.abs(-100.46 - lon) * 1.7; - } else { - y -= Math.abs(-100.46 - lon) * 1.7; - } - - // The width is in the range of the longitude ??? - x = ((-155 - lon) / -110) * 719; // -155 - -40 - - if (lon < -100.46) { - x -= Math.abs(-100.46 - lon) * 1; - - if (lat > 40) { - x += Math.abs(40 - lat) * 4; - } else { - x -= Math.abs(40 - lat) * 4; - } - } else { - x += Math.abs(-100.46 - lon) * 2; - - if (lat < 36 && lon > -90) { - x += Math.abs(36 - lat) * 8; - } else { - x -= Math.abs(36 - lat) * 6; - } - } - - // The further left and right from lat 45 and lon -97 the y increases - x = Math.round(x); - y = Math.round(y); - - // Determine if there is any "non-white" colors around the area. - // Search a 16x16 region. - for (let colorX = x - 8; colorX <= x + 8; colorX += 1) { - for (let colorY = y - 8; colorY <= y + 8; colorY += 1) { - const pixelColor = Almanac.getPixelColor(context, colorX, colorY); - if ((pixelColor.r !== 0 && pixelColor.g !== 0 && pixelColor.b !== 0) - || (pixelColor.r !== 255 && pixelColor.g !== 255 && pixelColor.b !== 255)) { - return pixelColor; - } - } - } - - return false; - } - - // get rgb values of a pixel - static getPixelColor(context, x, y) { - const pixelData = context.getImageData(x, y, 1, 1).data; - return { - r: pixelData[0], - g: pixelData[1], - b: pixelData[2], - }; - } - - // get temperature outlook from color - static getOutlookTemperatureIndicator(pixelColor) { - if (pixelColor.b > pixelColor.r) { - return 'Below Normal'; - } if (pixelColor.r > pixelColor.b) { - return 'Above Normal'; - } - return 'Normal'; - } - - // get precipitation outlook from color - static getOutlookPrecipitationIndicator(pixelColor) { - if (pixelColor.g > pixelColor.r) { - return 'Above Normal'; - } if (pixelColor.r > pixelColor.g) { - return 'Below Normal'; - } - return 'Normal'; - } - async drawCanvas() { super.drawCanvas(); const info = this.data; @@ -246,74 +124,48 @@ class Almanac extends WeatherDisplay { // extract moon images const [FullMoonImage, LastMoonImage, NewMoonImage, FirstMoonImage] = await Promise.all(this.moonImages); - switch (this.screenIndex) { - case 1: { - this.context.drawImage(await this.backgroundImage1, 0, 0); - draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2); - draw.triangle(this.context, 'rgb(28, 10, 87)', 500, 30, 450, 90, 500, 90); - draw.horizontalGradientSingle(this.context, 0, 90, 52, 399, draw.sideColor1, draw.sideColor2); - draw.horizontalGradientSingle(this.context, 584, 90, 640, 399, draw.sideColor1, draw.sideColor2); + // sun and moon data + this.context.drawImage(await this.backgroundImage0, 0, 0); + draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2); + draw.triangle(this.context, 'rgb(28, 10, 87)', 500, 30, 450, 90, 500, 90); + draw.horizontalGradientSingle(this.context, 0, 90, 640, 190, draw.sideColor1, draw.sideColor2); - draw.titleText(this.context, 'Almanac', 'Outlook'); + draw.titleText(this.context, 'Almanac', 'Astronomical'); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 320, 180, '30 Day Outlook', 2, 'center'); + draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 320, 120, Today.toLocaleString({ weekday: 'long' }), 2, 'center'); + draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 500, 120, Tomorrow.toLocaleString({ weekday: 'long' }), 2, 'center'); - const DateRange = `MID-${info.outlook.thisMonth.toUpperCase()} TO MID-${info.outlook.nextMonth.toUpperCase()}`; - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 320, 220, DateRange, 2, 'center'); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 150, 'Sunrise:', 2); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 150, DateTime.fromJSDate(info.sun[0].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 150, DateTime.fromJSDate(info.sun[1].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - const Temperature = info.outlook.temperature; - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 300, `Temperatures: ${Temperature}`, 2); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 180, ' Sunset:', 2); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 180, DateTime.fromJSDate(info.sun[0].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 180, DateTime.fromJSDate(info.sun[1].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - const Precipitation = info.outlook.precipitation; - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 380, `Precipitation: ${Precipitation}`, 2); - break; - } - case 0: - default: - // sun and moon data - this.context.drawImage(await this.backgroundImage0, 0, 0); - draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2); - draw.triangle(this.context, 'rgb(28, 10, 87)', 500, 30, 450, 90, 500, 90); - draw.horizontalGradientSingle(this.context, 0, 90, 640, 190, draw.sideColor1, draw.sideColor2); + draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 70, 220, 'Moon Data:', 2); - draw.titleText(this.context, 'Almanac', 'Astronomical'); + info.moon.forEach((MoonPhase, Index) => { + const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' }); - draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 320, 120, Today.toLocaleString({ weekday: 'long' }), 2, 'center'); - draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 500, 120, Tomorrow.toLocaleString({ weekday: 'long' }), 2, 'center'); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 120 + Index * 130, 260, MoonPhase.phase, 2, 'center'); + draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 120 + Index * 130, 390, date, 2, 'center'); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 150, 'Sunrise:', 2); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 150, DateTime.fromJSDate(info.sun[0].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 150, DateTime.fromJSDate(info.sun[1].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 180, ' Sunset:', 2); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 180, DateTime.fromJSDate(info.sun[0].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 180, DateTime.fromJSDate(info.sun[1].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); - - draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 70, 220, 'Moon Data:', 2); - - info.moon.forEach((MoonPhase, Index) => { - const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' }); - - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 120 + Index * 130, 260, MoonPhase.phase, 2, 'center'); - draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 120 + Index * 130, 390, date, 2, 'center'); - - const image = (() => { - switch (MoonPhase.phase) { - case 'Full': - return FullMoonImage; - case 'Last': - return LastMoonImage; - case 'New': - return NewMoonImage; - case 'First': - default: - return FirstMoonImage; - } - })(); - this.context.drawImage(image, 75 + Index * 130, 270); - }); - break; - } + const image = (() => { + switch (MoonPhase.phase) { + case 'Full': + return FullMoonImage; + case 'Last': + return LastMoonImage; + case 'New': + return NewMoonImage; + case 'First': + default: + return FirstMoonImage; + } + })(); + this.context.drawImage(image, 75 + Index * 130, 270); + }); this.finishDraw(); } diff --git a/server/scripts/modules/currentweatherscroll.js b/server/scripts/modules/currentweatherscroll.js index 195e006..5ac9042 100644 --- a/server/scripts/modules/currentweatherscroll.js +++ b/server/scripts/modules/currentweatherscroll.js @@ -1,4 +1,4 @@ -/* globals draw, navigation, utils */ +/* globals navigation, utils */ // eslint-disable-next-line no-unused-vars const currentWeatherScroll = (() => { @@ -6,23 +6,13 @@ const currentWeatherScroll = (() => { const degree = String.fromCharCode(176); // local variables - let context; // currently active context - let blankDrawArea; // original state of context let interval; let screenIndex = 0; // start drawing conditions // reset starts from the first item in the text scroll list - const start = (_context) => { + const start = () => { // store see if the context is new - if (context && _context !== context) { - // clean the outgoing context - cleanLastContext(); - // store the new blank context - blankDrawArea = _context.getImageData(0, 405, 640, 75); - } - // store the context locally - context = _context; // set up the interval if needed if (!interval) { @@ -34,18 +24,10 @@ const currentWeatherScroll = (() => { }; const stop = (reset) => { - cleanLastContext(); if (interval) interval = clearInterval(interval); if (reset) screenIndex = 0; }; - const cleanLastContext = () => { - if (!context) return; - if (blankDrawArea) context.putImageData(blankDrawArea, 0, 405); - blankDrawArea = undefined; - context = undefined; - }; - // increment interval, roll over const incrementInterval = () => { screenIndex = (screenIndex + 1) % (screens.length); @@ -60,9 +42,6 @@ const currentWeatherScroll = (() => { // nothing to do if there's no data yet if (!data) return; - // clean up any old text - if (context && blankDrawArea) context.putImageData(blankDrawArea, 0, 405); - drawCondition(screens[screenIndex](data)); }; @@ -108,10 +87,6 @@ const currentWeatherScroll = (() => { // internal draw function with preset parameters const drawCondition = (text) => { - if (context) { - draw.text(context, 'Star4000', '24pt', '#ffffff', 70, 430, text, 2); - } - // update all html scroll elements utils.elem.forEach('.weather-display .scroll .fixed', (elem) => { elem.innerHTML = text; diff --git a/server/scripts/modules/weatherdisplay.js b/server/scripts/modules/weatherdisplay.js index fbc2d7b..a608128 100644 --- a/server/scripts/modules/weatherdisplay.js +++ b/server/scripts/modules/weatherdisplay.js @@ -196,7 +196,7 @@ class WeatherDisplay { if (OkToDrawLogoImage) this.drawLogoImage(); if (OkToDrawNoaaImage) this.drawNoaaImage(); if (OkToDrawCurrentConditions) { - currentWeatherScroll.start(this.context); + currentWeatherScroll.start(); } else { // cause a reset if the progress screen is displayed currentWeatherScroll.stop(this.elemId === 'progress'); diff --git a/views/index.ejs b/views/index.ejs index 3a66405..736bcc3 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -86,7 +86,7 @@