forward/back navigation through travel forecast with timing
This commit is contained in:
parent
f27db7c66e
commit
81378359c9
|
@ -10,7 +10,7 @@ This project aims to bring back the feel of the 90's with a weather forecast tha
|
|||
|
||||
This project is based on the work of [Mike Battaglia](https://github.com/vbguyny/ws4kp). It was forked from his work in August 2020.
|
||||
|
||||
* Mike Battaglia For the original project and all of the code which draws the weather displays. This code remains largely intact and was a huge amount of work to get exactly right.
|
||||
* Mike Battaglia for the original project and all of the code which draws the weather displays. This code remains largely intact and was a huge amount of work to get exactly right. He's also responsible for all of the background graphics including the maps used in the application.
|
||||
* The team at [TWCClassics](https://twcclassics.com/) for several resources.
|
||||
* A [font](https://twcclassics.com/downloads.html) set used on the original WeatherStar 4000
|
||||
* [Icon](https://twcclassics.com/downloads.html) sets
|
||||
|
|
|
@ -15,6 +15,7 @@ class LatestObservations extends WeatherDisplay {
|
|||
}
|
||||
|
||||
async getData(weatherParameters) {
|
||||
super.getData();
|
||||
// calculate distance to each station
|
||||
const stationsByDistance = Object.keys(_StationInfo).map(key => {
|
||||
const station = _StationInfo[key];
|
||||
|
|
|
@ -9,15 +9,30 @@ class TravelForecast extends WeatherDisplay {
|
|||
// 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
|
||||
this.timing.baseDelay = 20;
|
||||
// page sizes are 4 cities, calculate the number of pages necessary plus overflow
|
||||
const pagesFloat = _TravelCities.length/4;
|
||||
const pages = Math.floor(pagesFloat) - 1; // first page is already displayed
|
||||
const extra = pages%1;
|
||||
const timingStep = this.cityHeight*4;
|
||||
this.timing.delay = [150];
|
||||
// add additional pages
|
||||
for (let i = 0; i < pages; i++) this.timing.delay.push(timingStep);
|
||||
// add the extra (not exactly 4 pages portion)
|
||||
if (extra !== 0) this.timing.delay.push(Math.round(this.extra*this.cityHeight));
|
||||
// add the final 3 second delay
|
||||
this.timing.delay.push(150);
|
||||
|
||||
// get the data
|
||||
this.getData(weatherParameters);
|
||||
|
||||
// scrolling tracking
|
||||
this.scrollCount = 0;
|
||||
this.endDelay = 0;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
super.getData();
|
||||
const forecastPromises = _TravelCities.map(async city => {
|
||||
try {
|
||||
// get point then forecast
|
||||
|
@ -70,7 +85,7 @@ class TravelForecast extends WeatherDisplay {
|
|||
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, 1728);
|
||||
draw.box(this.longContext, 'rgb(35, 50, 112)', 0, 0, 640, _TravelCities.length*this.cityHeight);
|
||||
|
||||
for (let i = 0; i <= 4; i++) {
|
||||
const y = i * 346;
|
||||
|
@ -79,7 +94,7 @@ class TravelForecast extends WeatherDisplay {
|
|||
|
||||
await Promise.all(cities.map(async (city, index) => {
|
||||
// calculate base y value
|
||||
const y = 50+72*index;
|
||||
const y = 50+this.cityHeight*index;
|
||||
|
||||
// city name
|
||||
draw.text(this.longContext, 'Star4000 Large Compressed', '24pt', '#FFFF00', 80, y, city.name, 2);
|
||||
|
@ -134,34 +149,30 @@ class TravelForecast extends WeatherDisplay {
|
|||
// 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);
|
||||
|
||||
// set up scrolling one time
|
||||
if (!this.scrollInterval) {
|
||||
this.scrollInterval = window.setInterval(() => {
|
||||
if (this.isActive()) {
|
||||
// get a fresh canvas
|
||||
const longCanvas = this.getLongCanvas();
|
||||
// increment scrolling
|
||||
this.scrollCount++;
|
||||
// wait 3 seconds at begining
|
||||
if (this.scrollCount < 150) return;
|
||||
// calculate scroll offset and don't go past end of canvas
|
||||
const offsetY = Math.min(longCanvas.height-289, (this.scrollCount-150));
|
||||
// copy the scrolled portion of the canvas
|
||||
this.context.drawImage(longCanvas, 0, offsetY, 640, 289, 0, 110, 640, 289);
|
||||
// track end of scrolling for 3 seconds
|
||||
if (offsetY >= longCanvas.height-289) this.endDelay++;
|
||||
// TODO: report playback done
|
||||
} else {
|
||||
// reset scroll to top of image
|
||||
this.scrollCount = 0;
|
||||
this.endDelay = 0;
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
this.finishDraw();
|
||||
this.setStatus(STATUS.loaded);
|
||||
}
|
||||
|
||||
// screen index change callback just runs the base count callback
|
||||
screenIndexChange() {
|
||||
this.baseCountChange(this.navBaseCount);
|
||||
}
|
||||
|
||||
// base count change callback
|
||||
baseCountChange(count) {
|
||||
// get a fresh canvas
|
||||
const longCanvas = this.getLongCanvas();
|
||||
|
||||
// calculate scroll offset and don't go past end
|
||||
let offsetY = Math.min(longCanvas.height-289, (count-this.timing.delay[0]));
|
||||
|
||||
// don't let offset go negative
|
||||
if (offsetY < 0) offsetY = 0;
|
||||
|
||||
// copy the scrolled portion of the canvas
|
||||
this.context.drawImage(longCanvas, 0, offsetY, 640, 289, 0, 110, 640, 289);
|
||||
}
|
||||
|
||||
getTravelCitiesDayName(cities) {
|
||||
const {DateTime} = luxon;
|
||||
// effectively returns early on the first found date
|
||||
|
|
|
@ -63,6 +63,22 @@ class WeatherDisplay {
|
|||
this.data = undefined;
|
||||
// set status
|
||||
this.setStatus(STATUS.loading);
|
||||
|
||||
// set up the timing delays
|
||||
if (Array.isArray(this.timing.delay) && typeof this.timing.delay[0] === 'number') {
|
||||
// array is defined as how long each screen should be displayed. This needs to be converted into total time for use here
|
||||
if (!this.timing.fullDelay) {
|
||||
let sum = 0;
|
||||
this.timing.fullDelay = this.timing.delay.map(val => {
|
||||
const calc = sum + val;
|
||||
sum += val;
|
||||
return calc;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// update total screens
|
||||
if (Array.isArray(this.timing.delay)) this.timing.totalScreens = this.timing.delay.length;
|
||||
}
|
||||
|
||||
drawCanvas() {
|
||||
|
@ -216,6 +232,9 @@ class WeatherDisplay {
|
|||
// reset timing
|
||||
this.startNavCount(navigation.isPlaying());
|
||||
|
||||
// if there was a command the canvas has already been drawn
|
||||
if (navCmd) return;
|
||||
|
||||
// refresh the canvas (incase the screen index changed)
|
||||
if (navCmd) this.drawCanvas();
|
||||
}
|
||||
|
@ -244,8 +263,8 @@ class WeatherDisplay {
|
|||
// increment the base count
|
||||
this.navBaseCount++;
|
||||
|
||||
// update total screens
|
||||
if (Array.isArray(this.timing.delay)) this.timing.totalScreens = this.timing.delay.length;
|
||||
// call base count change if available for this function
|
||||
if (this.baseCountChange) this.baseCountChange(this.navBaseCount);
|
||||
|
||||
// determine type of timing
|
||||
// simple delay
|
||||
|
@ -253,6 +272,16 @@ class WeatherDisplay {
|
|||
this.navNext();
|
||||
return;
|
||||
}
|
||||
|
||||
// array of timing integers
|
||||
if (Array.isArray(this.timing.delay) && typeof this.timing.delay[0] === 'number') {
|
||||
// scan the array for a matching number and calculate new screen index from the number
|
||||
const timingMatch = this.timing.fullDelay.indexOf(this.navBaseCount);
|
||||
// if not found return
|
||||
if (timingMatch < 0) return;
|
||||
// navigate to the next screen
|
||||
this.navNext();
|
||||
}
|
||||
}
|
||||
|
||||
// navigate to next screen
|
||||
|
@ -260,20 +289,24 @@ class WeatherDisplay {
|
|||
// check for special 'first frame' command
|
||||
if (command === navigation.msg.command.firstFrame) {
|
||||
this.resetNavBaseCount();
|
||||
this.drawCanvas();
|
||||
return;
|
||||
} else {
|
||||
// increment screen index
|
||||
this.screenIndex++;
|
||||
}
|
||||
|
||||
// increment screen index
|
||||
this.screenIndex++;
|
||||
// test for end reached
|
||||
if (this.screenIndex >= this.timing.totalScreens) {
|
||||
this.screenIndex = this.timing.totalScreens - 1;
|
||||
this.sendNavDisplayMessage(navigation.msg.response.next);
|
||||
this.stopNavBaseCount();
|
||||
return;
|
||||
}
|
||||
// if the end was not reached, update the canvas
|
||||
this.drawCanvas();
|
||||
this.baseCountFromScreenIndex();
|
||||
// if the end was not reached, update the canvas (typical), or run a callback (atypical)
|
||||
if (!this.screenIndexChange) {
|
||||
this.drawCanvas();
|
||||
} else {
|
||||
this.screenIndexChange(this.screenIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// navigate to previous screen
|
||||
|
@ -281,19 +314,36 @@ class WeatherDisplay {
|
|||
// check for special 'last frame' command
|
||||
if (command === navigation.msg.command.lastFrame) {
|
||||
this.screenIndex = this.timing.totalScreens-1;
|
||||
this.drawCanvas();
|
||||
return;
|
||||
} else {
|
||||
// decrement screen index
|
||||
this.screenIndex--;
|
||||
}
|
||||
// decrement screen index
|
||||
this.screenIndex--;
|
||||
|
||||
// test for end reached
|
||||
if (this.screenIndex < 0) {
|
||||
this.screenIndex = 0;
|
||||
this.sendNavDisplayMessage(navigation.msg.response.previous);
|
||||
return;
|
||||
}
|
||||
// if the end was not reached, update the canvas
|
||||
this.drawCanvas();
|
||||
this.baseCountFromScreenIndex();
|
||||
// if the end was not reached, update the canvas (typical), or run a callback (atypical)
|
||||
if (!this.screenIndexChange) {
|
||||
this.drawCanvas();
|
||||
} else {
|
||||
this.screenIndexChange(this.screenIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate a baseCount from the screen index for the array timings
|
||||
baseCountFromScreenIndex() {
|
||||
if (!Array.isArray(this.timing.delay)) return;
|
||||
// first screen starts at zero
|
||||
if (this.screenIndex === 0) {
|
||||
this.navBaseCount = 0;
|
||||
return;
|
||||
}
|
||||
// otherwise return one more than the previous sum
|
||||
this.navBaseCount = this.timing.fullDelay[this.screenIndex];
|
||||
}
|
||||
|
||||
// start and stop base counter
|
||||
|
|
Loading…
Reference in a new issue