remove current weather scroll canvas and almanac-outlook

This commit is contained in:
Matt Walsh 2022-08-05 14:34:00 -05:00
parent 80958226ce
commit eae3b321c7
4 changed files with 39 additions and 212 deletions

View file

@ -9,7 +9,6 @@ class Almanac extends WeatherDisplay {
// pre-load background images (returns promises) // pre-load background images (returns promises)
this.backgroundImage0 = utils.image.load('images/BackGround3_1.png'); 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) // load all images in parallel (returns promises)
this.moonImages = [ this.moonImages = [
@ -19,32 +18,20 @@ class Almanac extends WeatherDisplay {
utils.image.load('images/2/First-Quarter.gif'), utils.image.load('images/2/First-Quarter.gif'),
]; ];
this.timing.totalScreens = 2; this.timing.totalScreens = 1;
} }
async getData(_weatherParameters) { async getData(_weatherParameters) {
super.getData(_weatherParameters); super.getData(_weatherParameters);
const weatherParameters = _weatherParameters ?? this.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 // get sun/moon data
const { sun, moon } = this.calcSunMoonData(weatherParameters); 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 // store the data
this.data = { this.data = {
sun, sun,
moon, moon,
outlook,
}; };
// update status // update status
this.setStatus(STATUS.loaded); this.setStatus(STATUS.loaded);
@ -127,115 +114,6 @@ class Almanac extends WeatherDisplay {
return { phase: phaseName, date: moonDate }; 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() { async drawCanvas() {
super.drawCanvas(); super.drawCanvas();
const info = this.data; const info = this.data;
@ -246,74 +124,48 @@ class Almanac extends WeatherDisplay {
// extract moon images // extract moon images
const [FullMoonImage, LastMoonImage, NewMoonImage, FirstMoonImage] = await Promise.all(this.moonImages); const [FullMoonImage, LastMoonImage, NewMoonImage, FirstMoonImage] = await Promise.all(this.moonImages);
switch (this.screenIndex) { // sun and moon data
case 1: { this.context.drawImage(await this.backgroundImage0, 0, 0);
this.context.drawImage(await this.backgroundImage1, 0, 0); draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2);
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.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.horizontalGradientSingle(this.context, 0, 90, 52, 399, draw.sideColor1, draw.sideColor2);
draw.horizontalGradientSingle(this.context, 584, 90, 640, 399, 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', 70, 150, 'Sunrise:', 2);
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 320, 220, DateRange, 2, 'center'); 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, 180, ' Sunset:', 2);
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 300, `Temperatures: ${Temperature}`, 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', '#FFFF00', 70, 220, 'Moon Data:', 2);
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.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', '#FFFFFF', 120 + Index * 130, 260, MoonPhase.phase, 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, 390, date, 2, 'center');
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 150, 'Sunrise:', 2); const image = (() => {
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 150, DateTime.fromJSDate(info.sun[0].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); switch (MoonPhase.phase) {
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 150, DateTime.fromJSDate(info.sun[1].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); case 'Full':
return FullMoonImage;
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 70, 180, ' Sunset:', 2); case 'Last':
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 270, 180, DateTime.fromJSDate(info.sun[0].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); return LastMoonImage;
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 450, 180, DateTime.fromJSDate(info.sun[1].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(), 2); case 'New':
return NewMoonImage;
draw.text(this.context, 'Star4000', '24pt', '#FFFF00', 70, 220, 'Moon Data:', 2); case 'First':
default:
info.moon.forEach((MoonPhase, Index) => { return FirstMoonImage;
const date = MoonPhase.date.toLocaleString({ month: 'short', day: 'numeric' }); }
})();
draw.text(this.context, 'Star4000', '24pt', '#FFFFFF', 120 + Index * 130, 260, MoonPhase.phase, 2, 'center'); this.context.drawImage(image, 75 + Index * 130, 270);
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;
}
this.finishDraw(); this.finishDraw();
} }

View file

@ -1,4 +1,4 @@
/* globals draw, navigation, utils */ /* globals navigation, utils */
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const currentWeatherScroll = (() => { const currentWeatherScroll = (() => {
@ -6,23 +6,13 @@ const currentWeatherScroll = (() => {
const degree = String.fromCharCode(176); const degree = String.fromCharCode(176);
// local variables // local variables
let context; // currently active context
let blankDrawArea; // original state of context
let interval; let interval;
let screenIndex = 0; let screenIndex = 0;
// start drawing conditions // start drawing conditions
// reset starts from the first item in the text scroll list // reset starts from the first item in the text scroll list
const start = (_context) => { const start = () => {
// store see if the context is new // 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 // set up the interval if needed
if (!interval) { if (!interval) {
@ -34,18 +24,10 @@ const currentWeatherScroll = (() => {
}; };
const stop = (reset) => { const stop = (reset) => {
cleanLastContext();
if (interval) interval = clearInterval(interval); if (interval) interval = clearInterval(interval);
if (reset) screenIndex = 0; if (reset) screenIndex = 0;
}; };
const cleanLastContext = () => {
if (!context) return;
if (blankDrawArea) context.putImageData(blankDrawArea, 0, 405);
blankDrawArea = undefined;
context = undefined;
};
// increment interval, roll over // increment interval, roll over
const incrementInterval = () => { const incrementInterval = () => {
screenIndex = (screenIndex + 1) % (screens.length); screenIndex = (screenIndex + 1) % (screens.length);
@ -60,9 +42,6 @@ const currentWeatherScroll = (() => {
// nothing to do if there's no data yet // nothing to do if there's no data yet
if (!data) return; if (!data) return;
// clean up any old text
if (context && blankDrawArea) context.putImageData(blankDrawArea, 0, 405);
drawCondition(screens[screenIndex](data)); drawCondition(screens[screenIndex](data));
}; };
@ -108,10 +87,6 @@ const currentWeatherScroll = (() => {
// internal draw function with preset parameters // internal draw function with preset parameters
const drawCondition = (text) => { const drawCondition = (text) => {
if (context) {
draw.text(context, 'Star4000', '24pt', '#ffffff', 70, 430, text, 2);
}
// update all html scroll elements // update all html scroll elements
utils.elem.forEach('.weather-display .scroll .fixed', (elem) => { utils.elem.forEach('.weather-display .scroll .fixed', (elem) => {
elem.innerHTML = text; elem.innerHTML = text;

View file

@ -196,7 +196,7 @@ class WeatherDisplay {
if (OkToDrawLogoImage) this.drawLogoImage(); if (OkToDrawLogoImage) this.drawLogoImage();
if (OkToDrawNoaaImage) this.drawNoaaImage(); if (OkToDrawNoaaImage) this.drawNoaaImage();
if (OkToDrawCurrentConditions) { if (OkToDrawCurrentConditions) {
currentWeatherScroll.start(this.context); currentWeatherScroll.start();
} else { } else {
// cause a reset if the progress screen is displayed // cause a reset if the progress screen is displayed
currentWeatherScroll.stop(this.elemId === 'progress'); currentWeatherScroll.stop(this.elemId === 'progress');

View file

@ -86,7 +86,7 @@
<div class="instructions">Enter your location above to continue</div> <div class="instructions">Enter your location above to continue</div>
</div> </div>
</div> </div>
<div id="progress-html" class="weather-display show"> <div id="progress-html" class="weather-display">
<%- include('partials/progress.ejs') %> <%- include('partials/progress.ejs') %>
</div> </div>
<div id="hourly-html" class="weather-display"> <div id="hourly-html" class="weather-display">