canvas reference cleanup

This commit is contained in:
Matt Walsh 2022-11-21 21:50:22 -06:00
parent 73bec2d23d
commit 58e11474a9
20 changed files with 26 additions and 460 deletions

View file

@ -5,7 +5,9 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build:css": "sass ./server/styles/scss/style.scss ./server/styles/compiled.css"
"build:css": "sass ./server/styles/scss/style.scss ./server/styles/compiled.css",
"lint": "eslint ./server/scripts/**",
"lint:fix": "eslint --fix ./server/scripts/**"
},
"repository": {
"type": "git",

View file

@ -581,4 +581,3 @@ const RegionalCities = [
lon: -110.9698,
},
];

View file

@ -4,9 +4,7 @@ document.addEventListener('DOMContentLoaded', () => {
});
const index = (() => {
const overrides = {
// '32899, Orlando, Florida, USA': { x: -80.6774, y: 28.6143 },
};
const overrides = {};
const AutoRefreshIntervalMs = 500;
const AutoRefreshTotalIntervalMs = 600000; // 10 min.

View file

@ -5,7 +5,7 @@
// eslint-disable-next-line no-unused-vars
class Almanac extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Almanac', true, true);
super(navId, elemId, 'Almanac', true);
// pre-load background images (returns promises)
this.backgroundImage0 = utils.image.load('images/BackGround3_1.png');

View file

@ -4,7 +4,7 @@
// eslint-disable-next-line no-unused-vars
class CurrentWeather extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Current Conditions', true, true);
super(navId, elemId, 'Current Conditions', true);
// pre-load background image (returns promise)
this.backgroundImage = utils.image.load('images/BackGround1_1.png');
}
@ -134,36 +134,6 @@ class CurrentWeather extends WeatherDisplay {
fill.visibility = data.Visibility + data.VisibilityUnit;
fill.pressure = `${data.Pressure} ${data.PressureDirection}`;
// switch (data.PressureDirection) {
// case 'R':
// // Shadow
// draw.triangle(this.context, '#000000', 552, 302, 542, 312, 562, 312);
// draw.box(this.context, '#000000', 549, 312, 6, 15);
// // Border
// draw.triangle(this.context, '#000000', 550, 300, 540, 310, 560, 310);
// draw.box(this.context, '#000000', 547, 310, 6, 15);
// // Fill
// draw.triangle(this.context, '#FFFF00', 550, 301, 541, 309, 559, 309);
// draw.box(this.context, '#FFFF00', 548, 309, 4, 15);
// break;
// case 'F':
// // Shadow
// draw.triangle(this.context, '#000000', 552, 327, 542, 317, 562, 317);
// draw.box(this.context, '#000000', 549, 302, 6, 15);
// // Border
// draw.triangle(this.context, '#000000', 550, 325, 540, 315, 560, 315);
// draw.box(this.context, '#000000', 547, 300, 6, 15);
// // Fill
// draw.triangle(this.context, '#FFFF00', 550, 324, 541, 314, 559, 314);
// draw.box(this.context, '#FFFF00', 548, 301, 4, 15);
// break;
// default:
// }
if (data.observations.heatIndex.value && data.HeatIndex !== data.Temperature) {
fill['heat-index-label'] = 'Heat Index:';
fill['heat-index'] = data.HeatIndex + String.fromCharCode(176);

View file

@ -6,7 +6,7 @@
// eslint-disable-next-line no-unused-vars
class ExtendedForecast extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Extended Forecast', true, true);
super(navId, elemId, 'Extended Forecast', true);
// set timings
this.timing.totalScreens = 2;

View file

@ -5,7 +5,7 @@
class Hourly extends WeatherDisplay {
constructor(navId, elemId, defaultActive) {
// special height and width for scrolling
super(navId, elemId, 'Hourly Forecast', defaultActive, true);
super(navId, elemId, 'Hourly Forecast', defaultActive);
// set up the timing
this.timing.baseDelay = 20;

View file

@ -4,7 +4,7 @@
// eslint-disable-next-line no-unused-vars
class LatestObservations extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Latest Observations', true, true);
super(navId, elemId, 'Latest Observations', true);
// constants
this.MaximumRegionalStations = 7;

View file

@ -5,7 +5,7 @@
// eslint-disable-next-line no-unused-vars
class LocalForecast extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Local Forecast', true, true);
super(navId, elemId, 'Local Forecast', true);
// set timings
this.timing.baseDelay = 5000;

View file

@ -5,7 +5,7 @@
// eslint-disable-next-line no-unused-vars
class Progress extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, '', false, true);
super(navId, elemId, '', false);
// pre-load background image (returns promise)
this.backgroundImage = utils.image.load('images/BackGround1_1.png');
@ -97,12 +97,7 @@ class Progress extends WeatherDisplay {
const display = navigation.getDisplay(index);
if (display && display.status === STATUS.loaded) {
display.showCanvas(navigation.msg.command.firstFrame);
if (this.canvas) {
this.canvas.style.display = 'none';
}
if (this.isHtml) {
this.elem.classList.remove('show');
}
this.elem.classList.remove('show');
}
}
}

View file

@ -4,7 +4,7 @@
// eslint-disable-next-line no-unused-vars
class Radar extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Local Radar', true, true);
super(navId, elemId, 'Local Radar', true);
// set max images
this.dopplerRadarImageMax = 6;

View file

@ -6,7 +6,7 @@
// eslint-disable-next-line no-unused-vars
class RegionalForecast extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Regional Forecast', true, true);
super(navId, elemId, 'Regional Forecast', true);
// timings
this.timing.totalScreens = 3;
@ -102,7 +102,7 @@ class RegionalForecast extends WeatherDisplay {
RegionalForecast.buildForecast(forecast.properties.periods[2], city, cityXY),
];
} catch (e) {
console.log(`No regional forecast data for '${city.name}'`);
console.log(`No regional forecast data for '${city.name ?? city.city}'`);
console.log(e);
return false;
}
@ -149,11 +149,12 @@ class RegionalForecast extends WeatherDisplay {
// get the observation data
const observation = await utils.fetch.json(`${station}/observations/latest`);
// preload the image
if (!observation.properties.icon) return false;
utils.image.preload(icons.getWeatherRegionalIconFromIconLink(observation.properties.icon, !observation.properties.daytime));
// return the observation
return observation.properties;
} catch (e) {
console.log(`Unable to get regional observations for ${city.Name}`);
console.log(`Unable to get regional observations for ${city.Name ?? city.city}`);
console.error(e.status, e.responseJSON);
return false;
}

View file

@ -5,7 +5,7 @@
class TravelForecast extends WeatherDisplay {
constructor(navId, elemId, defaultActive) {
// special height and width for scrolling
super(navId, elemId, 'Travel Forecast', defaultActive, true);
super(navId, elemId, 'Travel Forecast', defaultActive);
// set up the timing
this.timing.baseDelay = 20;

View file

@ -1,6 +1,5 @@
// radar utilities
/* globals SuperGif */
// eslint-disable-next-line no-unused-vars
const utils = (() => {
// ****************************** weather data ********************************
@ -30,12 +29,6 @@ const utils = (() => {
}
});
// async version of SuperGif
const superGifAsync = (e) => new Promise((resolve) => {
const gif = new SuperGif(e);
gif.load(() => resolve(gif));
});
// preload an image
// the goal is to get it in the browser's cache so it is available more quickly when the browser needs it
// a list of cached icons is used to avoid hitting the cache multiple times
@ -47,22 +40,6 @@ const utils = (() => {
return true;
};
// draw an image on a local canvas and return the context
const drawLocalCanvas = (img) => {
// create a canvas
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
// get the context
const context = canvas.getContext('2d');
context.imageSmoothingEnabled = false;
// draw the image
context.drawImage(img, 0, 0);
return context;
};
// *********************************** unit conversions ***********************
Math.round2 = (value, decimals) => Number(`${Math.round(`${value}e${decimals}`)}e-${decimals}`);
@ -218,9 +195,7 @@ const utils = (() => {
},
image: {
load: loadImg,
superGifAsync,
preload,
drawLocalCanvas,
},
weather: {
getPoint,

View file

@ -12,7 +12,7 @@ const STATUS = {
// eslint-disable-next-line no-unused-vars
class WeatherDisplay {
constructor(navId, elemId, name, defaultEnabled, isHtml) {
constructor(navId, elemId, name, defaultEnabled) {
// navId is used in messaging
this.navId = navId;
this.elemId = undefined;
@ -21,7 +21,6 @@ class WeatherDisplay {
this.loadingStatus = STATUS.loading;
this.name = name ?? elemId;
this.getDataCallbacks = [];
this.isHtml = isHtml;
// default navigation timing
this.timing = {
@ -32,8 +31,8 @@ class WeatherDisplay {
this.navBaseCount = 0;
this.screenIndex = -1; // special starting condition
// create the canvas, also stores this.elemId
this.createCanvas(elemId);
// store elemId once
this.storeElemId(elemId);
if (elemId !== 'progress') this.addCheckbox(defaultEnabled);
if (this.enabled) {
@ -96,21 +95,10 @@ class WeatherDisplay {
this.loadingStatus = state;
}
createCanvas(elemId, width = 640, height = 480) {
storeElemId(elemId) {
// only create it once
if (this.elemId) return;
this.elemId = elemId;
// no additional work if this is HTML
if (this.isHtml) return;
// create a canvas
const canvas = document.createElement('template');
canvas.innerHTML = `<canvas id='${`${elemId}Canvas`}' width='${width}' height='${height}' style='display: none;' />`;
// add to the page
const container = document.getElementById('container');
container.appendChild(canvas.content.firstChild);
}
// get necessary data for this display
@ -143,47 +131,27 @@ class WeatherDisplay {
}
drawCanvas() {
if (!this.isHtml) {
// stop all gifs
this.gifs.forEach((gif) => gif.pause());
// delete the gifs
this.gifs.length = 0;
// refresh the canvas
this.canvas = document.getElementById(`${this.elemId}Canvas`);
this.context = this.canvas.getContext('2d');
}
// clean up the first-run flag in screen index
if (this.screenIndex < 0) this.screenIndex = 0;
}
finishDraw() {
let OkToDrawCurrentConditions = true;
let OkToDrawNoaaImage = true;
let OkToDrawCurrentDateTime = true;
let OkToDrawLogoImage = true;
// let OkToDrawCustomScrollText = false;
let bottom;
// visibility tests
// if (_ScrollText !== '') OkToDrawCustomScrollText = true;
if (this.elemId === 'almanac') OkToDrawNoaaImage = false;
if (this.elemId === 'travelForecast') OkToDrawNoaaImage = false;
if (this.elemId === 'regionalForecast') OkToDrawNoaaImage = false;
if (this.elemId === 'progress') {
OkToDrawCurrentConditions = false;
OkToDrawNoaaImage = false;
}
if (this.elemId === 'radar') {
OkToDrawCurrentConditions = false;
OkToDrawCurrentDateTime = false;
OkToDrawNoaaImage = false;
// OkToDrawCustomScrollText = false;
}
if (this.elemId === 'hazards') {
OkToDrawNoaaImage = false;
bottom = true;
OkToDrawLogoImage = false;
}
// draw functions
if (OkToDrawCurrentDateTime) {
@ -193,8 +161,6 @@ class WeatherDisplay {
setInterval(() => this.drawCurrentDateTime(bottom), 100);
}
}
if (OkToDrawLogoImage) this.drawLogoImage();
if (OkToDrawNoaaImage) this.drawNoaaImage();
if (OkToDrawCurrentConditions) {
currentWeatherScroll.start();
} else {
@ -228,28 +194,6 @@ class WeatherDisplay {
this.lastDate = date;
}
async drawNoaaImage() {
if (this.isHtml) return;
// load the image and store locally
if (!this.drawNoaaImage.image) {
this.drawNoaaImage.image = utils.image.load('images/noaa5.gif');
}
// wait for the image to load completely
const img = await this.drawNoaaImage.image;
this.context.drawImage(img, 356, 39);
}
async drawLogoImage() {
if (this.isHtml) return;
// load the image and store locally
if (!this.drawLogoImage.image) {
this.drawLogoImage.image = utils.image.load('images/Logo3.png');
}
// wait for the image load completely
const img = await this.drawLogoImage.image;
this.context.drawImage(img, 50, 30, 85, 67);
}
// show/hide the canvas and start/stop the navigation timer
showCanvas(navCmd) {
// reset timing if enabled
@ -259,30 +203,15 @@ class WeatherDisplay {
this.startNavCount();
if (!this.isHtml) {
// see if the canvas is already showing
if (this.canvas.style.display === 'block') return;
// show the canvas
this.canvas.style.display = 'block';
} else {
this.elem.classList.add('show');
}
this.elem.classList.add('show');
}
hideCanvas() {
this.resetNavBaseCount();
if (this.canvas) {
this.canvas.style.display = 'none';
}
if (this.isHtml) {
this.elem.classList.remove('show');
}
this.elem.classList.remove('show');
}
isActive() {
if (!this.isHtml) return document.getElementById(`${this.elemId}Canvas`).offsetParent !== null;
return this.elem.offsetHeight !== 0;
}

View file

@ -1,288 +0,0 @@
var GetWeatherHazards3 = function (WeatherParameters) {
var ZoneId = WeatherParameters.ZoneId;
var HazardUrls = [];
var HazardCounter = 0;
WeatherParameters.WeatherHazardConditions =
{
ZoneId: WeatherParameters.ZoneId,
Hazards: [],
};
var Url = 'https://alerts.weather.gov/cap/wwaatmget.php?x=' + ZoneId + '&y=0';
// Load the xml file using ajax
$.ajaxCORS({
type: 'GET',
url: Url,
dataType: 'text',
crossDomain: true,
cache: false,
success: function (text) {
// IE doesn't support XML tags with colons.
text = text.replaceAll('<cap:', '<cap_');
text = text.replaceAll('</cap:', '</cap_');
var $xml = $(text);
//console.log(xml);
$xml.find('entry').each(function () {
var entry = $(this);
// Skip non-alerts.
var cap_msgType = entry.find('cap_msgType');
if (cap_msgType.text() !== 'Alert') {
return true;
}
var link = entry.find('link');
var Url = link.attr('href');
HazardUrls.push(Url);
});
if (HazardUrls.length === 0) {
PopulateHazardConditions(WeatherParameters);
console.log(WeatherParameters.WeatherHazardConditions);
return;
}
$(HazardUrls).each(function () {
var Url = this.toString();
$.ajaxCORS({
type: 'GET',
url: Url,
dataType: 'xml',
crossDomain: true,
cache: true,
success: function (xml) {
var $xml = $(xml);
console.log(xml);
var description = $xml.find('description');
WeatherParameters.WeatherHazardConditions.Hazards.push(description.text());
HazardCounter++;
if (HazardCounter === HazardUrls.length) {
PopulateHazardConditions(WeatherParameters);
console.log(WeatherParameters.WeatherHazardConditions);
}
},
error: function () {
console.error('GetWeatherHazards3 failed for Url: ' + Url);
WeatherParameters.Progress.Hazards = LoadStatuses.Failed;
},
});
});
},
error: function (xhr, error, errorThrown) {
console.error('GetWeatherHazards3 failed: ' + errorThrown);
WeatherParameters.Progress.Hazards = LoadStatuses.Failed;
},
});
};
var canvasProgress_mousemove = function (e) {
canvasProgress.css('cursor', '');
var RatioX = canvasProgress.width() / 640;
var RatioY = canvasProgress.height() / 480;
if (e.offsetX >= (70 * RatioX) && e.offsetX <= (565 * RatioX)) {
//if (e.offsetY >= (105 * RatioY) && e.offsetY <= (350 * RatioY))
if (e.offsetY >= (100 * RatioY) && e.offsetY <= (385 * RatioY)) {
// Show hand cursor.
canvasProgress.css('cursor', 'pointer');
}
}
};
var PopulateHazardConditions = function (WeatherParameters) {
if (WeatherParameters === null || (_DontLoadGifs && WeatherParameters.Progress.Hazards !== LoadStatuses.Loaded)) {
return;
}
var WeatherHazardConditions = WeatherParameters.WeatherHazardConditions;
var ZoneId = WeatherHazardConditions.ZoneId;
var Text;
var Line;
var SkipLine;
var DontLoadGifs = _DontLoadGifs;
divHazards.empty();
$(WeatherHazardConditions.Hazards).each(function () {
//Text = this.replaceAll("\n", "<br/>");
//divHazards.html(divHazards.html() + "<br/><br/>" + Text);
Text = this.toString();
SkipLine = false;
Text = Text.replaceAll('\n', ' ');
//Text = Text.replaceAll("*** ", "");
//$(Text.split("\n")).each(function ()
$(Text.split(' ')).each(function () {
Line = this.toString();
Line = Line.toUpperCase();
if (Line.startsWith('&&')) {
return false;
} else if (Line.startsWith('$$')) {
return false;
}
if (SkipLine) {
if (Line === '') {
SkipLine = false;
return true;
}
return true;
}
if (Line.startsWith(ZoneId)) {
SkipLine = true;
return true;
} else if (Line.indexOf('>') !== -1) {
SkipLine = true;
return true;
} else if (Line.indexOf('LAT...LON ') !== -1) {
SkipLine = true;
return true;
}
//divHazards.html(divHazards.html() + "<br/>" + Line);
if (Line.indexOf('.') === 0 || Line.indexOf('*') === 0) {
divHazards.html(divHazards.html() + '<br/><br/>');
if (Line.indexOf('.') === 0 && Line.indexOf('...') !== 0) {
Line = Line.substr(1);
}
}
divHazards.html(divHazards.html() + Line + ' ');
});
divHazards.html(divHazards.html() + '<br/><br/>');
});
var DrawHazards = function () {
// Draw canvas
var canvas = canvasHazards[0];
var context = canvas.getContext('2d');
var BackGroundImage = new Image();
BackGroundImage.onload = function () {
context.drawImage(BackGroundImage, 0, 0);
if (DontLoadGifs) {
UpdateHazards();
}
if (WeatherHazardConditions.Hazards.length > 0) {
WeatherParameters.Progress.Hazards = LoadStatuses.Loaded;
} else {
WeatherParameters.Progress.Hazards = LoadStatuses.NoData;
}
UpdateWeatherCanvas(WeatherParameters, canvasHazards);
};
BackGroundImage.src = 'images/BackGround7.png';
};
var HazardsText = divHazards.html();
HazardsText = HazardsText.replaceAll('<br>', '\n');
HazardsText = HazardsText.replaceAll('<br/>', '\n');
HazardsText = HazardsText.replaceAll('<br />', '\n');
HazardsText = HazardsText.replaceAll('<br></br>', '\n');
WeatherHazardConditions.HazardsText = HazardsText;
WeatherHazardConditions.HazardsTextC = ConvertConditionsToMetric(HazardsText);
if (_Units === Units.Metric) {
HazardsText = WeatherHazardConditions.HazardsTextC;
}
var HazardsWrapped = HazardsText.wordWrap(32);
var cnvHazardsScroll;
var ShowHazardsScroll = function () {
var cnvHazardsScrollId;
var context;
cnvHazardsScrollId = 'cnvHazardsScroll';
var HazardsWrappedLines = HazardsWrapped.split('\n');
var MaxHazardsWrappedLines = 365;
if (_OperatingSystem === OperatingSystems.Andriod) {
MaxHazardsWrappedLines = 92;
}
if (HazardsWrappedLines.length > MaxHazardsWrappedLines) {
HazardsWrappedLines = HazardsWrappedLines.splice(0, MaxHazardsWrappedLines - 1);
}
var height = 0 + (HazardsWrappedLines.length * 45);
if (DontLoadGifs === false) {
// Clear the current image.
divHazardsScroll.empty();
divHazardsScroll.html('<canvas id=\'' + cnvHazardsScrollId + '\' />');
cnvHazardsScroll = $('#' + cnvHazardsScrollId);
cnvHazardsScroll.attr('width', '640'); // For Chrome.
cnvHazardsScroll.attr('height', height); // For Chrome.
}
cnvHazardsScroll = $('#' + cnvHazardsScrollId);
context = cnvHazardsScroll[0].getContext('2d');
DrawBox(context, 'rgb(112, 35, 35)', 0, 0, 640, height);
//var y = 0;
var y = 45;
$(HazardsWrappedLines).each(function () {
var HazardLine = this.toString();
DrawText(context, 'Star4000', '24pt', '#FFFFFF', 80, y, HazardLine, 1);
y += 45;
});
DrawHazards();
};
ShowHazardsScroll();
};
var UpdateHazards = function (Offset) {
var canvas = canvasHazards[0];
var context = canvas.getContext('2d');
var cnvHazardsScroll = $('#cnvHazardsScroll');
switch (Offset) {
case undefined:
break;
case 0:
_UpdateHazardsY = 0;
break;
case Infinity:
_UpdateHazardsY = cnvHazardsScroll.height();
break;
default:
_UpdateHazardsY += (385 * Offset);
if (_UpdateHazardsY > cnvHazardsScroll.height()) {
_UpdateHazardsY = cnvHazardsScroll.height();
} else if (_UpdateHazardsY < 0) {
_UpdateHazardsY = 0;
}
break;
}
DrawBox(context, 'rgb(112, 35,35)', 0, 0, 640, 385);
context.drawImage(cnvHazardsScroll[0], 0, _UpdateHazardsY, 640, 385, 0, 0, 640, 385);
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -26,7 +26,6 @@
<script type="text/javascript" src="scripts/vendor/jquery.autocomplete.min.js"></script>
<script type="text/javascript" src="scripts/vendor/auto/nosleep.js"></script>
<script type="text/javascript" src="scripts/vendor/auto/swiped-events.js"></script>
<script type="text/javascript" src="scripts/vendor/jquery.touchswipe.min.js"></script>
<script type="text/javascript" src="scripts/index.js"></script>
<script type="text/javascript" src="scripts/data/states.js"></script>