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

@ -39,7 +39,7 @@ class CurrentWeather extends WeatherDisplay {
} catch (e) {
console.error('Unable to get current observations');
console.error(e);
this.setStatus(STATUS.error);
this.setStatus(STATUS.failed);
return;
}
// we only get here if there was no error above

View file

@ -35,12 +35,12 @@ class ExtendedForecast extends WeatherDisplay {
} catch (e) {
console.error('Unable to get extended forecast');
console.error(e);
this.setStatus(STATUS.error);
this.setStatus(STATUS.failed);
return;
}
// we only get here if there was no error above
this.data = this.parseExtendedForecast(forecast.properties.periods);
this.screnIndex = 0;
this.screenIndex = 0;
this.drawCanvas();
}

View file

@ -227,7 +227,7 @@ const icons = (() => {
case 'tsra_hi':
case 'tsra_hi-n':
case 'hurricane':
return addPath('CC_TStorm');
return addPath('CC_TStorm.gif');
case 'wind_few':
case 'wind_sct':

View file

@ -100,6 +100,7 @@ class LocalForecast extends WeatherDisplay {
} catch (e) {
console.error(`GetWeatherForecast failed: ${weatherParameters.forecast}`);
console.error(e);
this.setStatus(STATUS.failed);
return false;
}
}

View file

@ -10,7 +10,29 @@ class Radar extends WeatherDisplay {
this.dopplerRadarImageMax = 6;
// update timing
this.timing.baseDelay = 350;
this.timing.delay = [4,1,1,1,1,1,12];
this.timing.delay = [
{time: 4, si: 0},
{time: 1, si: 1},
{time: 1, si: 2},
{time: 1, si: 3},
{time: 1, si: 4},
{time: 1, si: 5},
{time: 4, si: 6},
{time: 1, si: 0},
{time: 1, si: 1},
{time: 1, si: 2},
{time: 1, si: 3},
{time: 1, si: 4},
{time: 1, si: 5},
{time: 4, si: 6},
{time: 1, si: 0},
{time: 1, si: 1},
{time: 1, si: 2},
{time: 1, si: 3},
{time: 1, si: 4},
{time: 1, si: 5},
{time: 12, si: 6},
];
// pre-load background image (returns promise)
this.backgroundImage = utils.image.load('images/BackGround4_1.png');
@ -47,7 +69,7 @@ class Radar extends WeatherDisplay {
} catch (e) {
console.error('Unable to get list of radars');
console.error(e);
this.setStatus(STATUS.error);
this.setStatus(STATUS.failed);
return;
}
@ -192,7 +214,6 @@ class Radar extends WeatherDisplay {
this.data = radarInfo.map(radar=>radar.canvas);
this.times = radarInfo.map(radar=>radar.time);
this.drawCanvas();
}
async drawCanvas() {

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--;
}
// test for end reached
if (this.screenIndex < 0) {
this.screenIndex = 0;
// 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.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.navBaseCount = newBaseCount;
}
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) {