travel cities

This commit is contained in:
Matt Walsh 2022-09-23 15:12:10 -05:00
parent ed09d683d3
commit 3d7e93947b
9 changed files with 147 additions and 77 deletions

View file

@ -99,7 +99,7 @@ const navigation = (() => {
currentWeather, currentWeather,
new LatestObservations(1, 'latest-observations'), new LatestObservations(1, 'latest-observations'),
new Hourly(2, 'hourly'), new Hourly(2, 'hourly'),
new TravelForecast(3, 'travelForecast', false), // not active by default new TravelForecast(3, 'travel', false), // not active by default
new RegionalForecast(4, 'regional-forecast'), new RegionalForecast(4, 'regional-forecast'),
new LocalForecast(5, 'local-forecast'), new LocalForecast(5, 'local-forecast'),
new ExtendedForecast(6, 'extended-forecast'), new ExtendedForecast(6, 'extended-forecast'),

View file

@ -1,16 +1,11 @@
// travel forecast display // travel forecast display
/* globals WeatherDisplay, utils, STATUS, UNITS, draw, navigation, icons, luxon, TravelCities */ /* globals WeatherDisplay, utils, STATUS, UNITS, navigation, icons, luxon, TravelCities */
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
class TravelForecast extends WeatherDisplay { class TravelForecast extends WeatherDisplay {
constructor(navId, elemId, defaultActive) { constructor(navId, elemId, defaultActive) {
// special height and width for scrolling // special height and width for scrolling
super(navId, elemId, 'Travel Forecast', defaultActive); super(navId, elemId, 'Travel Forecast', defaultActive, true);
// pre-load background image (returns promise)
this.backgroundImage = utils.image.load('images/BackGround6_1.png');
// height of one city in the travel forecast
this.cityHeight = 72;
// set up the timing // set up the timing
this.timing.baseDelay = 20; this.timing.baseDelay = 20;
@ -18,7 +13,7 @@ class TravelForecast extends WeatherDisplay {
const pagesFloat = TravelCities.length / 4; const pagesFloat = TravelCities.length / 4;
const pages = Math.floor(pagesFloat) - 2; // first page is already displayed, last page doesn't happen const pages = Math.floor(pagesFloat) - 2; // first page is already displayed, last page doesn't happen
const extra = pages % 1; const extra = pages % 1;
const timingStep = this.cityHeight * 4; const timingStep = 75 * 4;
this.timing.delay = [150 + timingStep]; this.timing.delay = [150 + timingStep];
// add additional pages // add additional pages
for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep); for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep);
@ -69,47 +64,22 @@ class TravelForecast extends WeatherDisplay {
} }
async drawLongCanvas() { async drawLongCanvas() {
// create the "long" canvas if necessary // get the element and populate
if (!this.longCanvas) { const list = this.elem.querySelector('.travel-lines');
this.longCanvas = document.createElement('canvas'); list.innerHTML = '';
this.longCanvas.width = 640;
this.longCanvas.height = 1728;
this.longContext = this.longCanvas.getContext('2d');
this.longCanvasGifs = [];
}
// stop all gifs
this.longCanvasGifs.forEach((gif) => gif.pause());
// delete the gifs
this.longCanvasGifs.length = 0;
// set up variables // set up variables
const cities = this.data; const cities = this.data;
// clean up existing gifs const lines = cities.map((city) => {
this.gifs.forEach((gif) => gif.pause()); const fillValues = {};
// delete the gifs
this.gifs.length = 0;
this.longContext.clearRect(0, 0, this.longCanvas.width, this.longCanvas.height);
// draw the "long" canvas with all cities
draw.box(this.longContext, 'rgb(35, 50, 112)', 0, 0, 640, TravelCities.length * this.cityHeight);
for (let i = 0; i <= 4; i += 1) {
const y = i * 346;
draw.horizontalGradient(this.longContext, 0, y, 640, y + 346, '#102080', '#001040');
}
await Promise.all(cities.map(async (city, index) => {
// calculate base y value
const y = 50 + this.cityHeight * index;
// city name // city name
draw.text(this.longContext, 'Star4000 Large Compressed', '24pt', '#FFFF00', 80, y, city.name, 2); fillValues.city = city;
// check for forecast data // check for forecast data
if (city.icon) { if (city.icon) {
fillValues.city = city.name;
// get temperatures and convert if necessary // get temperatures and convert if necessary
let { low, high } = city; let { low, high } = city;
@ -122,25 +92,16 @@ class TravelForecast extends WeatherDisplay {
const lowString = Math.round(low).toString(); const lowString = Math.round(low).toString();
const highString = Math.round(high).toString(); const highString = Math.round(high).toString();
const xLow = (500 - (lowString.length * 20)); fillValues.low = lowString;
draw.text(this.longContext, 'Star4000 Large', '24pt', '#FFFF00', xLow, y, lowString, 2); fillValues.high = highString;
const xHigh = (560 - (highString.length * 20)); fillValues.icon = { type: 'img', src: city.icon };
draw.text(this.longContext, 'Star4000 Large', '24pt', '#FFFF00', xHigh, y, highString, 2);
this.longCanvasGifs.push(await utils.image.superGifAsync({
src: city.icon,
auto_play: true,
canvas: this.longCanvas,
x: 330,
y: y - 35,
max_width: 47,
}));
} else { } else {
draw.text(this.longContext, 'Star4000 Small', '24pt', '#FFFFFF', 400, y - 18, 'NO TRAVEL', 2); fillValues.error = 'NO TRAVEL DATA AVAILABLE';
draw.text(this.longContext, 'Star4000 Small', '24pt', '#FFFFFF', 400, y, 'DATA AVAILABLE', 2);
} }
})); return this.fillTemplate('travel-row', fillValues);
});
list.append(...lines);
} }
async drawCanvas() { async drawCanvas() {
@ -151,18 +112,7 @@ class TravelForecast extends WeatherDisplay {
// set up variables // set up variables
const cities = this.data; const cities = this.data;
// draw the standard context this.elem.querySelector('.header .title.dual .bottom').innerHTML = `For ${TravelForecast.getTravelCitiesDayName(cities)}`;
this.context.drawImage(await this.backgroundImage, 0, 0);
draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2);
draw.triangle(this.context, 'rgb(28, 10, 87)', 500, 30, 450, 90, 500, 90);
draw.titleText(this.context, 'Travel Forecast', `For ${TravelForecast.getTravelCitiesDayName(cities)}`);
draw.text(this.context, 'Star4000 Small', '24pt', '#FFFF00', 455, 105, 'LOW', 2);
draw.text(this.context, 'Star4000 Small', '24pt', '#FFFF00', 510, 105, 'HIGH', 2);
// copy the scrolled portion of the canvas for the initial run before the scrolling starts
this.context.drawImage(this.longCanvas, 0, 0, 640, 289, 0, 110, 640, 289);
this.finishDraw(); this.finishDraw();
} }
@ -180,17 +130,14 @@ class TravelForecast extends WeatherDisplay {
// base count change callback // base count change callback
baseCountChange(count) { baseCountChange(count) {
// get a fresh canvas
const longCanvas = this.getLongCanvas();
// calculate scroll offset and don't go past end // calculate scroll offset and don't go past end
let offsetY = Math.min(longCanvas.height - 289, (count - 150)); let offsetY = Math.min(this.elem.querySelector('.travel-lines').getBoundingClientRect().height - 289, (count - 150));
// don't let offset go negative // don't let offset go negative
if (offsetY < 0) offsetY = 0; if (offsetY < 0) offsetY = 0;
// copy the scrolled portion of the canvas // copy the scrolled portion of the canvas
this.context.drawImage(longCanvas, 0, offsetY, 640, 289, 0, 110, 640, 289); this.elem.querySelector('.main').scrollTo(0, offsetY);
} }
static getTravelCitiesDayName(cities) { static getTravelCitiesDayName(cities) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -22,7 +22,7 @@
&.right { &.right {
right: 0px; right: 0px;
font-family: 'Star4000 Large'; font-family: 'Star4000 Large';
font-size: 20px; font-size: 16pt;
font-weight: bold; font-weight: bold;
.row { .row {

View file

@ -0,0 +1,103 @@
@use 'shared/_colors'as c;
@use 'shared/_utils'as u;
.weather-display .main.travel {
&.main {
overflow-y: hidden;
.column-headers {
background-color: c.$column-header;
height: 20px;
position: absolute;
width: 100%;
}
.column-headers {
position: sticky;
top: 0px;
z-index: 5;
div {
display: inline-block;
font-family: 'Star4000 Small';
font-size: 24pt;
color: c.$column-header-text;
position: absolute;
top: -14px;
z-index: 5;
@include u.text-shadow();
}
.temp {
width: 50px;
text-align: center;
&.low {
left: 455px;
}
&.high {
left: 510px;
width: 60px;
}
}
}
.travel-lines {
min-height: 338px;
padding-top: 10px;
background: repeating-linear-gradient(0deg, c.$gradient-main-background-2 0px,
c.$gradient-main-background-1 136px,
c.$gradient-main-background-1 202px,
c.$gradient-main-background-2 338px,
);
.travel-row {
font-family: 'Star4000 Large';
font-size: 24pt;
height: 72px;
color: c.$title-color;
@include u.text-shadow();
position: relative;
>div {
position: absolute;
white-space: pre;
top: 8px;
}
.city {
left: 80px;
}
.icon {
left: 330px;
width: 70px;
text-align: center;
top: unset;
img {
max-width: 47px;
}
}
.temp {
width: 50px;
text-align: center;
&.low {
left: 455px;
}
&.high {
left: 510px;
width: 60px;
}
}
}
}
}
}

View file

@ -3,6 +3,7 @@
@import 'current-weather'; @import 'current-weather';
@import 'extended-forecast'; @import 'extended-forecast';
@import 'hourly'; @import 'hourly';
@import 'travel';
@import 'latest-observations'; @import 'latest-observations';
@import 'local-forecast'; @import 'local-forecast';
@import 'progress'; @import 'progress';

View file

@ -92,6 +92,9 @@
<div id="hourly-html" class="weather-display"> <div id="hourly-html" class="weather-display">
<%- include('partials/hourly.ejs') %> <%- include('partials/hourly.ejs') %>
</div> </div>
<div id="travel-html" class="weather-display">
<%- include('partials/travel.ejs') %>
</div>
<div id="current-weather-html" class="weather-display"> <div id="current-weather-html" class="weather-display">
<%- include('partials/current-weather.ejs') %> <%- include('partials/current-weather.ejs') %>
</div> </div>

16
views/partials/travel.ejs Normal file
View file

@ -0,0 +1,16 @@
<%- include('header.ejs', {titleDual: {top: 'Travel Forecast', bottom: 'For '} , hasTime: true }) %>
<div class="main has-scroll travel">
<div class="column-headers">
<div class="temp low">LOW</div>
<div class="temp high">HIGH</div>
</div>
<div class="travel-lines">
<div class="travel-row template">
<div class="city"></div>
<div class="icon"><img /></div>
<div class="temp low"></div>
<div class="temp high"></div>
</div>
</div>
</div>
<%- include('scroll.ejs') %>