better startup play/stop handing

This commit is contained in:
Matt Walsh 2020-09-17 16:34:38 -05:00
parent 36144f9eb1
commit 8f5b10664d
9 changed files with 157 additions and 174 deletions

View file

@ -4,6 +4,13 @@ $(() => {
}); });
const index = (() => { const index = (() => {
const overrides = {
// '32899, Orlando, Florida, USA': { x: -80.6774, y: 28.6143 },
};
const _AutoRefreshIntervalMs = 500;
const _AutoRefreshTotalIntervalMs = 600000; // 10 min.
const _NoSleep = new NoSleep();
let divTwc; let divTwc;
let divTwcTop; let divTwcTop;
let divTwcMiddle; let divTwcMiddle;
@ -13,15 +20,11 @@ const index = (() => {
let divTwcNavContainer; let divTwcNavContainer;
let txtScrollText; let txtScrollText;
const _NoSleep = new NoSleep();
let _AutoSelectQuery = false; let _AutoSelectQuery = false;
let _IsPlaying = false;
let _LastUpdate = null; let _LastUpdate = null;
let _AutoRefreshIntervalId = null; let _AutoRefreshIntervalId = null;
const _AutoRefreshIntervalMs = 500;
const _AutoRefreshTotalIntervalMs = 600000; // 10 min.
let _AutoRefreshCountMs = 0; let _AutoRefreshCountMs = 0;
let _FullScreenOverride = false; let _FullScreenOverride = false;
@ -70,9 +73,6 @@ const index = (() => {
$('.ToggleFullScreen').on('click', btnFullScreen_click); $('.ToggleFullScreen').on('click', btnFullScreen_click);
FullScreenResize(); FullScreenResize();
// listen for messages (from iframe) and handle accordingly
window.addEventListener('message', messageHandler, false);
const categories = [ const categories = [
'Land Features', 'Land Features',
'Bay', 'Channel', 'Cove', 'Dam', 'Delta', 'Gulf', 'Lagoon', 'Lake', 'Ocean', 'Reef', 'Reservoir', 'Sea', 'Sound', 'Strait', 'Waterfall', 'Wharf', // Water Features 'Bay', 'Channel', 'Cove', 'Dam', 'Delta', 'Gulf', 'Lagoon', 'Lake', 'Ocean', 'Reef', 'Reservoir', 'Sea', 'Sound', 'Strait', 'Waterfall', 'Wharf', // Water Features
@ -85,54 +85,6 @@ const index = (() => {
]; ];
const cats = categories.join(','); const cats = categories.join(',');
const overrides = {
// '32899, Orlando, Florida, USA': { x: -80.6774, y: 28.6143 },
};
const roundToPlaces = function (num, decimals) {
var n = Math.pow(10, decimals);
return Math.round((n * num).toFixed(decimals)) / n;
};
const doRedirectToGeometry = (geom) => {
const latLon = {lat:roundToPlaces(geom.y, 4), lon:roundToPlaces(geom.x, 4)};
LoadTwcData(latLon);
// Save the query
localStorage.setItem('TwcQuery', $('#txtAddress').val());
};
let PreviousSuggestionValue = null;
let PreviousSuggestion = null;
const OnSelect = (suggestion) => {
let request;
// Do not auto get the same city twice.
if (PreviousSuggestionValue === suggestion.value) return;
PreviousSuggestionValue = suggestion.value;
PreviousSuggestion = suggestion;
if (overrides[suggestion.value]) {
doRedirectToGeometry(overrides[suggestion.value]);
} else {
request = $.ajax({
url: location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find',
data: {
text: suggestion.value,
magicKey: suggestion.data,
f: 'json',
},
});
request.done((data) => {
const loc = data.locations[0];
if (loc) {
doRedirectToGeometry(loc.feature.geometry);
} else {
alert('An unexpected error occurred. Please try a different search string.');
}
});
}
};
$('#frmGetLatLng #txtAddress').devbridgeAutocomplete({ $('#frmGetLatLng #txtAddress').devbridgeAutocomplete({
serviceUrl: location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest', serviceUrl: location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest',
deferRequestBy: 300, deferRequestBy: 300,
@ -164,21 +116,13 @@ const index = (() => {
minChars: 3, minChars: 3,
showNoSuggestionNotice: true, showNoSuggestionNotice: true,
noSuggestionNotice: 'No results found. Please try a different search string.', noSuggestionNotice: 'No results found. Please try a different search string.',
onSelect: OnSelect, onSelect: autocompleteOnSelect,
width: 490, width: 490,
}); });
const ac = $('#frmGetLatLng #txtAddress').devbridgeAutocomplete(); const ac = $('#frmGetLatLng #txtAddress').devbridgeAutocomplete();
$('#frmGetLatLng').submit(function () { $('#frmGetLatLng').submit(() => {
if (ac.suggestions[0]) { if (ac.suggestions[0]) $(ac.suggestionsContainer.children[0]).click();
$(ac.suggestionsContainer.children[0]).click();
return false;
}
if (PreviousSuggestion) {
PreviousSuggestionValue = null;
OnSelect(PreviousSuggestion);
}
return false; return false;
}); });
@ -192,9 +136,7 @@ const index = (() => {
} }
const TwcPlay = localStorage.getItem('TwcPlay'); const TwcPlay = localStorage.getItem('TwcPlay');
if (!TwcPlay || TwcPlay === 'true') { if (TwcPlay === null || TwcPlay === 'true') postMessage('navButton', 'play');
_IsPlaying = true;
}
const TwcScrollText = localStorage.getItem('TwcScrollText'); const TwcScrollText = localStorage.getItem('TwcScrollText');
if (TwcScrollText) { if (TwcScrollText) {
@ -226,11 +168,9 @@ const index = (() => {
localStorage.removeItem('TwcUnits'); localStorage.removeItem('TwcUnits');
localStorage.removeItem('TwcPlay'); localStorage.removeItem('TwcPlay');
_IsPlaying = true; postMessage('navButton', 'play');
localStorage.removeItem('TwcQuery'); localStorage.removeItem('TwcQuery');
PreviousSuggestionValue = null;
PreviousSuggestion = null;
}); });
const TwcUnits = localStorage.getItem('TwcUnits'); const TwcUnits = localStorage.getItem('TwcUnits');
@ -248,7 +188,6 @@ const index = (() => {
postMessage('units', Units); postMessage('units', Units);
}); });
$('#chkAutoRefresh').on('change', (e) => { $('#chkAutoRefresh').on('change', (e) => {
const Checked = $(e.target).is(':checked'); const Checked = $(e.target).is(':checked');
@ -272,6 +211,43 @@ const index = (() => {
}; };
const autocompleteOnSelect = (suggestion) => {
let request;
// Do not auto get the same city twice.
if (this.previousSuggestionValue === suggestion.value) return;
this.previousSuggestionValue = suggestion.value;
PreviousSuggestion = suggestion;
if (overrides[suggestion.value]) {
doRedirectToGeometry(overrides[suggestion.value]);
} else {
request = $.ajax({
url: location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find',
data: {
text: suggestion.value,
magicKey: suggestion.data,
f: 'json',
},
});
request.done((data) => {
const loc = data.locations[0];
if (loc) {
doRedirectToGeometry(loc.feature.geometry);
} else {
alert('An unexpected error occurred. Please try a different search string.');
}
});
}
};
const doRedirectToGeometry = (geom) => {
const latLon = {lat:Math.round2(geom.y, 4), lon:Math.round2(geom.x, 4)};
LoadTwcData(latLon);
// Save the query
localStorage.setItem('TwcQuery', $('#txtAddress').val());
};
const FullScreenResize = () => { const FullScreenResize = () => {
const WindowWidth = $(window).width(); const WindowWidth = $(window).width();
const WindowHeight = $(window).height(); const WindowHeight = $(window).height();
@ -402,7 +378,7 @@ const index = (() => {
ExitFullscreen(); ExitFullscreen();
} }
if (_IsPlaying) { if (navigation.isPlaying()) {
_NoSleep.enable(); _NoSleep.enable();
} else { } else {
_NoSleep.disable(); _NoSleep.disable();
@ -482,7 +458,6 @@ const index = (() => {
postMessage('units', $('input[type=\'radio\'][name=\'radUnits\']:checked').val()); postMessage('units', $('input[type=\'radio\'][name=\'radUnits\']:checked').val());
if (_IsPlaying) postMessage('navButton', 'playToggle');
const display = $('#display'); const display = $('#display');
display.on('mousemove', document_mousemove); display.on('mousemove', document_mousemove);
@ -557,11 +532,7 @@ const index = (() => {
_WindowHeight = $window.height(); _WindowHeight = $window.height();
_WindowWidth = $window.width(); _WindowWidth = $window.width();
try {
postMessage('navButton', 'reset'); postMessage('navButton', 'reset');
} catch (ex) {
console.log(ex);
}
UpdateFullScreenNavigate(); UpdateFullScreenNavigate();
}; };
@ -582,7 +553,6 @@ const index = (() => {
} }
_NavigateFadeIntervalId = window.setTimeout(() => { _NavigateFadeIntervalId = window.setTimeout(() => {
//console.log("window_mousemove: TimeOut");
if (InFullScreen()) { if (InFullScreen()) {
$('body').addClass('HideCursor'); $('body').addClass('HideCursor');
@ -695,12 +665,8 @@ const index = (() => {
}; };
// read and dispatch an event from the iframe // read and dispatch an event from the iframe
const messageHandler = (event) => { const message = (data) => {
// test for trust // test for trust
if (!event.isTrusted) return;
// get the data
const data = JSON.parse(event.data);
// dispatch event // dispatch event
if (!data.type) return; if (!data.type) return;
switch (data.type) { switch (data.type) {
@ -714,12 +680,10 @@ const index = (() => {
break; break;
case 'isPlaying': case 'isPlaying':
_IsPlaying = data.message; localStorage.setItem('TwcPlay', navigation.isPlaying());
localStorage.setItem('TwcPlay', _IsPlaying);
if (_IsPlaying) { if (navigation.isPlaying()) {
_NoSleep.enable(); _NoSleep.enable();
$('img[src=\'images/nav/ic_play_arrow_white_24dp_1x.png\']').attr('title', 'Pause'); $('img[src=\'images/nav/ic_play_arrow_white_24dp_1x.png\']').attr('title', 'Pause');
$('img[src=\'images/nav/ic_play_arrow_white_24dp_1x.png\']').attr('src', 'images/nav/ic_pause_white_24dp_1x.png'); $('img[src=\'images/nav/ic_play_arrow_white_24dp_1x.png\']').attr('src', 'images/nav/ic_pause_white_24dp_1x.png');
$('img[src=\'images/nav/ic_play_arrow_white_24dp_2x.png\']').attr('title', 'Pause'); $('img[src=\'images/nav/ic_play_arrow_white_24dp_2x.png\']').attr('title', 'Pause');
@ -850,6 +814,7 @@ const index = (() => {
return { return {
init, init,
message,
}; };
})(); })();

View file

@ -44,7 +44,7 @@ class CurrentWeather extends WeatherDisplay {
} }
// we only get here if there was no error above // we only get here if there was no error above
this.data = Object.assign({}, observations, {station: station}); this.data = Object.assign({}, observations, {station: station});
this.drawCanvas(); this.setStatus(STATUS.loaded);
} }
async drawCanvas () { async drawCanvas () {
@ -175,7 +175,6 @@ class CurrentWeather extends WeatherDisplay {
})); }));
this.finishDraw(); this.finishDraw();
this.setStatus(STATUS.loaded);
} }
shortConditions(condition) { shortConditions(condition) {

View file

@ -41,8 +41,7 @@ class ExtendedForecast extends WeatherDisplay {
// we only get here if there was no error above // we only get here if there was no error above
this.data = this.parseExtendedForecast(forecast.properties.periods); this.data = this.parseExtendedForecast(forecast.properties.periods);
this.screenIndex = 0; this.screenIndex = 0;
this.drawCanvas(); this.setStatus(STATUS.loaded);
} }
// the api provides the forecast in 12 hour increments, flatten to day increments with high and low temperatures // the api provides the forecast in 12 hour increments, flatten to day increments with high and low temperatures
@ -166,6 +165,5 @@ class ExtendedForecast extends WeatherDisplay {
})); }));
this.finishDraw(); this.finishDraw();
this.setStatus(STATUS.loaded);
} }
} }

View file

@ -55,8 +55,7 @@ class LatestObservations extends WeatherDisplay {
this.setStatus(STATUS.noData); this.setStatus(STATUS.noData);
return; return;
} }
this.setStatus(STATUS.loaded);
this.drawCanvas();
} }
async drawCanvas() { async drawCanvas() {
@ -111,7 +110,6 @@ class LatestObservations extends WeatherDisplay {
y += 40; y += 40;
}); });
this.finishDraw(); this.finishDraw();
this.setStatus(STATUS.loaded);
} }
shortenCurrentConditions(condition) { shortenCurrentConditions(condition) {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
// navigation handles progress, next/previous and initial load messages from the parent frame // navigation handles progress, next/previous and initial load messages from the parent frame
/* globals utils, _StationInfo, STATUS */ /* globals index, utils, _StationInfo, STATUS */
/* globals CurrentWeather, LatestObservations, TravelForecast, RegionalForecast, LocalForecast, ExtendedForecast, Almanac, Radar, Progress */ /* globals CurrentWeather, LatestObservations, TravelForecast, RegionalForecast, LocalForecast, ExtendedForecast, Almanac, Radar, Progress */
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
@ -15,7 +15,6 @@ const UNITS = {
const navigation = (() => { const navigation = (() => {
let weatherParameters = {}; let weatherParameters = {};
let displays = []; let displays = [];
let initialLoadDone = false;
let currentUnits = UNITS.english; let currentUnits = UNITS.english;
let playing = false; let playing = false;
let progress; let progress;
@ -25,7 +24,6 @@ const navigation = (() => {
}; };
const message = (data) => { const message = (data) => {
// dispatch event // dispatch event
if (!data.type) return; if (!data.type) return;
switch (data.type) { switch (data.type) {
@ -48,14 +46,10 @@ const navigation = (() => {
}; };
const postMessage = (type, message = {}) => { const postMessage = (type, message = {}) => {
const parent = window.parent; index.message({type, message});
parent.postMessage(JSON.stringify({type, message}, window.location.origin));
}; };
const getWeather = async (latLon) => { const getWeather = async (latLon) => {
// reset statuses
initialLoadDone = false;
// get initial weather data // get initial weather data
const point = await utils.weather.getPoint(latLon.lat, latLon.lon); const point = await utils.weather.getPoint(latLon.lat, latLon.lon);
@ -93,6 +87,11 @@ const navigation = (() => {
// update the main process for display purposes // update the main process for display purposes
postMessage('weatherParameters', weatherParameters); postMessage('weatherParameters', weatherParameters);
// draw the progress canvas
progress = new Progress(-1,'progress');
await progress.drawCanvas();
progress.showCanvas();
// start loading canvases if necessary // start loading canvases if necessary
if (displays.length === 0) { if (displays.length === 0) {
displays = [ displays = [
@ -114,25 +113,21 @@ const navigation = (() => {
// ShowDopplerMap(this.weatherParameters); // ShowDopplerMap(this.weatherParameters);
// GetWeatherHazards3(this.weatherParameters); // GetWeatherHazards3(this.weatherParameters);
// draw the progress canvas
progress = new Progress(-1,'progress');
progress.drawCanvas();
progress.showCanvas();
}; };
// receive a status update from a module {id, value} // receive a status update from a module {id, value}
const updateStatus = (value) => { const updateStatus = (value) => {
// skip if initial load if (value.id < 0) return;
if (initialLoadDone) return;
// test for loaded status
if (value.status !== STATUS.loaded) return;
progress.drawCanvas(displays, countLoadedCanvases()); progress.drawCanvas(displays, countLoadedCanvases());
// if this is the first display and we're playing, load it up so it starts playing
if (isPlaying() && value.id === 0 && value.status === STATUS.loaded) {
navTo(msg.command.firstFrame);
}
// send loaded messaged to parent // send loaded messaged to parent
if (countLoadedCanvases() < displays.length) return; if (countLoadedCanvases() < displays.length) return;
postMessage('loaded'); postMessage('loaded');
// store the display number
}; };
const countLoadedCanvases = () => displays.reduce((acc, display) => { const countLoadedCanvases = () => displays.reduce((acc, display) => {
@ -183,9 +178,9 @@ const navigation = (() => {
const navTo = (direction) => { const navTo = (direction) => {
// test for a current display // test for a current display
const current = currentDisplay(); const current = currentDisplay();
progress.hideCanvas();
if (!current) { if (!current) {
// special case for no active displays (typically on progress screen) // special case for no active displays (typically on progress screen)
progress.hideCanvas();
displays[0].navNext(msg.command.firstFrame); displays[0].navNext(msg.command.firstFrame);
return; return;
} }
@ -223,14 +218,23 @@ const navigation = (() => {
const setPlaying = (newValue) => { const setPlaying = (newValue) => {
playing = newValue; playing = newValue;
postMessage('isPlaying', playing); postMessage('isPlaying', playing);
// if we're playing and on the progress screen jump to the next screen
if (!progress) return;
if (playing && !currentDisplay()) navTo(msg.command.firstFrame);
}; };
// handle all navigation buttons // handle all navigation buttons
const handleNavButton = (button) => { const handleNavButton = (button) => {
switch (button) { switch (button) {
case 'play':
setPlaying(true);
break;
case 'playToggle': case 'playToggle':
setPlaying(!playing); setPlaying(!playing);
break; break;
case 'stop':
setPlaying(false);
break;
case 'next': case 'next':
setPlaying(false); setPlaying(false);
navTo(msg.command.nextFrame); navTo(msg.command.nextFrame);

View file

@ -95,12 +95,13 @@ class Progress extends WeatherDisplay {
canvasClick(e) { canvasClick(e) {
const x = e.offsetX; const x = e.offsetX;
const y = e.offsetY; const y = e.offsetY;
console.log(x,y);
// eliminate off canvas and outside area clicks // eliminate off canvas and outside area clicks
if (!this.isActive()) return; if (!this.isActive()) return;
if (y < 100 || y > 410) return; if (y < 100 || y > 410) return;
if (x < 440 || x > 570) return; if (x < 440 || x > 570) return;
// stop playing
navigation.message('navButton', stop);
// use the y value to determine an index // use the y value to determine an index
const index = Math.floor((y-100)/29); const index = Math.floor((y-100)/29);
const display = navigation.getDisplay(index); const display = navigation.getDisplay(index);

View file

@ -67,14 +67,11 @@ class TravelForecast extends WeatherDisplay {
return; return;
} }
this.drawCanvas(true); this.setStatus(STATUS.loaded);
this.drawLongCanvas();
} }
async drawCanvas(newData) { async drawLongCanvas () {
// there are technically 2 canvases: the standard canvas and the extra-long canvas that contains the complete
// list of cities. The second canvas is copied into the standard canvas to create the scroll
super.drawCanvas();
// create the "long" canvas if necessary // create the "long" canvas if necessary
if (!this.longCanvas) { if (!this.longCanvas) {
this.longCanvas = document.createElement('canvas'); this.longCanvas = document.createElement('canvas');
@ -85,8 +82,6 @@ class TravelForecast extends WeatherDisplay {
// set up variables // set up variables
const cities = this.data; const cities = this.data;
// draw the long canvas only if there is new data
if (newData) {
this.longContext.clearRect(0,0,this.longCanvas.width,this.longCanvas.height); this.longContext.clearRect(0,0,this.longCanvas.width,this.longCanvas.height);
// draw the "long" canvas with all cities // draw the "long" canvas with all cities
@ -141,6 +136,14 @@ class TravelForecast extends WeatherDisplay {
})); }));
} }
async drawCanvas() {
// there are technically 2 canvases: the standard canvas and the extra-long canvas that contains the complete
// list of cities. The second canvas is copied into the standard canvas to create the scroll
super.drawCanvas();
// set up variables
const cities = this.data;
// draw the standard context // draw the standard context
this.context.drawImage(await this.backgroundImage, 0, 0); this.context.drawImage(await this.backgroundImage, 0, 0);
draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2); draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2);
@ -155,7 +158,12 @@ class TravelForecast extends WeatherDisplay {
this.context.drawImage(this.longCanvas, 0, 0, 640, 289, 0, 110, 640, 289); this.context.drawImage(this.longCanvas, 0, 0, 640, 289, 0, 110, 640, 289);
this.finishDraw(); this.finishDraw();
this.setStatus(STATUS.loaded); }
async showCanvas() {
// special to travel forecast to draw the remainder of the canvas
await this.drawCanvas();
super.showCanvas();
} }
// screen index change callback just runs the base count callback // screen index change callback just runs the base count callback

View file

@ -225,6 +225,10 @@ class WeatherDisplay {
return document.getElementById(this.elemId+'Canvas').offsetParent !== null; return document.getElementById(this.elemId+'Canvas').offsetParent !== null;
} }
isEnabled() {
return true;
}
// navigation timings // navigation timings
// totalScreens = total number of screens that are available // totalScreens = total number of screens that are available
// baseDelay = ms to delay before re-evaluating screenIndex // baseDelay = ms to delay before re-evaluating screenIndex
@ -246,7 +250,7 @@ class WeatherDisplay {
this.updateScreenFromBaseCount(); this.updateScreenFromBaseCount();
} }
updateScreenFromBaseCount() { async updateScreenFromBaseCount() {
// get the next screen index // get the next screen index
let nextScreenIndex = this.screenIndexFromBaseCount(); let nextScreenIndex = this.screenIndexFromBaseCount();
@ -261,11 +265,17 @@ class WeatherDisplay {
// test for no change and exit early // test for no change and exit early
if (nextScreenIndex === this.screenIndex) return; if (nextScreenIndex === this.screenIndex) return;
// test for -1 (no screen displayed yet)
if (nextScreenIndex === -1) {
this.screenIndex = 0;
} else {
this.screenIndex = nextScreenIndex; this.screenIndex = nextScreenIndex;
}
// call the appropriate screen index change method // call the appropriate screen index change method
if (!this.screenIndexChange) { if (!this.screenIndexChange) {
this.drawCanvas(); await this.drawCanvas();
this.showCanvas();
} else { } else {
this.screenIndexChange(this.screenIndex); this.screenIndexChange(this.screenIndex);
} }

View file

@ -1 +1 @@
module.exports = '3.0.0'; module.exports = '3.0.1';