more consistent navigation control

This commit is contained in:
Matt Walsh
2020-09-09 14:29:03 -05:00
parent 1f688318b5
commit 9a09ccd1ea
6 changed files with 119 additions and 91 deletions

View File

@@ -27,7 +27,7 @@ class WeatherDisplay {
delay: 1, // 1*1second = 1 second total display time
};
this.navBaseCount = 0;
this.screenIndex = 0;
this.screenIndex = -1; // special starting condition
this.setStatus(STATUS.loading);
this.createCanvas(elemId);
@@ -65,21 +65,8 @@ class WeatherDisplay {
// 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;
// recalculate navigation timing (in case it was modified in the constructor)
this.calcNavTiming();
}
drawCanvas() {
@@ -104,9 +91,7 @@ class WeatherDisplay {
// if (_ScrollText !== '') OkToDrawCustomScrollText = true;
if (this.elemId === 'almanac') OkToDrawNoaaImage = false;
if (this.elemId === 'travelForecast') OkToDrawNoaaImage = false;
if (this.elemId === 'regionalForecast0') OkToDrawNoaaImage = false;
if (this.elemId === 'regionalForecast1') OkToDrawNoaaImage = false;
if (this.elemId === 'regionalForecast2') OkToDrawNoaaImage = false;
if (this.elemId === 'regionalForecast') OkToDrawNoaaImage = false;
if (this.elemId === 'radar') {
OkToDrawCurrentConditions = false;
OkToDrawCurrentDateTime = false;
@@ -228,12 +213,6 @@ 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 (in case the screen index changed)
if (navCmd) this.drawCanvas();
}
hideCanvas() {
this.stopNavBaseCount(true);
@@ -263,21 +242,70 @@ class WeatherDisplay {
// call base count change if available for this function
if (this.baseCountChange) this.baseCountChange(this.navBaseCount);
// determine type of timing
// simple delay
if (typeof this.timing.delay === 'number') {
this.navNext();
// handle base count/screen index changes
this.updateScreenFromBaseCount();
}
updateScreenFromBaseCount() {
// get the next screen index
let nextScreenIndex = this.screenIndexFromBaseCount();
// special cases for first and last frame
// must compare with false as nextScreenIndex could be 0 which is valid
if (nextScreenIndex === false) {
this.sendNavDisplayMessage(navigation.msg.response.next);
this.stopNavBaseCount();
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 && this.navBaseCount <= this.timing.fullDelay[this.timing.totalScreens-1]) return;
// navigate to the next screen
this.navNext();
// test for no change and exit early
if (nextScreenIndex === this.screenIndex) return;
this.screenIndex = nextScreenIndex;
// call the appropriate screen index change method
if (!this.screenIndexChange) {
this.drawCanvas();
} else {
this.screenIndexChange(this.screenIndex);
}
}
// take the three timing formats shown above and break them into arrays for consistent usage in navigation functions
// this.timing.fullDelay = [end of screen index 0 in base counts, end of screen index 1...]
// this.timing.screenIndexes = [screen index to use during this.timing.fullDelay[0], screen index to use during this.timing.fullDelay[1], ...]
calcNavTiming() {
// update total screens
if (Array.isArray(this.timing.delay)) this.timing.totalScreens = this.timing.delay.length;
// if the delay is provided as a single value, expand it to a series of the same value
let intermediateDelay = [];
if (typeof this.timing.delay === 'number') {
for (let i = 0; i < this.timing.totalScreens; i++) intermediateDelay.push(this.timing.delay);
} else {
// map just the delays to the intermediate block
intermediateDelay = this.timing.delay.map(delay => {
if (typeof delay === 'object') return delay.time;
return delay;
});
}
// calculate the cumulative end point of each delay
let sum = 0;
this.timing.fullDelay = intermediateDelay.map(val => {
const calc = sum + val;
sum += val;
return calc;
});
// generate a list of screen either sequentially if not provided in an object or from the object
if (Array.isArray(this.timing.delay) && typeof this.timing.delay[0] === 'object') {
// extract screen indexes from objects
this.timing.screenIndexes = this.timing.delay.map(delay => delay.si);
} else {
// generate sequential screen indexes
this.timing.screenIndexes = [];
for (let i = 0; i < this.timing.totalScreens; i++) this.timing.screenIndexes.push(i);
}
}
@@ -287,62 +315,40 @@ class WeatherDisplay {
if (command === navigation.msg.command.firstFrame) {
this.resetNavBaseCount();
} else {
// increment screen index
this.screenIndex++;
// set the base count to the next available frame
const newBaseCount = this.timing.fullDelay.find(delay => delay > this.navBaseCount);
this.navBaseCount = newBaseCount;
}
// 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;
}
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);
}
this.showCanvas();
this.updateScreenFromBaseCount();
}
// navigate to previous screen
navPrev(command) {
// check for special 'last frame' command
if (command === navigation.msg.command.lastFrame) {
this.screenIndex = this.timing.totalScreens-1;
this.navBaseCount = this.timing.fullDelay[this.timing.totalScreens-1]-1;
} else {
// decrement screen index
this.screenIndex--;
// find the highest fullDelay that is less than the current base count
const newBaseCount = this.timing.fullDelay.reduce((acc, delay) => {
if (delay < this.navBaseCount) return delay;
return acc;
},0);
// if the new base count is zero then we're already at the first screen
if (newBaseCount === 0 && this.navBaseCount === 0) {
this.sendNavDisplayMessage(navigation.msg.response.previous);
return;
}
this.navBaseCount = newBaseCount;
}
// test for end reached
if (this.screenIndex < 0) {
this.screenIndex = 0;
this.sendNavDisplayMessage(navigation.msg.response.previous);
return;
}
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);
}
this.showCanvas();
this.updateScreenFromBaseCount();
}
// 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];
// get the screen index for the current base count, returns false if past end of timing array (go to next screen, stop timing)
screenIndexFromBaseCount() {
// find the first timing in the timing array that is greater than the base count
const timingIndex = this.timing.fullDelay.findIndex(delay => delay > this.navBaseCount);
if (timingIndex === -1) return false;
return this.timing.screenIndexes[timingIndex];
}
// start and stop base counter
@@ -357,7 +363,7 @@ class WeatherDisplay {
}
resetNavBaseCount() {
this.navBaseCount = 0;
this.screenIndex = 0;
this.screenIndex = -1;
}
sendNavDisplayMessage(message) {