From 3f5cd4ca7014f84e989133141a1dd1548ed0ee89 Mon Sep 17 00:00:00 2001 From: Matt Walsh Date: Fri, 9 Dec 2022 13:50:17 -0600 Subject: [PATCH] class static code cleanup --- server/scripts/modules/almanac.mjs | 30 +-- server/scripts/modules/currentweather.mjs | 41 ++-- server/scripts/modules/extendedforecast.mjs | 170 +++++++------- server/scripts/modules/hourly.mjs | 135 +++++------ server/scripts/modules/latestobservations.mjs | 39 ++-- server/scripts/modules/localforecast.mjs | 19 +- server/scripts/modules/radar-utils.mjs | 185 +++++++++++++++ server/scripts/modules/radar.mjs | 188 +--------------- .../modules/regionalforecast-utils.mjs | 205 +++++++++++++++++ server/scripts/modules/regionalforecast.mjs | 212 +----------------- server/scripts/modules/travelforecast.mjs | 27 ++- server/styles/main.css | 2 +- server/styles/main.css.map | 2 +- server/styles/scss/_page.scss | 5 +- 14 files changed, 631 insertions(+), 629 deletions(-) create mode 100644 server/scripts/modules/radar-utils.mjs create mode 100644 server/scripts/modules/regionalforecast-utils.mjs diff --git a/server/scripts/modules/almanac.mjs b/server/scripts/modules/almanac.mjs index f7e2c11..8366908 100644 --- a/server/scripts/modules/almanac.mjs +++ b/server/scripts/modules/almanac.mjs @@ -133,7 +133,7 @@ class Almanac extends WeatherDisplay { fill.date = date; fill.type = MoonPhase.phase; - fill.icon = { type: 'img', src: Almanac.imageName(MoonPhase.Phase) }; + fill.icon = { type: 'img', src: imageName(MoonPhase.Phase) }; return this.fillTemplate('day', fill); }); @@ -145,20 +145,6 @@ class Almanac extends WeatherDisplay { this.finishDraw(); } - static imageName(type) { - switch (type) { - case 'Full': - return 'images/2/Full-Moon.gif'; - case 'Last': - return 'images/2/Last-Quarter.gif'; - case 'New': - return 'images/2/New-Moon.gif'; - case 'First': - default: - return 'images/2/First-Quarter.gif'; - } - } - // make sun and moon data available outside this class // promise allows for data to be requested before it is available async getSun() { @@ -170,6 +156,20 @@ class Almanac extends WeatherDisplay { } } +const imageName = (type) => { + switch (type) { + case 'Full': + return 'images/2/Full-Moon.gif'; + case 'Last': + return 'images/2/Last-Quarter.gif'; + case 'New': + return 'images/2/New-Moon.gif'; + case 'First': + default: + return 'images/2/First-Quarter.gif'; + } +}; + // register display const display = new Almanac(8, 'almanac'); registerDisplay(display); diff --git a/server/scripts/modules/currentweather.mjs b/server/scripts/modules/currentweather.mjs index 8116226..b603ad3 100644 --- a/server/scripts/modules/currentweather.mjs +++ b/server/scripts/modules/currentweather.mjs @@ -128,7 +128,7 @@ class CurrentWeather extends WeatherDisplay { let Conditions = data.observations.textDescription; if (Conditions.length > 15) { - Conditions = CurrentWeather.shortConditions(Conditions); + Conditions = shortConditions(Conditions); } fill.condition = Conditions; @@ -170,26 +170,27 @@ class CurrentWeather extends WeatherDisplay { this.getDataCallbacks.push(() => resolve(this.parseData())); }); } - - static shortConditions(_condition) { - let condition = _condition; - condition = condition.replace(/Light/g, 'L'); - condition = condition.replace(/Heavy/g, 'H'); - condition = condition.replace(/Partly/g, 'P'); - condition = condition.replace(/Mostly/g, 'M'); - condition = condition.replace(/Few/g, 'F'); - condition = condition.replace(/Thunderstorm/g, 'T\'storm'); - condition = condition.replace(/ in /g, ''); - condition = condition.replace(/Vicinity/g, ''); - condition = condition.replace(/ and /g, ' '); - condition = condition.replace(/Freezing Rain/g, 'Frz Rn'); - condition = condition.replace(/Freezing/g, 'Frz'); - condition = condition.replace(/Unknown Precip/g, ''); - condition = condition.replace(/L Snow Fog/g, 'L Snw/Fog'); - condition = condition.replace(/ with /g, '/'); - return condition; - } } + +const shortConditions = (_condition) => { + let condition = _condition; + condition = condition.replace(/Light/g, 'L'); + condition = condition.replace(/Heavy/g, 'H'); + condition = condition.replace(/Partly/g, 'P'); + condition = condition.replace(/Mostly/g, 'M'); + condition = condition.replace(/Few/g, 'F'); + condition = condition.replace(/Thunderstorm/g, 'T\'storm'); + condition = condition.replace(/ in /g, ''); + condition = condition.replace(/Vicinity/g, ''); + condition = condition.replace(/ and /g, ' '); + condition = condition.replace(/Freezing Rain/g, 'Frz Rn'); + condition = condition.replace(/Freezing/g, 'Frz'); + condition = condition.replace(/Unknown Precip/g, ''); + condition = condition.replace(/L Snow Fog/g, 'L Snw/Fog'); + condition = condition.replace(/ with /g, '/'); + return condition; +}; + const display = new CurrentWeather(0, 'current-weather'); registerDisplay(display); diff --git a/server/scripts/modules/extendedforecast.mjs b/server/scripts/modules/extendedforecast.mjs index e061817..35916b2 100644 --- a/server/scripts/modules/extendedforecast.mjs +++ b/server/scripts/modules/extendedforecast.mjs @@ -36,95 +36,11 @@ class ExtendedForecast extends WeatherDisplay { return; } // we only get here if there was no error above - this.data = ExtendedForecast.parse(forecast.properties.periods); + this.data = parse(forecast.properties.periods); this.screenIndex = 0; this.setStatus(STATUS.loaded); } - // the api provides the forecast in 12 hour increments, flatten to day increments with high and low temperatures - static parse(fullForecast) { - // create a list of days starting with today - const Days = [0, 1, 2, 3, 4, 5, 6]; - - const dates = Days.map((shift) => { - const date = DateTime.local().startOf('day').plus({ days: shift }); - return date.toLocaleString({ weekday: 'short' }); - }); - - // track the destination forecast index - let destIndex = 0; - const forecast = []; - fullForecast.forEach((period) => { - // create the destination object if necessary - if (!forecast[destIndex]) { - forecast.push({ - dayName: '', low: undefined, high: undefined, text: undefined, icon: undefined, - }); - } - // get the object to modify/populate - const fDay = forecast[destIndex]; - // high temperature will always be last in the source array so it will overwrite the low values assigned below - fDay.icon = getWeatherIconFromIconLink(period.icon); - fDay.text = ExtendedForecast.shortenExtendedForecastText(period.shortForecast); - fDay.dayName = dates[destIndex]; - - // preload the icon - preloadImg(fDay.icon); - - if (period.isDaytime) { - // day time is the high temperature - fDay.high = period.temperature; - destIndex += 1; - } else { - // low temperature - fDay.low = period.temperature; - } - }); - - return forecast; - } - - static shortenExtendedForecastText(long) { - const regexList = [ - [/ and /ig, ' '], - [/Slight /ig, ''], - [/Chance /ig, ''], - [/Very /ig, ''], - [/Patchy /ig, ''], - [/Areas /ig, ''], - [/Dense /ig, ''], - [/Thunderstorm/g, 'T\'Storm'], - ]; - // run all regexes - const short = regexList.reduce((working, [regex, replace]) => working.replace(regex, replace), long); - - let conditions = short.split(' '); - if (short.indexOf('then') !== -1) { - conditions = short.split(' then '); - conditions = conditions[1].split(' '); - } - - let short1 = conditions[0].substr(0, 10); - let short2 = ''; - if (conditions[1]) { - if (!short1.endsWith('.')) { - short2 = conditions[1].substr(0, 10); - } else { - short1 = short1.replace(/\./, ''); - } - - if (short2 === 'Blowing') { - short2 = ''; - } - } - let result = short1; - if (short2 !== '') { - result += ` ${short2}`; - } - - return result; - } - async drawCanvas() { super.drawCanvas(); @@ -160,5 +76,89 @@ class ExtendedForecast extends WeatherDisplay { } } +// the api provides the forecast in 12 hour increments, flatten to day increments with high and low temperatures +const parse = (fullForecast) => { + // create a list of days starting with today + const Days = [0, 1, 2, 3, 4, 5, 6]; + + const dates = Days.map((shift) => { + const date = DateTime.local().startOf('day').plus({ days: shift }); + return date.toLocaleString({ weekday: 'short' }); + }); + + // track the destination forecast index + let destIndex = 0; + const forecast = []; + fullForecast.forEach((period) => { + // create the destination object if necessary + if (!forecast[destIndex]) { + forecast.push({ + dayName: '', low: undefined, high: undefined, text: undefined, icon: undefined, + }); + } + // get the object to modify/populate + const fDay = forecast[destIndex]; + // high temperature will always be last in the source array so it will overwrite the low values assigned below + fDay.icon = getWeatherIconFromIconLink(period.icon); + fDay.text = shortenExtendedForecastText(period.shortForecast); + fDay.dayName = dates[destIndex]; + + // preload the icon + preloadImg(fDay.icon); + + if (period.isDaytime) { + // day time is the high temperature + fDay.high = period.temperature; + destIndex += 1; + } else { + // low temperature + fDay.low = period.temperature; + } + }); + + return forecast; +}; + +const shortenExtendedForecastText = (long) => { + const regexList = [ + [/ and /ig, ' '], + [/Slight /ig, ''], + [/Chance /ig, ''], + [/Very /ig, ''], + [/Patchy /ig, ''], + [/Areas /ig, ''], + [/Dense /ig, ''], + [/Thunderstorm/g, 'T\'Storm'], + ]; + // run all regexes + const short = regexList.reduce((working, [regex, replace]) => working.replace(regex, replace), long); + + let conditions = short.split(' '); + if (short.indexOf('then') !== -1) { + conditions = short.split(' then '); + conditions = conditions[1].split(' '); + } + + let short1 = conditions[0].substr(0, 10); + let short2 = ''; + if (conditions[1]) { + if (!short1.endsWith('.')) { + short2 = conditions[1].substr(0, 10); + } else { + short1 = short1.replace(/\./, ''); + } + + if (short2 === 'Blowing') { + short2 = ''; + } + } + let result = short1; + if (short2 !== '') { + result += ` ${short2}`; + } + + return result; +}; + // register display registerDisplay(new ExtendedForecast(7, 'extended-forecast')); diff --git a/server/scripts/modules/hourly.mjs b/server/scripts/modules/hourly.mjs index 0f0478d..019120c 100644 --- a/server/scripts/modules/hourly.mjs +++ b/server/scripts/modules/hourly.mjs @@ -43,7 +43,7 @@ class Hourly extends WeatherDisplay { return; } - this.data = await Hourly.parseForecast(forecast.properties); + this.data = await parseForecast(forecast.properties); this.getDataCallback(); if (!superResponse) return; @@ -51,66 +51,6 @@ class Hourly extends WeatherDisplay { this.drawLongCanvas(); } - // extract specific values from forecast and format as an array - static async parseForecast(data) { - const temperature = Hourly.expand(data.temperature.values); - const apparentTemperature = Hourly.expand(data.apparentTemperature.values); - const windSpeed = Hourly.expand(data.windSpeed.values); - const windDirection = Hourly.expand(data.windDirection.values); - const skyCover = Hourly.expand(data.skyCover.values); // cloud icon - const weather = Hourly.expand(data.weather.values); // fog icon - const iceAccumulation = Hourly.expand(data.iceAccumulation.values); // ice icon - const probabilityOfPrecipitation = Hourly.expand(data.probabilityOfPrecipitation.values); // rain icon - const snowfallAmount = Hourly.expand(data.snowfallAmount.values); // snow icon - - const icons = await Hourly.determineIcon(skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed); - - return temperature.map((val, idx) => ({ - temperature: celsiusToFahrenheit(temperature[idx]), - apparentTemperature: celsiusToFahrenheit(apparentTemperature[idx]), - windSpeed: kilometersToMiles(windSpeed[idx]), - windDirection: directionToNSEW(windDirection[idx]), - probabilityOfPrecipitation: probabilityOfPrecipitation[idx], - skyCover: skyCover[idx], - icon: icons[idx], - })); - } - - // given forecast paramaters determine a suitable icon - static async determineIcon(skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed) { - const startOfHour = DateTime.local().startOf('hour'); - const sunTimes = (await getSun()).sun; - const overnight = Interval.fromDateTimes(DateTime.fromJSDate(sunTimes[0].sunset), DateTime.fromJSDate(sunTimes[1].sunrise)); - const tomorrowOvernight = DateTime.fromJSDate(sunTimes[1].sunset); - return skyCover.map((val, idx) => { - const hour = startOfHour.plus({ hours: idx }); - const isNight = overnight.contains(hour) || (hour > tomorrowOvernight); - return getHourlyIcon(skyCover[idx], weather[idx], iceAccumulation[idx], probabilityOfPrecipitation[idx], snowfallAmount[idx], windSpeed[idx], isNight); - }); - } - - // expand a set of values with durations to an hour-by-hour array - static expand(data) { - const startOfHour = DateTime.utc().startOf('hour').toMillis(); - const result = []; // resulting expanded values - data.forEach((item) => { - let startTime = Date.parse(item.validTime.substr(0, item.validTime.indexOf('/'))); - const duration = Duration.fromISO(item.validTime.substr(item.validTime.indexOf('/') + 1)).shiftTo('milliseconds').values.milliseconds; - const endTime = startTime + duration; - // loop through duration at one hour intervals - do { - // test for timestamp greater than now - if (startTime >= startOfHour && result.length < 24) { - result.push(item.value); // push data array - } // timestamp is after now - // increment start time by 1 hour - startTime += 3600000; - } while (startTime < endTime && result.length < 24); - }); // for each value - - return result; - } - async drawLongCanvas() { // get the list element and populate const list = this.elem.querySelector('.hourly-lines'); @@ -178,19 +118,6 @@ class Hourly extends WeatherDisplay { this.elem.querySelector('.main').scrollTo(0, offsetY); } - static getTravelCitiesDayName(cities) { - // effectively returns early on the first found date - return cities.reduce((dayName, city) => { - if (city && dayName === '') { - // today or tomorrow - const day = DateTime.local().plus({ days: (city.today) ? 0 : 1 }); - // return the day - return day.toLocaleString({ weekday: 'long' }); - } - return dayName; - }, ''); - } - // make data available outside this class // promise allows for data to be requested before it is available async getCurrentData() { @@ -202,6 +129,66 @@ class Hourly extends WeatherDisplay { } } +// extract specific values from forecast and format as an array +const parseForecast = async (data) => { + const temperature = expand(data.temperature.values); + const apparentTemperature = expand(data.apparentTemperature.values); + const windSpeed = expand(data.windSpeed.values); + const windDirection = expand(data.windDirection.values); + const skyCover = expand(data.skyCover.values); // cloud icon + const weather = expand(data.weather.values); // fog icon + const iceAccumulation = expand(data.iceAccumulation.values); // ice icon + const probabilityOfPrecipitation = expand(data.probabilityOfPrecipitation.values); // rain icon + const snowfallAmount = expand(data.snowfallAmount.values); // snow icon + + const icons = await determineIcon(skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed); + + return temperature.map((val, idx) => ({ + temperature: celsiusToFahrenheit(temperature[idx]), + apparentTemperature: celsiusToFahrenheit(apparentTemperature[idx]), + windSpeed: kilometersToMiles(windSpeed[idx]), + windDirection: directionToNSEW(windDirection[idx]), + probabilityOfPrecipitation: probabilityOfPrecipitation[idx], + skyCover: skyCover[idx], + icon: icons[idx], + })); +}; + +// given forecast paramaters determine a suitable icon +const determineIcon = async (skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed) => { + const startOfHour = DateTime.local().startOf('hour'); + const sunTimes = (await getSun()).sun; + const overnight = Interval.fromDateTimes(DateTime.fromJSDate(sunTimes[0].sunset), DateTime.fromJSDate(sunTimes[1].sunrise)); + const tomorrowOvernight = DateTime.fromJSDate(sunTimes[1].sunset); + return skyCover.map((val, idx) => { + const hour = startOfHour.plus({ hours: idx }); + const isNight = overnight.contains(hour) || (hour > tomorrowOvernight); + return getHourlyIcon(skyCover[idx], weather[idx], iceAccumulation[idx], probabilityOfPrecipitation[idx], snowfallAmount[idx], windSpeed[idx], isNight); + }); +}; + +// expand a set of values with durations to an hour-by-hour array +const expand = (data) => { + const startOfHour = DateTime.utc().startOf('hour').toMillis(); + const result = []; // resulting expanded values + data.forEach((item) => { + let startTime = Date.parse(item.validTime.substr(0, item.validTime.indexOf('/'))); + const duration = Duration.fromISO(item.validTime.substr(item.validTime.indexOf('/') + 1)).shiftTo('milliseconds').values.milliseconds; + const endTime = startTime + duration; + // loop through duration at one hour intervals + do { + // test for timestamp greater than now + if (startTime >= startOfHour && result.length < 24) { + result.push(item.value); // push data array + } // timestamp is after now + // increment start time by 1 hour + startTime += 3600000; + } while (startTime < endTime && result.length < 24); + }); // for each value + + return result; +}; + // register display const display = new Hourly(2, 'hourly', false); registerDisplay(display); diff --git a/server/scripts/modules/latestobservations.mjs b/server/scripts/modules/latestobservations.mjs index 4ae9967..8ab9151 100644 --- a/server/scripts/modules/latestobservations.mjs +++ b/server/scripts/modules/latestobservations.mjs @@ -82,7 +82,7 @@ class LatestObservations extends WeatherDisplay { const fill = {}; fill.location = locationCleanup(condition.city).substr(0, 14); fill.temp = Temperature; - fill.weather = LatestObservations.shortenCurrentConditions(condition.textDescription).substr(0, 9); + fill.weather = shortenCurrentConditions(condition.textDescription).substr(0, 9); if (WindSpeed > 0) { fill.wind = windDirection + (Array(6 - windDirection.length - WindSpeed.toString().length).join(' ')) + WindSpeed.toString(); } else if (WindSpeed === 'NA') { @@ -100,25 +100,24 @@ class LatestObservations extends WeatherDisplay { this.finishDraw(); } - - static shortenCurrentConditions(_condition) { - let condition = _condition; - condition = condition.replace(/Light/, 'L'); - condition = condition.replace(/Heavy/, 'H'); - condition = condition.replace(/Partly/, 'P'); - condition = condition.replace(/Mostly/, 'M'); - condition = condition.replace(/Few/, 'F'); - condition = condition.replace(/Thunderstorm/, 'T\'storm'); - condition = condition.replace(/ in /, ''); - condition = condition.replace(/Vicinity/, ''); - condition = condition.replace(/ and /, ' '); - condition = condition.replace(/Freezing Rain/, 'Frz Rn'); - condition = condition.replace(/Freezing/, 'Frz'); - condition = condition.replace(/Unknown Precip/, ''); - condition = condition.replace(/L Snow Fog/, 'L Snw/Fog'); - condition = condition.replace(/ with /, '/'); - return condition; - } } +const shortenCurrentConditions = (_condition) => { + let condition = _condition; + condition = condition.replace(/Light/, 'L'); + condition = condition.replace(/Heavy/, 'H'); + condition = condition.replace(/Partly/, 'P'); + condition = condition.replace(/Mostly/, 'M'); + condition = condition.replace(/Few/, 'F'); + condition = condition.replace(/Thunderstorm/, 'T\'storm'); + condition = condition.replace(/ in /, ''); + condition = condition.replace(/Vicinity/, ''); + condition = condition.replace(/ and /, ' '); + condition = condition.replace(/Freezing Rain/, 'Frz Rn'); + condition = condition.replace(/Freezing/, 'Frz'); + condition = condition.replace(/Unknown Precip/, ''); + condition = condition.replace(/L Snow Fog/, 'L Snw/Fog'); + condition = condition.replace(/ with /, '/'); + return condition; +}; // register display registerDisplay(new LatestObservations(1, 'latest-observations')); diff --git a/server/scripts/modules/localforecast.mjs b/server/scripts/modules/localforecast.mjs index 754ecfb..0c98b78 100644 --- a/server/scripts/modules/localforecast.mjs +++ b/server/scripts/modules/localforecast.mjs @@ -25,7 +25,7 @@ class LocalForecast extends WeatherDisplay { return; } // parse raw data - const conditions = LocalForecast.parse(rawData); + const conditions = parse(rawData); // read each text this.screenTexts = conditions.map((condition) => { @@ -80,17 +80,14 @@ class LocalForecast extends WeatherDisplay { this.finishDraw(); } - - // format the forecast - static parse(forecast) { - // only use the first 6 lines - return forecast.properties.periods.slice(0, 6).map((text) => ({ - // format day and text - DayName: text.name.toUpperCase(), - Text: text.detailedForecast, - })); - } } +// format the forecast +// only use the first 6 lines +const parse = (forecast) => forecast.properties.periods.slice(0, 6).map((text) => ({ + // format day and text + DayName: text.name.toUpperCase(), + Text: text.detailedForecast, +})); // register display registerDisplay(new LocalForecast(6, 'local-forecast')); diff --git a/server/scripts/modules/radar-utils.mjs b/server/scripts/modules/radar-utils.mjs new file mode 100644 index 0000000..d2b46a7 --- /dev/null +++ b/server/scripts/modules/radar-utils.mjs @@ -0,0 +1,185 @@ +const getXYFromLatitudeLongitudeMap = (pos, offsetX, offsetY) => { + let y = 0; + let x = 0; + const imgHeight = 3200; + const imgWidth = 5100; + + y = (51.75 - pos.latitude) * 55.2; + // center map + y -= offsetY; + + // Do not allow the map to exceed the max/min coordinates. + if (y > (imgHeight - (offsetY * 2))) { + y = imgHeight - (offsetY * 2); + } else if (y < 0) { + y = 0; + } + + x = ((-130.37 - pos.longitude) * 41.775) * -1; + // center map + x -= offsetX; + + // Do not allow the map to exceed the max/min coordinates. + if (x > (imgWidth - (offsetX * 2))) { + x = imgWidth - (offsetX * 2); + } else if (x < 0) { + x = 0; + } + + return { x: x * 2, y: y * 2 }; +}; + +const getXYFromLatitudeLongitudeDoppler = (pos, offsetX, offsetY) => { + let y = 0; + let x = 0; + const imgHeight = 6000; + const imgWidth = 2800; + + y = (51 - pos.latitude) * 61.4481; + // center map + y -= offsetY; + + // Do not allow the map to exceed the max/min coordinates. + if (y > (imgHeight - (offsetY * 2))) { + y = imgHeight - (offsetY * 2); + } else if (y < 0) { + y = 0; + } + + x = ((-129.138 - pos.longitude) * 42.1768) * -1; + // center map + x -= offsetX; + + // Do not allow the map to exceed the max/min coordinates. + if (x > (imgWidth - (offsetX * 2))) { + x = imgWidth - (offsetX * 2); + } else if (x < 0) { + x = 0; + } + + return { x: x * 2, y: y * 2 }; +}; + +const removeDopplerRadarImageNoise = (RadarContext) => { + const RadarImageData = RadarContext.getImageData(0, 0, RadarContext.canvas.width, RadarContext.canvas.height); + + // examine every pixel, + // change any old rgb to the new-rgb + for (let i = 0; i < RadarImageData.data.length; i += 4) { + // i + 0 = red + // i + 1 = green + // i + 2 = blue + // i + 3 = alpha (0 = transparent, 255 = opaque) + let R = RadarImageData.data[i]; + let G = RadarImageData.data[i + 1]; + let B = RadarImageData.data[i + 2]; + let A = RadarImageData.data[i + 3]; + + // is this pixel the old rgb? + if ((R === 0 && G === 0 && B === 0) + || (R === 0 && G === 236 && B === 236) + || (R === 1 && G === 160 && B === 246) + || (R === 0 && G === 0 && B === 246)) { + // change to your new rgb + + // Transparent + R = 0; + G = 0; + B = 0; + A = 0; + } else if ((R === 0 && G === 255 && B === 0)) { + // Light Green 1 + R = 49; + G = 210; + B = 22; + A = 255; + } else if ((R === 0 && G === 200 && B === 0)) { + // Light Green 2 + R = 0; + G = 142; + B = 0; + A = 255; + } else if ((R === 0 && G === 144 && B === 0)) { + // Dark Green 1 + R = 20; + G = 90; + B = 15; + A = 255; + } else if ((R === 255 && G === 255 && B === 0)) { + // Dark Green 2 + R = 10; + G = 40; + B = 10; + A = 255; + } else if ((R === 231 && G === 192 && B === 0)) { + // Yellow + R = 196; + G = 179; + B = 70; + A = 255; + } else if ((R === 255 && G === 144 && B === 0)) { + // Orange + R = 190; + G = 72; + B = 19; + A = 255; + } else if ((R === 214 && G === 0 && B === 0) + || (R === 255 && G === 0 && B === 0)) { + // Red + R = 171; + G = 14; + B = 14; + A = 255; + } else if ((R === 192 && G === 0 && B === 0) + || (R === 255 && G === 0 && B === 255)) { + // Brown + R = 115; + G = 31; + B = 4; + A = 255; + } + + RadarImageData.data[i] = R; + RadarImageData.data[i + 1] = G; + RadarImageData.data[i + 2] = B; + RadarImageData.data[i + 3] = A; + } + + RadarContext.putImageData(RadarImageData, 0, 0); +}; + +const mergeDopplerRadarImage = (mapContext, radarContext) => { + const mapImageData = mapContext.getImageData(0, 0, mapContext.canvas.width, mapContext.canvas.height); + const radarImageData = radarContext.getImageData(0, 0, radarContext.canvas.width, radarContext.canvas.height); + + // examine every pixel, + // change any old rgb to the new-rgb + for (let i = 0; i < radarImageData.data.length; i += 4) { + // i + 0 = red + // i + 1 = green + // i + 2 = blue + // i + 3 = alpha (0 = transparent, 255 = opaque) + + // is this pixel the old rgb? + if ((mapImageData.data[i] < 116 && mapImageData.data[i + 1] < 116 && mapImageData.data[i + 2] < 116)) { + // change to your new rgb + + // Transparent + radarImageData.data[i] = 0; + radarImageData.data[i + 1] = 0; + radarImageData.data[i + 2] = 0; + radarImageData.data[i + 3] = 0; + } + } + + radarContext.putImageData(radarImageData, 0, 0); + + mapContext.drawImage(radarContext.canvas, 0, 0); +}; + +export { + getXYFromLatitudeLongitudeDoppler, + getXYFromLatitudeLongitudeMap, + removeDopplerRadarImageNoise, + mergeDopplerRadarImage, +}; diff --git a/server/scripts/modules/radar.mjs b/server/scripts/modules/radar.mjs index 073c029..d3e1a85 100644 --- a/server/scripts/modules/radar.mjs +++ b/server/scripts/modules/radar.mjs @@ -6,6 +6,7 @@ import { text } from './utils/fetch.mjs'; import { rewriteUrl } from './utils/cors.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; +import * as utils from './radar-utils.mjs'; class Radar extends WeatherDisplay { constructor(navId, elemId) { @@ -109,7 +110,7 @@ class Radar extends WeatherDisplay { const height = 1600; offsetX *= 2; offsetY *= 2; - const sourceXY = Radar.getXYFromLatitudeLongitudeMap(weatherParameters, offsetX, offsetY); + const sourceXY = utils.getXYFromLatitudeLongitudeMap(weatherParameters, offsetX, offsetY); // create working context for manipulation const workingCanvas = document.createElement('canvas'); @@ -121,7 +122,7 @@ class Radar extends WeatherDisplay { // calculate radar offsets const radarOffsetX = 120; const radarOffsetY = 70; - const radarSourceXY = Radar.getXYFromLatitudeLongitudeDoppler(weatherParameters, offsetX, offsetY); + const radarSourceXY = utils.getXYFromLatitudeLongitudeDoppler(weatherParameters, offsetX, offsetY); const radarSourceX = radarSourceXY.x / 2; const radarSourceY = radarSourceXY.y / 2; @@ -179,10 +180,10 @@ class Radar extends WeatherDisplay { cropContext.imageSmoothingEnabled = false; cropContext.drawImage(workingCanvas, radarSourceX, radarSourceY, (radarOffsetX * 2), (radarOffsetY * 2.33), 0, 0, 640, 367); // clean the image - Radar.removeDopplerRadarImageNoise(cropContext); + utils.removeDopplerRadarImageNoise(cropContext); // merge the radar and map - Radar.mergeDopplerRadarImage(context, cropContext); + utils.mergeDopplerRadarImage(context, cropContext); const elem = this.fillTemplate('frame', { map: { type: 'img', src: canvas.toDataURL() } }); @@ -218,185 +219,6 @@ class Radar extends WeatherDisplay { this.finishDraw(); } - - static getXYFromLatitudeLongitudeMap(pos, offsetX, offsetY) { - let y = 0; - let x = 0; - const imgHeight = 3200; - const imgWidth = 5100; - - y = (51.75 - pos.latitude) * 55.2; - // center map - y -= offsetY; - - // Do not allow the map to exceed the max/min coordinates. - if (y > (imgHeight - (offsetY * 2))) { - y = imgHeight - (offsetY * 2); - } else if (y < 0) { - y = 0; - } - - x = ((-130.37 - pos.longitude) * 41.775) * -1; - // center map - x -= offsetX; - - // Do not allow the map to exceed the max/min coordinates. - if (x > (imgWidth - (offsetX * 2))) { - x = imgWidth - (offsetX * 2); - } else if (x < 0) { - x = 0; - } - - return { x: x * 2, y: y * 2 }; - } - - static getXYFromLatitudeLongitudeDoppler(pos, offsetX, offsetY) { - let y = 0; - let x = 0; - const imgHeight = 6000; - const imgWidth = 2800; - - y = (51 - pos.latitude) * 61.4481; - // center map - y -= offsetY; - - // Do not allow the map to exceed the max/min coordinates. - if (y > (imgHeight - (offsetY * 2))) { - y = imgHeight - (offsetY * 2); - } else if (y < 0) { - y = 0; - } - - x = ((-129.138 - pos.longitude) * 42.1768) * -1; - // center map - x -= offsetX; - - // Do not allow the map to exceed the max/min coordinates. - if (x > (imgWidth - (offsetX * 2))) { - x = imgWidth - (offsetX * 2); - } else if (x < 0) { - x = 0; - } - - return { x: x * 2, y: y * 2 }; - } - - static removeDopplerRadarImageNoise(RadarContext) { - const RadarImageData = RadarContext.getImageData(0, 0, RadarContext.canvas.width, RadarContext.canvas.height); - - // examine every pixel, - // change any old rgb to the new-rgb - for (let i = 0; i < RadarImageData.data.length; i += 4) { - // i + 0 = red - // i + 1 = green - // i + 2 = blue - // i + 3 = alpha (0 = transparent, 255 = opaque) - let R = RadarImageData.data[i]; - let G = RadarImageData.data[i + 1]; - let B = RadarImageData.data[i + 2]; - let A = RadarImageData.data[i + 3]; - - // is this pixel the old rgb? - if ((R === 0 && G === 0 && B === 0) - || (R === 0 && G === 236 && B === 236) - || (R === 1 && G === 160 && B === 246) - || (R === 0 && G === 0 && B === 246)) { - // change to your new rgb - - // Transparent - R = 0; - G = 0; - B = 0; - A = 0; - } else if ((R === 0 && G === 255 && B === 0)) { - // Light Green 1 - R = 49; - G = 210; - B = 22; - A = 255; - } else if ((R === 0 && G === 200 && B === 0)) { - // Light Green 2 - R = 0; - G = 142; - B = 0; - A = 255; - } else if ((R === 0 && G === 144 && B === 0)) { - // Dark Green 1 - R = 20; - G = 90; - B = 15; - A = 255; - } else if ((R === 255 && G === 255 && B === 0)) { - // Dark Green 2 - R = 10; - G = 40; - B = 10; - A = 255; - } else if ((R === 231 && G === 192 && B === 0)) { - // Yellow - R = 196; - G = 179; - B = 70; - A = 255; - } else if ((R === 255 && G === 144 && B === 0)) { - // Orange - R = 190; - G = 72; - B = 19; - A = 255; - } else if ((R === 214 && G === 0 && B === 0) - || (R === 255 && G === 0 && B === 0)) { - // Red - R = 171; - G = 14; - B = 14; - A = 255; - } else if ((R === 192 && G === 0 && B === 0) - || (R === 255 && G === 0 && B === 255)) { - // Brown - R = 115; - G = 31; - B = 4; - A = 255; - } - - RadarImageData.data[i] = R; - RadarImageData.data[i + 1] = G; - RadarImageData.data[i + 2] = B; - RadarImageData.data[i + 3] = A; - } - - RadarContext.putImageData(RadarImageData, 0, 0); - } - - static mergeDopplerRadarImage(mapContext, radarContext) { - const mapImageData = mapContext.getImageData(0, 0, mapContext.canvas.width, mapContext.canvas.height); - const radarImageData = radarContext.getImageData(0, 0, radarContext.canvas.width, radarContext.canvas.height); - - // examine every pixel, - // change any old rgb to the new-rgb - for (let i = 0; i < radarImageData.data.length; i += 4) { - // i + 0 = red - // i + 1 = green - // i + 2 = blue - // i + 3 = alpha (0 = transparent, 255 = opaque) - - // is this pixel the old rgb? - if ((mapImageData.data[i] < 116 && mapImageData.data[i + 1] < 116 && mapImageData.data[i + 2] < 116)) { - // change to your new rgb - - // Transparent - radarImageData.data[i] = 0; - radarImageData.data[i + 1] = 0; - radarImageData.data[i + 2] = 0; - radarImageData.data[i + 3] = 0; - } - } - - radarContext.putImageData(radarImageData, 0, 0); - - mapContext.drawImage(radarContext.canvas, 0, 0); - } } // register display diff --git a/server/scripts/modules/regionalforecast-utils.mjs b/server/scripts/modules/regionalforecast-utils.mjs new file mode 100644 index 0000000..c82218d --- /dev/null +++ b/server/scripts/modules/regionalforecast-utils.mjs @@ -0,0 +1,205 @@ +import { getWeatherRegionalIconFromIconLink } from './icons.mjs'; +import { preloadImg } from './utils/image.mjs'; +import { json } from './utils/fetch.mjs'; + +const buildForecast = (forecast, city, cityXY) => ({ + daytime: forecast.isDaytime, + temperature: forecast.temperature || 0, + name: formatCity(city.city), + icon: forecast.icon, + x: cityXY.x, + y: cityXY.y, + time: forecast.startTime, +}); + +const getRegionalObservation = async (point, city) => { + try { + // get stations + const stations = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/stations`); + + // get the first station + const station = stations.features[0].id; + // get the observation data + const observation = await json(`${station}/observations/latest`); + // preload the image + if (!observation.properties.icon) return false; + preloadImg(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 ?? city.city}`); + console.error(e.status, e.responseJSON); + return false; + } +}; + +// utility latitude/pixel conversions +const getXYFromLatitudeLongitude = (Latitude, Longitude, OffsetX, OffsetY, state) => { + if (state === 'AK') return getXYFromLatitudeLongitudeAK(Latitude, Longitude, OffsetX, OffsetY); + if (state === 'HI') return getXYFromLatitudeLongitudeHI(Latitude, Longitude, OffsetX, OffsetY); + let y = 0; + let x = 0; + const ImgHeight = 1600; + const ImgWidth = 2550; + + y = (50.5 - Latitude) * 55.2; + y -= OffsetY; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (y > (ImgHeight - (OffsetY * 2))) { + y = ImgHeight - (OffsetY * 2); + } else if (y < 0) { + y = 0; + } + + x = ((-127.5 - Longitude) * 41.775) * -1; + x -= OffsetX; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (x > (ImgWidth - (OffsetX * 2))) { + x = ImgWidth - (OffsetX * 2); + } else if (x < 0) { + x = 0; + } + + return { x, y }; +}; + +const getXYFromLatitudeLongitudeAK = (Latitude, Longitude, OffsetX, OffsetY) => { + let y = 0; + let x = 0; + const ImgHeight = 1142; + const ImgWidth = 1200; + + y = (73.0 - Latitude) * 56; + y -= OffsetY; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (y > (ImgHeight - (OffsetY * 2))) { + y = ImgHeight - (OffsetY * 2); + } else if (y < 0) { + y = 0; + } + + x = ((-175.0 - Longitude) * 25.0) * -1; + x -= OffsetX; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (x > (ImgWidth - (OffsetX * 2))) { + x = ImgWidth - (OffsetX * 2); + } else if (x < 0) { + x = 0; + } + + return { x, y }; +}; + +const getXYFromLatitudeLongitudeHI = (Latitude, Longitude, OffsetX, OffsetY) => { + let y = 0; + let x = 0; + const ImgHeight = 571; + const ImgWidth = 600; + + y = (25 - Latitude) * 55.2; + y -= OffsetY; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (y > (ImgHeight - (OffsetY * 2))) { + y = ImgHeight - (OffsetY * 2); + } else if (y < 0) { + y = 0; + } + + x = ((-164.5 - Longitude) * 41.775) * -1; + x -= OffsetX; // Centers map. + // Do not allow the map to exceed the max/min coordinates. + if (x > (ImgWidth - (OffsetX * 2))) { + x = ImgWidth - (OffsetX * 2); + } else if (x < 0) { + x = 0; + } + + return { x, y }; +}; + +const getMinMaxLatitudeLongitude = (X, Y, OffsetX, OffsetY, state) => { + if (state === 'AK') return getMinMaxLatitudeLongitudeAK(X, Y, OffsetX, OffsetY); + if (state === 'HI') return getMinMaxLatitudeLongitudeHI(X, Y, OffsetX, OffsetY); + const maxLat = ((Y / 55.2) - 50.5) * -1; + const minLat = (((Y + (OffsetY * 2)) / 55.2) - 50.5) * -1; + const minLon = (((X * -1) / 41.775) + 127.5) * -1; + const maxLon = ((((X + (OffsetX * 2)) * -1) / 41.775) + 127.5) * -1; + + return { + minLat, maxLat, minLon, maxLon, + }; +}; + +const getMinMaxLatitudeLongitudeAK = (X, Y, OffsetX, OffsetY) => { + const maxLat = ((Y / 56) - 73.0) * -1; + const minLat = (((Y + (OffsetY * 2)) / 56) - 73.0) * -1; + const minLon = (((X * -1) / 25) + 175.0) * -1; + const maxLon = ((((X + (OffsetX * 2)) * -1) / 25) + 175.0) * -1; + + return { + minLat, maxLat, minLon, maxLon, + }; +}; + +const getMinMaxLatitudeLongitudeHI = (X, Y, OffsetX, OffsetY) => { + const maxLat = ((Y / 55.2) - 25) * -1; + const minLat = (((Y + (OffsetY * 2)) / 55.2) - 25) * -1; + const minLon = (((X * -1) / 41.775) + 164.5) * -1; + const maxLon = ((((X + (OffsetX * 2)) * -1) / 41.775) + 164.5) * -1; + + return { + minLat, maxLat, minLon, maxLon, + }; +}; + +const getXYForCity = (City, MaxLatitude, MinLongitude, state) => { + if (state === 'AK') getXYForCityAK(City, MaxLatitude, MinLongitude); + if (state === 'HI') getXYForCityHI(City, MaxLatitude, MinLongitude); + let x = (City.lon - MinLongitude) * 57; + let y = (MaxLatitude - City.lat) * 70; + + if (y < 30) y = 30; + if (y > 282) y = 282; + + if (x < 40) x = 40; + if (x > 580) x = 580; + + return { x, y }; +}; + +const getXYForCityAK = (City, MaxLatitude, MinLongitude) => { + let x = (City.lon - MinLongitude) * 37; + let y = (MaxLatitude - City.lat) * 70; + + if (y < 30) y = 30; + if (y > 282) y = 282; + + if (x < 40) x = 40; + if (x > 580) x = 580; + return { x, y }; +}; + +const getXYForCityHI = (City, MaxLatitude, MinLongitude) => { + let x = (City.lon - MinLongitude) * 57; + let y = (MaxLatitude - City.lat) * 70; + + if (y < 30) y = 30; + if (y > 282) y = 282; + + if (x < 40) x = 40; + if (x > 580) x = 580; + + return { x, y }; +}; + +// to fit on the map, remove anything after punctuation and then limit to 15 characters +const formatCity = (city) => city.match(/[^-;/\\,]*/)[0].substr(0, 12); + +export { + buildForecast, + getRegionalObservation, + getXYFromLatitudeLongitude, + getMinMaxLatitudeLongitude, + getXYForCity, + formatCity, +}; diff --git a/server/scripts/modules/regionalforecast.mjs b/server/scripts/modules/regionalforecast.mjs index 0fe4e85..19a71b6 100644 --- a/server/scripts/modules/regionalforecast.mjs +++ b/server/scripts/modules/regionalforecast.mjs @@ -10,6 +10,7 @@ import { preloadImg } from './utils/image.mjs'; import { DateTime } from '../vendor/auto/luxon.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; +import * as utils from './regionalforecast-utils.mjs'; class RegionalForecast extends WeatherDisplay { constructor(navId, elemId) { @@ -38,10 +39,10 @@ class RegionalForecast extends WeatherDisplay { y: 117, }; // get user's location in x/y - const sourceXY = RegionalForecast.getXYFromLatitudeLongitude(weatherParameters.latitude, weatherParameters.longitude, offsetXY.x, offsetXY.y, weatherParameters.state); + const sourceXY = utils.getXYFromLatitudeLongitude(weatherParameters.latitude, weatherParameters.longitude, offsetXY.x, offsetXY.y, weatherParameters.state); // get latitude and longitude limits - const minMaxLatLon = RegionalForecast.getMinMaxLatitudeLongitude(sourceXY.x, sourceXY.y, offsetXY.x, offsetXY.y, weatherParameters.state); + const minMaxLatLon = utils.getMinMaxLatitudeLongitude(sourceXY.x, sourceXY.y, offsetXY.x, offsetXY.y, weatherParameters.state); // get a target distance let targetDistance = 2.5; @@ -75,12 +76,12 @@ class RegionalForecast extends WeatherDisplay { if (!city.point) throw new Error('No pre-loaded point'); // start off the observation task - const observationPromise = RegionalForecast.getRegionalObservation(city.point, city); + const observationPromise = utils.getRegionalObservation(city.point, city); const forecast = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`); // get XY on map for city - const cityXY = RegionalForecast.getXYForCity(city, minMaxLatLon.maxLat, minMaxLatLon.minLon, weatherParameters.state); + const cityXY = utils.getXYForCity(city, minMaxLatLon.maxLat, minMaxLatLon.minLon, weatherParameters.state); // wait for the regional observation if it's not done yet const observation = await observationPromise; @@ -88,7 +89,7 @@ class RegionalForecast extends WeatherDisplay { const regionalObservation = { daytime: !!observation.icon.match(/\/day\//), temperature: celsiusToFahrenheit(observation.temperature.value), - name: RegionalForecast.formatCity(city.city), + name: utils.formatCity(city.city), icon: observation.icon, x: cityXY.x, y: cityXY.y, @@ -104,8 +105,8 @@ class RegionalForecast extends WeatherDisplay { // always skip the first forecast index because it's what's going on right now return [ regionalObservation, - RegionalForecast.buildForecast(forecast.properties.periods[1], city, cityXY), - RegionalForecast.buildForecast(forecast.properties.periods[2], city, cityXY), + utils.buildForecast(forecast.properties.periods[1], city, cityXY), + utils.buildForecast(forecast.properties.periods[2], city, cityXY), ]; } catch (e) { console.log(`No regional forecast data for '${city.name ?? city.city}'`); @@ -133,203 +134,6 @@ class RegionalForecast extends WeatherDisplay { this.setStatus(STATUS.loaded); } - static buildForecast(forecast, city, cityXY) { - return { - daytime: forecast.isDaytime, - temperature: forecast.temperature || 0, - name: RegionalForecast.formatCity(city.city), - icon: forecast.icon, - x: cityXY.x, - y: cityXY.y, - time: forecast.startTime, - }; - } - - static async getRegionalObservation(point, city) { - try { - // get stations - const stations = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/stations`); - - // get the first station - const station = stations.features[0].id; - // get the observation data - const observation = await json(`${station}/observations/latest`); - // preload the image - if (!observation.properties.icon) return false; - preloadImg(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 ?? city.city}`); - console.error(e.status, e.responseJSON); - return false; - } - } - - // utility latitude/pixel conversions - static getXYFromLatitudeLongitude(Latitude, Longitude, OffsetX, OffsetY, state) { - if (state === 'AK') return RegionalForecast.getXYFromLatitudeLongitudeAK(Latitude, Longitude, OffsetX, OffsetY); - if (state === 'HI') return RegionalForecast.getXYFromLatitudeLongitudeHI(Latitude, Longitude, OffsetX, OffsetY); - let y = 0; - let x = 0; - const ImgHeight = 1600; - const ImgWidth = 2550; - - y = (50.5 - Latitude) * 55.2; - y -= OffsetY; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (y > (ImgHeight - (OffsetY * 2))) { - y = ImgHeight - (OffsetY * 2); - } else if (y < 0) { - y = 0; - } - - x = ((-127.5 - Longitude) * 41.775) * -1; - x -= OffsetX; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (x > (ImgWidth - (OffsetX * 2))) { - x = ImgWidth - (OffsetX * 2); - } else if (x < 0) { - x = 0; - } - - return { x, y }; - } - - static getXYFromLatitudeLongitudeAK(Latitude, Longitude, OffsetX, OffsetY) { - let y = 0; - let x = 0; - const ImgHeight = 1142; - const ImgWidth = 1200; - - y = (73.0 - Latitude) * 56; - y -= OffsetY; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (y > (ImgHeight - (OffsetY * 2))) { - y = ImgHeight - (OffsetY * 2); - } else if (y < 0) { - y = 0; - } - - x = ((-175.0 - Longitude) * 25.0) * -1; - x -= OffsetX; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (x > (ImgWidth - (OffsetX * 2))) { - x = ImgWidth - (OffsetX * 2); - } else if (x < 0) { - x = 0; - } - - return { x, y }; - } - - static getXYFromLatitudeLongitudeHI(Latitude, Longitude, OffsetX, OffsetY) { - let y = 0; - let x = 0; - const ImgHeight = 571; - const ImgWidth = 600; - - y = (25 - Latitude) * 55.2; - y -= OffsetY; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (y > (ImgHeight - (OffsetY * 2))) { - y = ImgHeight - (OffsetY * 2); - } else if (y < 0) { - y = 0; - } - - x = ((-164.5 - Longitude) * 41.775) * -1; - x -= OffsetX; // Centers map. - // Do not allow the map to exceed the max/min coordinates. - if (x > (ImgWidth - (OffsetX * 2))) { - x = ImgWidth - (OffsetX * 2); - } else if (x < 0) { - x = 0; - } - - return { x, y }; - } - - static getMinMaxLatitudeLongitude(X, Y, OffsetX, OffsetY, state) { - if (state === 'AK') return RegionalForecast.getMinMaxLatitudeLongitudeAK(X, Y, OffsetX, OffsetY); - if (state === 'HI') return RegionalForecast.getMinMaxLatitudeLongitudeHI(X, Y, OffsetX, OffsetY); - const maxLat = ((Y / 55.2) - 50.5) * -1; - const minLat = (((Y + (OffsetY * 2)) / 55.2) - 50.5) * -1; - const minLon = (((X * -1) / 41.775) + 127.5) * -1; - const maxLon = ((((X + (OffsetX * 2)) * -1) / 41.775) + 127.5) * -1; - - return { - minLat, maxLat, minLon, maxLon, - }; - } - - static getMinMaxLatitudeLongitudeAK(X, Y, OffsetX, OffsetY) { - const maxLat = ((Y / 56) - 73.0) * -1; - const minLat = (((Y + (OffsetY * 2)) / 56) - 73.0) * -1; - const minLon = (((X * -1) / 25) + 175.0) * -1; - const maxLon = ((((X + (OffsetX * 2)) * -1) / 25) + 175.0) * -1; - - return { - minLat, maxLat, minLon, maxLon, - }; - } - - static getMinMaxLatitudeLongitudeHI(X, Y, OffsetX, OffsetY) { - const maxLat = ((Y / 55.2) - 25) * -1; - const minLat = (((Y + (OffsetY * 2)) / 55.2) - 25) * -1; - const minLon = (((X * -1) / 41.775) + 164.5) * -1; - const maxLon = ((((X + (OffsetX * 2)) * -1) / 41.775) + 164.5) * -1; - - return { - minLat, maxLat, minLon, maxLon, - }; - } - - static getXYForCity(City, MaxLatitude, MinLongitude, state) { - if (state === 'AK') RegionalForecast.getXYForCityAK(City, MaxLatitude, MinLongitude); - if (state === 'HI') RegionalForecast.getXYForCityHI(City, MaxLatitude, MinLongitude); - let x = (City.lon - MinLongitude) * 57; - let y = (MaxLatitude - City.lat) * 70; - - if (y < 30) y = 30; - if (y > 282) y = 282; - - if (x < 40) x = 40; - if (x > 580) x = 580; - - return { x, y }; - } - - static getXYForCityAK(City, MaxLatitude, MinLongitude) { - let x = (City.lon - MinLongitude) * 37; - let y = (MaxLatitude - City.lat) * 70; - - if (y < 30) y = 30; - if (y > 282) y = 282; - - if (x < 40) x = 40; - if (x > 580) x = 580; - return { x, y }; - } - - static getXYForCityHI(City, MaxLatitude, MinLongitude) { - let x = (City.lon - MinLongitude) * 57; - let y = (MaxLatitude - City.lat) * 70; - - if (y < 30) y = 30; - if (y > 282) y = 282; - - if (x < 40) x = 40; - if (x > 580) x = 580; - - return { x, y }; - } - - // to fit on the map, remove anything after punctuation and then limit to 15 characters - static formatCity(city) { - return city.match(/[^-;/\\,]*/)[0].substr(0, 12); - } - drawCanvas() { super.drawCanvas(); // break up data into useful values diff --git a/server/scripts/modules/travelforecast.mjs b/server/scripts/modules/travelforecast.mjs index 2669dc2..c93e2cd 100644 --- a/server/scripts/modules/travelforecast.mjs +++ b/server/scripts/modules/travelforecast.mjs @@ -112,7 +112,7 @@ class TravelForecast extends WeatherDisplay { // set up variables const cities = this.data; - this.elem.querySelector('.header .title.dual .bottom').innerHTML = `For ${TravelForecast.getTravelCitiesDayName(cities)}`; + this.elem.querySelector('.header .title.dual .bottom').innerHTML = `For ${getTravelCitiesDayName(cities)}`; this.finishDraw(); } @@ -140,24 +140,23 @@ class TravelForecast extends WeatherDisplay { this.elem.querySelector('.main').scrollTo(0, offsetY); } - static getTravelCitiesDayName(cities) { - // effectively returns early on the first found date - return cities.reduce((dayName, city) => { - if (city && dayName === '') { - // today or tomorrow - const day = DateTime.local().plus({ days: (city.today) ? 0 : 1 }); - // return the day - return day.toLocaleString({ weekday: 'long' }); - } - return dayName; - }, ''); - } - // necessary to get the lastest long canvas when scrolling getLongCanvas() { return this.longCanvas; } } +// effectively returns early on the first found date +const getTravelCitiesDayName = (cities) => cities.reduce((dayName, city) => { + if (city && dayName === '') { + // today or tomorrow + const day = DateTime.local().plus({ days: (city.today) ? 0 : 1 }); + // return the day + return day.toLocaleString({ weekday: 'long' }); + } + return dayName; +}, '') +; + // register display, not active by default registerDisplay(new TravelForecast(4, 'travel', false)); diff --git a/server/styles/main.css b/server/styles/main.css index 4f98240..94d18de 100644 --- a/server/styles/main.css +++ b/server/styles/main.css @@ -1 +1 @@ -@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff")}body{font-family:"Star4000"}@media(prefers-color-scheme: dark){body{background-color:#000;color:#fff}}@media(prefers-color-scheme: dark){body a{color:#add8e6}}input,button{font-family:"Star4000"}#imgGetGps{height:13px;vertical-align:middle}#txtAddress{width:490px;font-size:16pt;max-width:calc(100% - 8px)}@media(prefers-color-scheme: dark){#txtAddress{background-color:#000;color:#fff;border:1px solid #a9a9a9}}#btnGetGps,#btnGetLatLng,#btnClearQuery{font-size:16pt;border:1px solid #a9a9a9}@media(prefers-color-scheme: dark){#btnGetGps,#btnGetLatLng,#btnClearQuery{background-color:#000;color:#fff}}#btnGetGps img.dark{display:none}@media(prefers-color-scheme: dark){#btnGetGps img.dark{display:inline-block}}@media(prefers-color-scheme: dark){#btnGetGps img.light{display:none}}.autocomplete-suggestions{background-color:#fff;border:1px solid #000}.autocomplete-suggestion{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:16pt}.autocomplete-selected{background-color:blue;color:#fff}#divTwc{display:block;background-color:#000;color:#fff;width:100%;max-width:640px}#divTwcLeft{display:none;text-align:right;flex-direction:column;vertical-align:middle}#divTwcLeft>div{flex:1;padding-right:12px;display:flex;flex-direction:column;justify-content:center}#divTwcRight{text-align:left;display:none;flex-direction:column;vertical-align:middle}#divTwcRight>div{flex:1;padding-left:12px;display:flex;flex-direction:column;justify-content:center}#divTwcBottom{display:flex;flex-direction:row;background-color:#000;color:#fff;width:100%}@media(prefers-color-scheme: dark){#divTwcBottom{background-color:#303030}}#divTwcBottom>div{padding-left:6px;padding-right:6px}#divTwcBottomLeft{flex:1;text-align:left}#divTwcBottomMiddle{flex:0;text-align:center}#divTwcBottomRight{flex:1;text-align:right}#divTwcNavContainer{display:none}#divTwcNav{width:100%;display:flex;flex-direction:row;background-color:#000;color:#fff;max-width:640px}#divTwcNav>div{padding-left:6px;padding-right:6px}#divTwcNavLeft{flex:1;text-align:left}#divTwcNavMiddle{flex:0;text-align:center}#divTwcNavRight{flex:1;text-align:right}#imgPause1x,#imgPause2x{visibility:hidden;position:absolute}.HideCursor{cursor:none !important}#txtScrollText{width:475px}@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff")}@font-face{font-family:"Star 4 Radar";src:url("../fonts/Star 4 Radar.woff") format("woff")}@font-face{font-family:"Star4000 Extended";src:url("../fonts/Star4000 Extended.woff") format("woff")}@font-face{font-family:"Star4000LCN";src:url("../fonts/Star4000LCN.woff") format("woff")}@font-face{font-family:"Star4000 Large Compressed";src:url("../fonts/Star4000 Large Compressed.woff") format("woff")}@font-face{font-family:"Star4000 Large";src:url("../fonts/Star4000 Large.ttf") format("truetype")}@font-face{font-family:"Star4000 Small";src:url("../fonts/Star4000 Small.woff") format("woff")}#display{font-family:"Star4000";margin:0 0 0 0;width:100%}jsgif{display:none}#Star4000{font-family:"Star4000"}#Star4000Extended{font-family:"Star4000 Extended"}#Star4000LargeCompressed{font-family:"Star4000 Large Compressed"}#Star4000Large{font-family:"Star4000 Large"}#Star4000LargeCompressedNumbers{font-family:"Star4000LCN"}#Star4000Small{font-family:"Star4000 Small"}#Star4Radar{font-family:"Star 4 Radar"}#container{position:relative;width:100%;height:100%;background-image:url(../images/BackGround1_1.png)}#divTwc:-webkit-full-screen #container{background-image:none;width:unset;height:unset}#divTwc:-ms-fullscreen #container{background-image:none;width:unset;height:unset}#divTwc:fullscreen #container{background-image:none;width:unset;height:unset}#loading{width:640px;height:480px;max-width:100%;text-shadow:4px 4px #000;display:flex;align-items:center;text-align:center;justify-content:center}#loading .title{font-family:Star4000 Large;font-size:36px;color:#ff0;margin-bottom:40px}#loading .instructions{font-size:18pt}.heading{font-weight:bold;margin-top:15px}#enabledDisplays{margin-bottom:15px}#enabledDisplays label{display:block;max-width:300px}#divTwcBottom img{zoom:150%}#divTwc:-webkit-full-screen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-ms-fullscreen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:fullscreen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-webkit-full-screen #display{position:relative}#divTwc:-ms-fullscreen #display{position:relative}#divTwc:fullscreen #display{position:relative}#divTwc:-webkit-full-screen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:-ms-fullscreen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:fullscreen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}.navButton{cursor:pointer}.visible{visibility:visible;opacity:1;transition:opacity 1s linear}.hidden{visibility:hidden;opacity:0;transition:visibility 0s 1s,opacity 1s linear}.weather-display{width:640px;height:480px;overflow:hidden;position:relative;background-image:url(../images/BackGround1_1.png);height:0px}.weather-display.show{height:480px}.weather-display .template{display:none}.weather-display .header{width:640px;height:60px;padding-top:30px}.weather-display .header .title{color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000";font-size:24pt;position:absolute;width:250px}.weather-display .header .title.single{left:170px;top:25px}.weather-display .header .title.dual{left:170px}.weather-display .header .title.dual>div{position:absolute}.weather-display .header .title.dual .top{top:-3px}.weather-display .header .title.dual .bottom{top:26px}.weather-display .header .logo{top:30px;left:50px;position:absolute;z-index:10}.weather-display .header .noaa-logo{position:absolute;top:39px;left:356px}.weather-display .header .title.single{top:40px}.weather-display .header .date-time{white-space:pre;color:#fff;font-family:"Star4000 Small";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;left:415px;width:170px;text-align:right;position:absolute}.weather-display .header .date-time.date{padding-top:22px}.weather-display .main{position:relative}.weather-display .main.has-scroll{width:640px;height:310px;overflow:hidden}.weather-display .main.has-box{margin-left:64px;margin-right:64px;width:calc(100% - 128px)}.weather-display .scroll{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;width:640px;height:70px;overflow:hidden;margin-top:10px}.weather-display .scroll .fixed{font-family:"Star4000";font-size:24pt;margin-left:55px}.weather-display .main.current-weather.main .col{height:50px;width:255px;display:inline-block;margin-top:10px;position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.current-weather.main .col.left{font-family:"Star4000 Extended";font-size:24pt}.weather-display .main.current-weather.main .col.right{right:0px;font-family:"Star4000 Large";font-size:16pt;font-weight:bold}.weather-display .main.current-weather.main .col.right .row{margin-bottom:12px}.weather-display .main.current-weather.main .col.right .row .label,.weather-display .main.current-weather.main .col.right .row .value{display:inline-block}.weather-display .main.current-weather.main .col.right .row .label{margin-left:20px}.weather-display .main.current-weather.main .col.right .row .value{float:right;margin-right:10px}.weather-display .main.current-weather.main .center{text-align:center}.weather-display .main.current-weather.main .temp{font-family:"Star4000 Large";font-size:24pt}.weather-display .main.current-weather.main .icon{height:100px}.weather-display .main.current-weather.main .icon img{max-width:126px}.weather-display .main.current-weather.main .wind-container{margin-bottom:10px}.weather-display .main.current-weather.main .wind-container>div{width:45%;display:inline-block;margin:0px}.weather-display .main.current-weather.main .wind-container .wind-label{margin-left:5px}.weather-display .main.current-weather.main .wind-container .wind{text-align:right}.weather-display .main.current-weather.main .wind-gusts{margin-left:5px}.weather-display .main.current-weather.main .location{color:#ff0;margin-bottom:10px}#extended-forecast-html.weather-display{background-image:url("../images/BackGround2_1.png")}.weather-display .main.extended-forecast .day-container{margin-top:16px;margin-left:27px}.weather-display .main.extended-forecast .day{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding:5px;height:285px;width:155px;display:inline-block;margin:0px 15px;font-family:"Star4000";font-size:24pt}.weather-display .main.extended-forecast .day .date{text-transform:uppercase;text-align:center;color:#ff0}.weather-display .main.extended-forecast .day .condition{text-align:center;height:74px;margin-top:10px}.weather-display .main.extended-forecast .day .icon{text-align:center;height:75px}.weather-display .main.extended-forecast .day .icon img{max-height:75px}.weather-display .main.extended-forecast .day .temperatures{width:100%;margin-top:5px}.weather-display .main.extended-forecast .day .temperatures .temperature-block{display:inline-block;width:44%;vertical-align:top}.weather-display .main.extended-forecast .day .temperatures .temperature-block>div{text-align:center}.weather-display .main.extended-forecast .day .temperatures .temperature-block .value{font-family:"Star4000 Large";margin-top:4px}.weather-display .main.extended-forecast .day .temperatures .temperature-block.lo .label{color:#8080ff}.weather-display .main.extended-forecast .day .temperatures .temperature-block.hi .label{color:#ff0}.weather-display .main.hourly.main{overflow-y:hidden}.weather-display .main.hourly.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.hourly.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.hourly.main .column-headers .temp{left:355px}.weather-display .main.hourly.main .column-headers .like{left:435px}.weather-display .main.hourly.main .column-headers .wind{left:535px}.weather-display .main.hourly.main .hourly-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.hourly.main .hourly-lines .hourly-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.hourly.main .hourly-lines .hourly-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.hourly.main .hourly-lines .hourly-row .hour{left:25px}.weather-display .main.hourly.main .hourly-lines .hourly-row .icon{left:255px;width:70px;text-align:center;top:unset}.weather-display .main.hourly.main .hourly-lines .hourly-row .temp{left:355px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like{left:425px}.weather-display .main.hourly.main .hourly-lines .hourly-row .wind{left:505px;width:100px;text-align:right}#hourly-graph-html{background-image:url(../images/BackGround1_1_Chart.png)}#hourly-graph-html .header .right{position:absolute;top:35px;right:60px;width:360px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:right}#hourly-graph-html .header .right div{margin-top:-18px}#hourly-graph-html .header .right .temperature{color:red}#hourly-graph-html .header .right .cloud{color:#d3d3d3}#hourly-graph-html .header .right .rain{color:aqua}.weather-display .main.hourly-graph.main>div{position:absolute}.weather-display .main.hourly-graph.main .label{font-family:"Star4000 Small";font-size:24pt;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;margin-top:-15px;position:absolute}.weather-display .main.hourly-graph.main .x-axis{bottom:0px;left:0px;width:640px;height:20px}.weather-display .main.hourly-graph.main .x-axis .label{text-align:center;width:50px}.weather-display .main.hourly-graph.main .x-axis .label.l-1{left:25px}.weather-display .main.hourly-graph.main .x-axis .label.l-2{left:158px}.weather-display .main.hourly-graph.main .x-axis .label.l-3{left:291px}.weather-display .main.hourly-graph.main .x-axis .label.l-4{left:424px}.weather-display .main.hourly-graph.main .x-axis .label.l-5{left:557px}.weather-display .main.hourly-graph.main .chart{top:0px;left:50px}.weather-display .main.hourly-graph.main .chart img{width:532px;height:285px}.weather-display .main.hourly-graph.main .y-axis{top:0px;left:0px;width:50px;height:285px}.weather-display .main.hourly-graph.main .y-axis .label{text-align:right;right:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-1{top:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-2{top:140px}.weather-display .main.hourly-graph.main .y-axis .label.l-3{bottom:0px}.weather-display .main.hourly-graph.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly-graph.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.hourly-graph.main .column-headers .temp{left:355px}.weather-display .main.hourly-graph.main .column-headers .like{left:435px}.weather-display .main.hourly-graph.main .column-headers .wind{left:535px}.weather-display .main.travel.main{overflow-y:hidden}.weather-display .main.travel.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.travel.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.travel.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.travel.main .column-headers .temp{width:50px;text-align:center}.weather-display .main.travel.main .column-headers .temp.low{left:455px}.weather-display .main.travel.main .column-headers .temp.high{left:510px;width:60px}.weather-display .main.travel.main .travel-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.travel.main .travel-lines .travel-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.travel.main .travel-lines .travel-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.travel.main .travel-lines .travel-row .city{left:80px}.weather-display .main.travel.main .travel-lines .travel-row .icon{left:330px;width:70px;text-align:center;top:unset}.weather-display .main.travel.main .travel-lines .travel-row .icon img{max-width:47px}.weather-display .main.travel.main .travel-lines .travel-row .temp{width:50px;text-align:center}.weather-display .main.travel.main .travel-lines .travel-row .temp.low{left:455px}.weather-display .main.travel.main .travel-lines .travel-row .temp.high{left:510px;width:60px}.weather-display .latest-observations.main{overflow-y:hidden}.weather-display .latest-observations.main .column-headers{height:20px;position:absolute;width:100%}.weather-display .latest-observations.main .column-headers{top:0px}.weather-display .latest-observations.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;position:absolute;top:-14px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .latest-observations.main .column-headers .temp{display:none}.weather-display .latest-observations.main .column-headers .temp.show{display:inline-block}.weather-display .latest-observations.main .temp{left:230px}.weather-display .latest-observations.main .weather{left:280px}.weather-display .latest-observations.main .wind{left:430px}.weather-display .latest-observations.main .observation-lines{min-height:338px;padding-top:10px}.weather-display .latest-observations.main .observation-lines .observation-row{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;height:40px}.weather-display .latest-observations.main .observation-lines .observation-row>div{position:absolute;top:8px}.weather-display .latest-observations.main .observation-lines .observation-row .wind{white-space:pre;text-align:right}.weather-display .local-forecast .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:280px;overflow:hidden}.weather-display .local-forecast .forecasts{position:relative}.weather-display .local-forecast .forecast{font-family:"Star4000";font-size:24pt;text-transform:uppercase;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;min-height:280px;line-height:40px}.weather-display .progress{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000 Extended";font-size:19pt}.weather-display .progress .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:310px;overflow:hidden}.weather-display .progress .container .item{position:relative}.weather-display .progress .container .item .name{white-space:nowrap}.weather-display .progress .container .item .name::after{content:"........................................................................"}.weather-display .progress .container .item .links{position:absolute;text-align:right;right:0px;top:0px}.weather-display .progress .container .item .links>div{background-color:#26235a;display:none;padding-left:4px}.weather-display .progress .container .item .links .loading{color:#ff0}.weather-display .progress .container .item .links .press-here{color:lime;cursor:pointer}.weather-display .progress .container .item .links .failed{color:red}.weather-display .progress .container .item .links .no-data{color:silver}.weather-display .progress .container .item .links .disabled{color:silver}.weather-display .progress .container .item .links.loading .loading{display:block}.weather-display .progress .container .item .links.press-here .press-here{display:block}.weather-display .progress .container .item .links.failed .failed{display:block}.weather-display .progress .container .item .links.no-data .no-data{display:block}.weather-display .progress .container .item .links.disabled .disabled{display:block}@-webkit-keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}@keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}#progress-html.weather-display .scroll .progress-bar-container{border:2px solid #000;background-color:#fff;margin:20px auto;width:524px;position:relative;display:none}#progress-html.weather-display .scroll .progress-bar-container.show{display:block}#progress-html.weather-display .scroll .progress-bar-container .progress-bar{height:20px;margin:2px;width:520px;background:repeating-linear-gradient(90deg, #09246f 0px, #09246f 5px, #364ac0 5px, #364ac0 10px, #4f99f9 10px, #4f99f9 15px, #8ffdfa 15px, #8ffdfa 20px, #4f99f9 20px, #4f99f9 25px, #364ac0 25px, #364ac0 30px, #09246f 30px, #09246f 40px);-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:progress-scroll;animation-name:progress-scroll;-webkit-animation-timing-function:steps(8, end);animation-timing-function:steps(8, end)}#progress-html.weather-display .scroll .progress-bar-container .cover{position:absolute;top:0px;right:0px;background-color:#fff;width:100%;height:24px;transition:width 1s steps(6)}#radar-html.weather-display{background-image:url("../images/BackGround4_1.png")}#radar-html.weather-display .header{height:83px}#radar-html.weather-display .header .title.dual{color:#fff;font-family:"Arial",sans-serif;font-weight:bold;font-size:28pt;left:155px}#radar-html.weather-display .header .title.dual .top{top:-4px}#radar-html.weather-display .header .title.dual .bottom{top:31px}#radar-html.weather-display .header .right{position:absolute;right:0px;width:360px;margin-top:2px;font-family:"Star4000";font-size:18pt;font-weight:bold;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:center}#radar-html.weather-display .header .right .scale>div{display:inline-block}#radar-html.weather-display .header .right .scale-table{display:table-row;border-collapse:collapse}#radar-html.weather-display .header .right .scale-table .box{display:table-cell;border:2px solid #000;width:17px;height:24px;padding:0}#radar-html.weather-display .header .right .scale-table .box-1{background-color:#31d216}#radar-html.weather-display .header .right .scale-table .box-2{background-color:#1c8a12}#radar-html.weather-display .header .right .scale-table .box-3{background-color:#145a0f}#radar-html.weather-display .header .right .scale-table .box-4{background-color:#0a280a}#radar-html.weather-display .header .right .scale-table .box-5{background-color:#c4b346}#radar-html.weather-display .header .right .scale-table .box-6{background-color:#be4813}#radar-html.weather-display .header .right .scale-table .box-7{background-color:#ab0e0e}#radar-html.weather-display .header .right .scale-table .box-8{background-color:#731f04}#radar-html.weather-display .header .right .scale .text{position:relative;top:-5px}#radar-html.weather-display .header .right .time{position:relative;font-weight:normal;top:-14px;font-family:"Star4000 Small";font-size:24pt}.weather-display .main.radar{overflow:hidden;height:367px}.weather-display .main.radar .container .scroll-area{position:relative}#regional-forecast-html.weather-display{background-image:url("../images/BackGround5_1.png")}.weather-display .main.regional-forecast{position:relative}.weather-display .main.regional-forecast .map{position:absolute}.weather-display .main.regional-forecast .location{position:absolute;width:140px;margin-left:-40px;margin-top:-35px}.weather-display .main.regional-forecast .location>div{position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.regional-forecast .location .icon{top:26px;left:44px}.weather-display .main.regional-forecast .location .icon img{max-height:32px}.weather-display .main.regional-forecast .location .temp{font-family:"Star4000 Large";font-size:28px;color:#ff0;top:28px;text-align:right;width:40px}.weather-display .main.regional-forecast .location .city{font-family:Star4000;font-size:20px}#almanac-html.weather-display{background-image:url("../images/BackGround3_1.png")}.weather-display .main.almanac{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.almanac .sun{display:table;margin-left:50px;height:100px}.weather-display .main.almanac .sun>div{display:table-row;position:relative}.weather-display .main.almanac .sun>div>div{display:table-cell}.weather-display .main.almanac .sun .days{color:#ff0;text-align:right;top:-5px}.weather-display .main.almanac .sun .days .day{padding-right:10px}.weather-display .main.almanac .sun .times{text-align:right}.weather-display .main.almanac .sun .times .sun-time{width:200px}.weather-display .main.almanac .sun .times.times-1{top:-10px}.weather-display .main.almanac .sun .times.times-2{top:-15px}.weather-display .main.almanac .moon{position:relative;top:-10px;padding:0px 60px}.weather-display .main.almanac .moon .title{color:#ff0}.weather-display .main.almanac .moon .day{display:inline-block;text-align:center;width:130px}.weather-display .main.almanac .moon .day .icon{padding-left:10px}.weather-display .main.almanac .moon .day .date{position:relative;top:-10px}/*# sourceMappingURL=main.css.map */ \ No newline at end of file +@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff")}body{font-family:"Star4000"}@media(prefers-color-scheme: dark){body{background-color:#000;color:#fff}}@media(prefers-color-scheme: dark){body a{color:#add8e6}}input,button{font-family:"Star4000"}#imgGetGps{height:13px;vertical-align:middle}#txtAddress{width:490px;font-size:16pt;max-width:calc(100% - 8px)}@media(prefers-color-scheme: dark){#txtAddress{background-color:#000;color:#fff;border:1px solid #a9a9a9}}#btnGetGps,#btnGetLatLng,#btnClearQuery{font-size:16pt;border:1px solid #a9a9a9}@media(prefers-color-scheme: dark){#btnGetGps,#btnGetLatLng,#btnClearQuery{background-color:#000;color:#fff}}#btnGetGps img.dark{display:none}@media(prefers-color-scheme: dark){#btnGetGps img.dark{display:inline-block}}@media(prefers-color-scheme: dark){#btnGetGps img.light{display:none}}.autocomplete-suggestions{background-color:#fff;border:1px solid #000}@media(prefers-color-scheme: dark){.autocomplete-suggestions{background-color:#000}}.autocomplete-suggestion{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:16pt}.autocomplete-selected{background-color:blue;color:#fff}#divTwc{display:block;background-color:#000;color:#fff;width:100%;max-width:640px}#divTwcLeft{display:none;text-align:right;flex-direction:column;vertical-align:middle}#divTwcLeft>div{flex:1;padding-right:12px;display:flex;flex-direction:column;justify-content:center}#divTwcRight{text-align:left;display:none;flex-direction:column;vertical-align:middle}#divTwcRight>div{flex:1;padding-left:12px;display:flex;flex-direction:column;justify-content:center}#divTwcBottom{display:flex;flex-direction:row;background-color:#000;color:#fff;width:100%}@media(prefers-color-scheme: dark){#divTwcBottom{background-color:#303030}}#divTwcBottom>div{padding-left:6px;padding-right:6px}#divTwcBottomLeft{flex:1;text-align:left}#divTwcBottomMiddle{flex:0;text-align:center}#divTwcBottomRight{flex:1;text-align:right}#divTwcNavContainer{display:none}#divTwcNav{width:100%;display:flex;flex-direction:row;background-color:#000;color:#fff;max-width:640px}#divTwcNav>div{padding-left:6px;padding-right:6px}#divTwcNavLeft{flex:1;text-align:left}#divTwcNavMiddle{flex:0;text-align:center}#divTwcNavRight{flex:1;text-align:right}#imgPause1x,#imgPause2x{visibility:hidden;position:absolute}.HideCursor{cursor:none !important}#txtScrollText{width:475px}@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff")}@font-face{font-family:"Star 4 Radar";src:url("../fonts/Star 4 Radar.woff") format("woff")}@font-face{font-family:"Star4000 Extended";src:url("../fonts/Star4000 Extended.woff") format("woff")}@font-face{font-family:"Star4000LCN";src:url("../fonts/Star4000LCN.woff") format("woff")}@font-face{font-family:"Star4000 Large Compressed";src:url("../fonts/Star4000 Large Compressed.woff") format("woff")}@font-face{font-family:"Star4000 Large";src:url("../fonts/Star4000 Large.ttf") format("truetype")}@font-face{font-family:"Star4000 Small";src:url("../fonts/Star4000 Small.woff") format("woff")}#display{font-family:"Star4000";margin:0 0 0 0;width:100%}jsgif{display:none}#Star4000{font-family:"Star4000"}#Star4000Extended{font-family:"Star4000 Extended"}#Star4000LargeCompressed{font-family:"Star4000 Large Compressed"}#Star4000Large{font-family:"Star4000 Large"}#Star4000LargeCompressedNumbers{font-family:"Star4000LCN"}#Star4000Small{font-family:"Star4000 Small"}#Star4Radar{font-family:"Star 4 Radar"}#container{position:relative;width:100%;height:100%;background-image:url(../images/BackGround1_1.png)}#divTwc:-webkit-full-screen #container{background-image:none;width:unset;height:unset}#divTwc:-ms-fullscreen #container{background-image:none;width:unset;height:unset}#divTwc:fullscreen #container{background-image:none;width:unset;height:unset}#loading{width:640px;height:480px;max-width:100%;text-shadow:4px 4px #000;display:flex;align-items:center;text-align:center;justify-content:center}#loading .title{font-family:Star4000 Large;font-size:36px;color:#ff0;margin-bottom:40px}#loading .instructions{font-size:18pt}.heading{font-weight:bold;margin-top:15px}#enabledDisplays{margin-bottom:15px}#enabledDisplays label{display:block;max-width:300px}#divTwcBottom img{zoom:150%}#divTwc:-webkit-full-screen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-ms-fullscreen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:fullscreen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-webkit-full-screen #display{position:relative}#divTwc:-ms-fullscreen #display{position:relative}#divTwc:fullscreen #display{position:relative}#divTwc:-webkit-full-screen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:-ms-fullscreen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:fullscreen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}.navButton{cursor:pointer}.visible{visibility:visible;opacity:1;transition:opacity 1s linear}.hidden{visibility:hidden;opacity:0;transition:visibility 0s 1s,opacity 1s linear}.weather-display{width:640px;height:480px;overflow:hidden;position:relative;background-image:url(../images/BackGround1_1.png);height:0px}.weather-display.show{height:480px}.weather-display .template{display:none}.weather-display .header{width:640px;height:60px;padding-top:30px}.weather-display .header .title{color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000";font-size:24pt;position:absolute;width:250px}.weather-display .header .title.single{left:170px;top:25px}.weather-display .header .title.dual{left:170px}.weather-display .header .title.dual>div{position:absolute}.weather-display .header .title.dual .top{top:-3px}.weather-display .header .title.dual .bottom{top:26px}.weather-display .header .logo{top:30px;left:50px;position:absolute;z-index:10}.weather-display .header .noaa-logo{position:absolute;top:39px;left:356px}.weather-display .header .title.single{top:40px}.weather-display .header .date-time{white-space:pre;color:#fff;font-family:"Star4000 Small";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;left:415px;width:170px;text-align:right;position:absolute}.weather-display .header .date-time.date{padding-top:22px}.weather-display .main{position:relative}.weather-display .main.has-scroll{width:640px;height:310px;overflow:hidden}.weather-display .main.has-box{margin-left:64px;margin-right:64px;width:calc(100% - 128px)}.weather-display .scroll{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;width:640px;height:70px;overflow:hidden;margin-top:10px}.weather-display .scroll .fixed{font-family:"Star4000";font-size:24pt;margin-left:55px}.weather-display .main.current-weather.main .col{height:50px;width:255px;display:inline-block;margin-top:10px;position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.current-weather.main .col.left{font-family:"Star4000 Extended";font-size:24pt}.weather-display .main.current-weather.main .col.right{right:0px;font-family:"Star4000 Large";font-size:16pt;font-weight:bold}.weather-display .main.current-weather.main .col.right .row{margin-bottom:12px}.weather-display .main.current-weather.main .col.right .row .label,.weather-display .main.current-weather.main .col.right .row .value{display:inline-block}.weather-display .main.current-weather.main .col.right .row .label{margin-left:20px}.weather-display .main.current-weather.main .col.right .row .value{float:right;margin-right:10px}.weather-display .main.current-weather.main .center{text-align:center}.weather-display .main.current-weather.main .temp{font-family:"Star4000 Large";font-size:24pt}.weather-display .main.current-weather.main .icon{height:100px}.weather-display .main.current-weather.main .icon img{max-width:126px}.weather-display .main.current-weather.main .wind-container{margin-bottom:10px}.weather-display .main.current-weather.main .wind-container>div{width:45%;display:inline-block;margin:0px}.weather-display .main.current-weather.main .wind-container .wind-label{margin-left:5px}.weather-display .main.current-weather.main .wind-container .wind{text-align:right}.weather-display .main.current-weather.main .wind-gusts{margin-left:5px}.weather-display .main.current-weather.main .location{color:#ff0;margin-bottom:10px}#extended-forecast-html.weather-display{background-image:url("../images/BackGround2_1.png")}.weather-display .main.extended-forecast .day-container{margin-top:16px;margin-left:27px}.weather-display .main.extended-forecast .day{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding:5px;height:285px;width:155px;display:inline-block;margin:0px 15px;font-family:"Star4000";font-size:24pt}.weather-display .main.extended-forecast .day .date{text-transform:uppercase;text-align:center;color:#ff0}.weather-display .main.extended-forecast .day .condition{text-align:center;height:74px;margin-top:10px}.weather-display .main.extended-forecast .day .icon{text-align:center;height:75px}.weather-display .main.extended-forecast .day .icon img{max-height:75px}.weather-display .main.extended-forecast .day .temperatures{width:100%;margin-top:5px}.weather-display .main.extended-forecast .day .temperatures .temperature-block{display:inline-block;width:44%;vertical-align:top}.weather-display .main.extended-forecast .day .temperatures .temperature-block>div{text-align:center}.weather-display .main.extended-forecast .day .temperatures .temperature-block .value{font-family:"Star4000 Large";margin-top:4px}.weather-display .main.extended-forecast .day .temperatures .temperature-block.lo .label{color:#8080ff}.weather-display .main.extended-forecast .day .temperatures .temperature-block.hi .label{color:#ff0}.weather-display .main.hourly.main{overflow-y:hidden}.weather-display .main.hourly.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.hourly.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.hourly.main .column-headers .temp{left:355px}.weather-display .main.hourly.main .column-headers .like{left:435px}.weather-display .main.hourly.main .column-headers .wind{left:535px}.weather-display .main.hourly.main .hourly-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.hourly.main .hourly-lines .hourly-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.hourly.main .hourly-lines .hourly-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.hourly.main .hourly-lines .hourly-row .hour{left:25px}.weather-display .main.hourly.main .hourly-lines .hourly-row .icon{left:255px;width:70px;text-align:center;top:unset}.weather-display .main.hourly.main .hourly-lines .hourly-row .temp{left:355px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like{left:425px}.weather-display .main.hourly.main .hourly-lines .hourly-row .wind{left:505px;width:100px;text-align:right}#hourly-graph-html{background-image:url(../images/BackGround1_1_Chart.png)}#hourly-graph-html .header .right{position:absolute;top:35px;right:60px;width:360px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:right}#hourly-graph-html .header .right div{margin-top:-18px}#hourly-graph-html .header .right .temperature{color:red}#hourly-graph-html .header .right .cloud{color:#d3d3d3}#hourly-graph-html .header .right .rain{color:aqua}.weather-display .main.hourly-graph.main>div{position:absolute}.weather-display .main.hourly-graph.main .label{font-family:"Star4000 Small";font-size:24pt;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;margin-top:-15px;position:absolute}.weather-display .main.hourly-graph.main .x-axis{bottom:0px;left:0px;width:640px;height:20px}.weather-display .main.hourly-graph.main .x-axis .label{text-align:center;width:50px}.weather-display .main.hourly-graph.main .x-axis .label.l-1{left:25px}.weather-display .main.hourly-graph.main .x-axis .label.l-2{left:158px}.weather-display .main.hourly-graph.main .x-axis .label.l-3{left:291px}.weather-display .main.hourly-graph.main .x-axis .label.l-4{left:424px}.weather-display .main.hourly-graph.main .x-axis .label.l-5{left:557px}.weather-display .main.hourly-graph.main .chart{top:0px;left:50px}.weather-display .main.hourly-graph.main .chart img{width:532px;height:285px}.weather-display .main.hourly-graph.main .y-axis{top:0px;left:0px;width:50px;height:285px}.weather-display .main.hourly-graph.main .y-axis .label{text-align:right;right:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-1{top:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-2{top:140px}.weather-display .main.hourly-graph.main .y-axis .label.l-3{bottom:0px}.weather-display .main.hourly-graph.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly-graph.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.hourly-graph.main .column-headers .temp{left:355px}.weather-display .main.hourly-graph.main .column-headers .like{left:435px}.weather-display .main.hourly-graph.main .column-headers .wind{left:535px}.weather-display .main.travel.main{overflow-y:hidden}.weather-display .main.travel.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.travel.main .column-headers{position:-webkit-sticky;position:sticky;top:0px;z-index:5}.weather-display .main.travel.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.travel.main .column-headers .temp{width:50px;text-align:center}.weather-display .main.travel.main .column-headers .temp.low{left:455px}.weather-display .main.travel.main .column-headers .temp.high{left:510px;width:60px}.weather-display .main.travel.main .travel-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.travel.main .travel-lines .travel-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.travel.main .travel-lines .travel-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.travel.main .travel-lines .travel-row .city{left:80px}.weather-display .main.travel.main .travel-lines .travel-row .icon{left:330px;width:70px;text-align:center;top:unset}.weather-display .main.travel.main .travel-lines .travel-row .icon img{max-width:47px}.weather-display .main.travel.main .travel-lines .travel-row .temp{width:50px;text-align:center}.weather-display .main.travel.main .travel-lines .travel-row .temp.low{left:455px}.weather-display .main.travel.main .travel-lines .travel-row .temp.high{left:510px;width:60px}.weather-display .latest-observations.main{overflow-y:hidden}.weather-display .latest-observations.main .column-headers{height:20px;position:absolute;width:100%}.weather-display .latest-observations.main .column-headers{top:0px}.weather-display .latest-observations.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;position:absolute;top:-14px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .latest-observations.main .column-headers .temp{display:none}.weather-display .latest-observations.main .column-headers .temp.show{display:inline-block}.weather-display .latest-observations.main .temp{left:230px}.weather-display .latest-observations.main .weather{left:280px}.weather-display .latest-observations.main .wind{left:430px}.weather-display .latest-observations.main .observation-lines{min-height:338px;padding-top:10px}.weather-display .latest-observations.main .observation-lines .observation-row{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;height:40px}.weather-display .latest-observations.main .observation-lines .observation-row>div{position:absolute;top:8px}.weather-display .latest-observations.main .observation-lines .observation-row .wind{white-space:pre;text-align:right}.weather-display .local-forecast .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:280px;overflow:hidden}.weather-display .local-forecast .forecasts{position:relative}.weather-display .local-forecast .forecast{font-family:"Star4000";font-size:24pt;text-transform:uppercase;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;min-height:280px;line-height:40px}.weather-display .progress{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000 Extended";font-size:19pt}.weather-display .progress .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:310px;overflow:hidden}.weather-display .progress .container .item{position:relative}.weather-display .progress .container .item .name{white-space:nowrap}.weather-display .progress .container .item .name::after{content:"........................................................................"}.weather-display .progress .container .item .links{position:absolute;text-align:right;right:0px;top:0px}.weather-display .progress .container .item .links>div{background-color:#26235a;display:none;padding-left:4px}.weather-display .progress .container .item .links .loading{color:#ff0}.weather-display .progress .container .item .links .press-here{color:lime;cursor:pointer}.weather-display .progress .container .item .links .failed{color:red}.weather-display .progress .container .item .links .no-data{color:silver}.weather-display .progress .container .item .links .disabled{color:silver}.weather-display .progress .container .item .links.loading .loading{display:block}.weather-display .progress .container .item .links.press-here .press-here{display:block}.weather-display .progress .container .item .links.failed .failed{display:block}.weather-display .progress .container .item .links.no-data .no-data{display:block}.weather-display .progress .container .item .links.disabled .disabled{display:block}@-webkit-keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}@keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}#progress-html.weather-display .scroll .progress-bar-container{border:2px solid #000;background-color:#fff;margin:20px auto;width:524px;position:relative;display:none}#progress-html.weather-display .scroll .progress-bar-container.show{display:block}#progress-html.weather-display .scroll .progress-bar-container .progress-bar{height:20px;margin:2px;width:520px;background:repeating-linear-gradient(90deg, #09246f 0px, #09246f 5px, #364ac0 5px, #364ac0 10px, #4f99f9 10px, #4f99f9 15px, #8ffdfa 15px, #8ffdfa 20px, #4f99f9 20px, #4f99f9 25px, #364ac0 25px, #364ac0 30px, #09246f 30px, #09246f 40px);-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:progress-scroll;animation-name:progress-scroll;-webkit-animation-timing-function:steps(8, end);animation-timing-function:steps(8, end)}#progress-html.weather-display .scroll .progress-bar-container .cover{position:absolute;top:0px;right:0px;background-color:#fff;width:100%;height:24px;transition:width 1s steps(6)}#radar-html.weather-display{background-image:url("../images/BackGround4_1.png")}#radar-html.weather-display .header{height:83px}#radar-html.weather-display .header .title.dual{color:#fff;font-family:"Arial",sans-serif;font-weight:bold;font-size:28pt;left:155px}#radar-html.weather-display .header .title.dual .top{top:-4px}#radar-html.weather-display .header .title.dual .bottom{top:31px}#radar-html.weather-display .header .right{position:absolute;right:0px;width:360px;margin-top:2px;font-family:"Star4000";font-size:18pt;font-weight:bold;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:center}#radar-html.weather-display .header .right .scale>div{display:inline-block}#radar-html.weather-display .header .right .scale-table{display:table-row;border-collapse:collapse}#radar-html.weather-display .header .right .scale-table .box{display:table-cell;border:2px solid #000;width:17px;height:24px;padding:0}#radar-html.weather-display .header .right .scale-table .box-1{background-color:#31d216}#radar-html.weather-display .header .right .scale-table .box-2{background-color:#1c8a12}#radar-html.weather-display .header .right .scale-table .box-3{background-color:#145a0f}#radar-html.weather-display .header .right .scale-table .box-4{background-color:#0a280a}#radar-html.weather-display .header .right .scale-table .box-5{background-color:#c4b346}#radar-html.weather-display .header .right .scale-table .box-6{background-color:#be4813}#radar-html.weather-display .header .right .scale-table .box-7{background-color:#ab0e0e}#radar-html.weather-display .header .right .scale-table .box-8{background-color:#731f04}#radar-html.weather-display .header .right .scale .text{position:relative;top:-5px}#radar-html.weather-display .header .right .time{position:relative;font-weight:normal;top:-14px;font-family:"Star4000 Small";font-size:24pt}.weather-display .main.radar{overflow:hidden;height:367px}.weather-display .main.radar .container .scroll-area{position:relative}#regional-forecast-html.weather-display{background-image:url("../images/BackGround5_1.png")}.weather-display .main.regional-forecast{position:relative}.weather-display .main.regional-forecast .map{position:absolute}.weather-display .main.regional-forecast .location{position:absolute;width:140px;margin-left:-40px;margin-top:-35px}.weather-display .main.regional-forecast .location>div{position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.regional-forecast .location .icon{top:26px;left:44px}.weather-display .main.regional-forecast .location .icon img{max-height:32px}.weather-display .main.regional-forecast .location .temp{font-family:"Star4000 Large";font-size:28px;color:#ff0;top:28px;text-align:right;width:40px}.weather-display .main.regional-forecast .location .city{font-family:Star4000;font-size:20px}#almanac-html.weather-display{background-image:url("../images/BackGround3_1.png")}.weather-display .main.almanac{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.almanac .sun{display:table;margin-left:50px;height:100px}.weather-display .main.almanac .sun>div{display:table-row;position:relative}.weather-display .main.almanac .sun>div>div{display:table-cell}.weather-display .main.almanac .sun .days{color:#ff0;text-align:right;top:-5px}.weather-display .main.almanac .sun .days .day{padding-right:10px}.weather-display .main.almanac .sun .times{text-align:right}.weather-display .main.almanac .sun .times .sun-time{width:200px}.weather-display .main.almanac .sun .times.times-1{top:-10px}.weather-display .main.almanac .sun .times.times-2{top:-15px}.weather-display .main.almanac .moon{position:relative;top:-10px;padding:0px 60px}.weather-display .main.almanac .moon .title{color:#ff0}.weather-display .main.almanac .moon .day{display:inline-block;text-align:center;width:130px}.weather-display .main.almanac .moon .day .icon{padding-left:10px}.weather-display .main.almanac .moon .day .date{position:relative;top:-10px}/*# sourceMappingURL=main.css.map */ \ No newline at end of file diff --git a/server/styles/main.css.map b/server/styles/main.css.map index b0dc8db..7147813 100644 --- a/server/styles/main.css.map +++ b/server/styles/main.css.map @@ -1 +1 @@ -{"version":3,"sources":["scss/_page.scss","scss/_weather-display.scss","scss/shared/_colors.scss","scss/shared/_utils.scss","scss/_current-weather.scss","scss/_extended-forecast.scss","scss/_hourly.scss","scss/_hourly-graph.scss","scss/_travel.scss","scss/_latest-observations.scss","scss/_local-forecast.scss","scss/_progress.scss","scss/_radar.scss","scss/_regional-forecast.scss","scss/_almanac.scss"],"names":[],"mappings":"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","file":"main.css"} \ No newline at end of file +{"version":3,"sources":["scss/_page.scss","scss/_weather-display.scss","scss/shared/_colors.scss","scss/shared/_utils.scss","scss/_current-weather.scss","scss/_extended-forecast.scss","scss/_hourly.scss","scss/_hourly-graph.scss","scss/_travel.scss","scss/_latest-observations.scss","scss/_local-forecast.scss","scss/_progress.scss","scss/_radar.scss","scss/_regional-forecast.scss","scss/_almanac.scss"],"names":[],"mappings":"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","file":"main.css"} \ No newline at end of file diff --git a/server/styles/scss/_page.scss b/server/styles/scss/_page.scss index bae6619..05c4956 100644 --- a/server/styles/scss/_page.scss +++ b/server/styles/scss/_page.scss @@ -73,7 +73,10 @@ button { .autocomplete-suggestions { background-color: #ffffff; border: 1px solid #000000; - /*overflow: auto;*/ + + @media (prefers-color-scheme: dark) { + background-color: #000000; + } } .autocomplete-suggestion {