From 07f8795ae6e87b6e7882eca366554149fe490937 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 15 May 2018 15:38:47 +0200 Subject: [PATCH] Improvements on positioning in the timeline when openning the app Now the app will try to re position itself on the timeline at the last place visited with the same zoom level. This will not be possible only when it is the first time the app is usued or when the screen resolution was changed, in both cases the positionning will be at the current datetime. --- Canvas.js | 18 +++-- Dashboard.js | 8 +- Panels/TimeControlPanel.js | 17 +++- Spaces/ChartSpace.js | 49 +++++++++--- TimeMachine.js | 16 +++- TimelineChart.js | 27 +++++-- ViewPort.js | 159 +++++++++++++++++++++++++------------ 7 files changed, 211 insertions(+), 83 deletions(-) diff --git a/Canvas.js b/Canvas.js index e6855f970..8138525d0 100644 --- a/Canvas.js +++ b/Canvas.js @@ -86,17 +86,25 @@ function newCanvas() { let panelsSpace = newPanelsSpace(); panelsSpace.initialize(); - this.panelsSpace = panelsSpace; + thisObject.panelsSpace = panelsSpace; let floatingSpace = newFloatingSpace(); floatingSpace.initialize(); - this.floatingSpace = floatingSpace; + thisObject.floatingSpace = floatingSpace; let chartSpace = newChartSpace(); - chartSpace.initialize(); + chartSpace.initialize(onCharSpaceInitialized); - this.chartSpace = chartSpace; + thisObject.chartSpace = chartSpace; + + function onCharSpaceInitialized(err) { + viewPort.raiseEvents(); // These events will impacts on objects just initialized. + + /* We will store the last used this screen resolution. This will help us know if we can remember the las viewPort offset or not, since they depends on the screen resolution. */ + + window.localStorage.setItem('webApp.lastRun.screenResolution', browserCanvas.width + '.' + browserCanvas.height); + } /* Splash Screen */ @@ -108,7 +116,7 @@ function newCanvas() { function onAnimationInitialized(err) { - this.animation = animation; + thisObject.animation = animation; /* Here we add all the functions that will be called during the animation cycle. */ diff --git a/Dashboard.js b/Dashboard.js index 3f2ae9899..2e039b20b 100644 --- a/Dashboard.js +++ b/Dashboard.js @@ -129,7 +129,7 @@ const FONT_ASPECT_RATIO = 0.60; const CHART_ASPECT_RATIO = 1 / 10; const INITIAL_ZOOM_LEVEL = -22; // This is the zoom level at the view port in which the APP starts. -const INITIAL_TIME_PERIOD = recalculatePeriod(INITIAL_ZOOM_LEVEL); +let INITIAL_TIME_PERIOD = recalculatePeriod(INITIAL_ZOOM_LEVEL); // This value will be overwritten at the viewPort.initialize if the user had a prevous session with this same browser. var viewPort = newViewPort(); @@ -153,11 +153,7 @@ const PERIOD_10_MIN = "10-min"; const PERIOD_05_MIN = "05-min"; const PERIOD_01_MIN = "01-min"; -var newDate = new Date(); -newDate.setMilliseconds(0); -newDate.setDate(newDate.getDate() - 90); - -const INITIAL_DATE = new Date(); +const INITIAL_DATE = new Date(); // This value will be overwritten at the viewPort.initialize if the user had a prevous session with this same browser. var maxDate = new Date(); maxDate.setMilliseconds(0); diff --git a/Panels/TimeControlPanel.js b/Panels/TimeControlPanel.js index 949cb69af..f6b3e98a5 100644 --- a/Panels/TimeControlPanel.js +++ b/Panels/TimeControlPanel.js @@ -86,8 +86,21 @@ function newTimeControlPanel() { thisObject.buttons = buttons; + let datetime = INITIAL_DATE; - var datetime = INITIAL_DATE; + /* There is a chance that we could resume the last session at the place we left it. */ + + let lastRun = window.localStorage.getItem('webApp.lastRun.screenResolution'); + + if (lastRun !== null && lastRun === browserCanvas.width + '.' + browserCanvas.height) { + + let savedCurrentDatetime = window.localStorage.getItem('timeControlPanel.currentDatetime'); + + if (savedCurrentDatetime !== null) { + datetime = new Date(savedCurrentDatetime); + + } + } var datetimeDisplay = { currentDatetime: datetime, @@ -153,6 +166,8 @@ function newTimeControlPanel() { thisObject.datetimeDisplay.currentDatetime = newDatetime; + window.localStorage.setItem('timeControlPanel.currentDatetime', newDatetime); + } diff --git a/Spaces/ChartSpace.js b/Spaces/ChartSpace.js index 81a441fe0..16c0f3e10 100644 --- a/Spaces/ChartSpace.js +++ b/Spaces/ChartSpace.js @@ -13,7 +13,7 @@ function newChartSpace() { const logger = newDebugLog(); logger.fileName = MODULE_NAME; - var chartSpace = { + var thisObject = { container: undefined, draw: draw, timeMachines: [], @@ -24,25 +24,28 @@ function newChartSpace() { var container = newContainer(); container.initialize(); - chartSpace.container = container; + thisObject.container = container; - chartSpace.container.frame.width = browserCanvas.width * 1000; - chartSpace.container.frame.height = browserCanvas.height * 100; + thisObject.container.frame.width = browserCanvas.width * 1000; + thisObject.container.frame.height = browserCanvas.height * 100; container.displacement.containerName = "Chart Space"; container.frame.containerName = "Chart Space"; - container.frame.position.x = browserCanvas.width / 2 - chartSpace.container.frame.width / 2; - container.frame.position.y = browserCanvas.height / 2 - chartSpace.container.frame.height / 2; + container.frame.position.x = browserCanvas.width / 2 - thisObject.container.frame.width / 2; + container.frame.position.y = browserCanvas.height / 2 - thisObject.container.frame.height / 2; container.isDraggeable = false; - return chartSpace; + return thisObject; - function initialize() { + function initialize(callBackFunction) { if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + let initializedCounter = 0; + let toInitialize = 1; + /* We create the first of many possible time machines that could live at the Chart Space. */ var timeMachine = newTimeMachine(); @@ -60,21 +63,41 @@ function newChartSpace() { timeMachine.container.frame.position.x = this.container.frame.width / 2 - timeMachine.container.frame.width / 2; timeMachine.container.frame.position.y = this.container.frame.height / 2 - timeMachine.container.frame.height / 2; - timeMachine.initialize(); + timeMachine.initialize(onTimeMachineInitialized); - this.timeMachines.push(timeMachine); + function onTimeMachineInitialized(err) { + if (INFO_LOG === true) { logger.write("[INFO] initialize -> onTimeMachineInitialized -> Entering function."); } + + initializedCounter++; + + if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + + if (INFO_LOG === true) { logger.write("[INFO] initialize -> onTimeMachineInitialized -> Initialization of a Time Machine failed."); } + + callBackFunction(err); + return; + } + + thisObject.timeMachines.push(timeMachine); + + if (initializedCounter === toInitialize) { + + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); + + } + } } function draw() { - chartSpace.container.frame.draw(false, false); + thisObject.container.frame.draw(false, false); /* When we draw the chart space, that means we draw all the time machines in it. */ - for (var i = 0; i < chartSpace.timeMachines.length; i++ ) { + for (var i = 0; i < thisObject.timeMachines.length; i++ ) { - var timeMachine = chartSpace.timeMachines[i]; + var timeMachine = thisObject.timeMachines[i]; timeMachine.draw(); } diff --git a/TimeMachine.js b/TimeMachine.js index 6d651beb1..1345ff66f 100644 --- a/TimeMachine.js +++ b/TimeMachine.js @@ -37,7 +37,7 @@ function newTimeMachine() { return thisObject; - function initialize() { + function initialize(callBackFunction) { if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } @@ -70,16 +70,26 @@ function newTimeMachine() { iteration++; - function onDefaultMarketInitialized() { + function onDefaultMarketInitialized(err) { if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDefaultMarketInitialized -> Entering function."); } + if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + + if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDefaultMarketInitialized -> Initialization of the only market failed."); } + + callBackFunction(err); + return; + } + thisObject.charts.push(timelineChart); controlPanel.container.eventHandler.listenToEvent('Datetime Changed', timelineChart.setDatetime, undefined); timelineChart.container.eventHandler.listenToEvent('Datetime Changed', controlPanel.setDatetime); - initializeTheRestOfTheMarkets(); + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); + + //initializeTheRestOfTheMarkets(); } diff --git a/TimelineChart.js b/TimelineChart.js index 6fd38b31c..9ffd0bdc1 100644 --- a/TimelineChart.js +++ b/TimelineChart.js @@ -65,8 +65,16 @@ chartGrid = newChartGrid(); recalculateScale(); - moveViewPortToCurrentDatetime(); + /* When the Web App has never run, we need to position the viewPort at the current Date. This in turn will set the current date as the date for loading the data. */ + + let lastRun = window.localStorage.getItem('webApp.lastRun.screenResolution'); + + if (lastRun === null || lastRun !== browserCanvas.width + '.' + browserCanvas.height) { + + moveViewPortToCurrentDatetime(); + } + /* Event Subscriptions - we need this events to be fired first here and then in active Plotters. */ viewPort.eventHandler.listenToEvent("Offset Changed", onOffsetChanged); @@ -117,7 +125,7 @@ if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> Received OK Response."); } initializationReady = true; - callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE); + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); break; } @@ -496,10 +504,17 @@ if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> onPlotterInizialized -> Entering function."); } if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> onPlotterInizialized -> key = " + pProductCard.product.plotter.devTeam + "-" + pProductCard.product.plotter.codeName + "-" + pProductCard.product.plotter.moduleName); } - try { - plotter.positionAtDatetime(INITIAL_DATE); - } catch (err) { - // If the plotter does not implement this function its ok. + /* When the Web App has never run, we need to position the viewPort at the current Date. Otherwise it will get automatically positioned at the last thing the user was browsing. */ + + let lastRun = window.localStorage.getItem('webApp.lastRun.screenResolution'); + + if (lastRun === null || lastRun !== browserCanvas.width + '.' + browserCanvas.height) { + + try { + plotter.positionAtDatetime(INITIAL_DATE); + } catch (err) { + // If the plotter does not implement this function its ok. + } } let productPlotter = { diff --git a/ViewPort.js b/ViewPort.js index 6ca6a9d33..9c5d7f18d 100644 --- a/ViewPort.js +++ b/ViewPort.js @@ -9,10 +9,10 @@ function newViewPort() { const LEFT_MARGIN = 50; const RIGHT_MARGIN = 50; - let viewPort = { + let thisObject = { visibleArea: undefined, eventHandler: undefined, - zoomLevel: INITIAL_ZOOM_LEVEL, + zoomLevel: undefined, mousePosition: undefined, applyZoom: applyZoom, zoomFontSize: zoomFontSize, @@ -24,11 +24,10 @@ function newViewPort() { displaceTarget: displaceTarget, animate: animate, draw: draw, + raiseEvents: raiseEvents, initialize: initialize }; - zoomTargetLevel = INITIAL_ZOOM_LEVEL; - let increment = 0.035; var offset = { @@ -46,42 +45,93 @@ function newViewPort() { y: 0 }; - viewPort.mousePosition = { + thisObject.mousePosition = { x: 0, y: 0 }; - viewPort.eventHandler = newEventHandler(); + thisObject.eventHandler = newEventHandler(); - return viewPort; + let zoomTargetLevel; + + return thisObject; function initialize() { - viewPort.visibleArea = { + thisObject.visibleArea = { topLeft: { x: LEFT_MARGIN, y: TOP_MARGIN }, topRight: { x: browserCanvas.width - RIGHT_MARGIN , y: TOP_MARGIN }, bottomRight: { x: browserCanvas.width - RIGHT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN}, bottomLeft: { x: LEFT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN} }; + /* There is a chance that we could resume the last session at the place we left it. */ + + let lastRun = window.localStorage.getItem('webApp.lastRun.screenResolution'); + + if (lastRun !== null && lastRun === browserCanvas.width + '.' + browserCanvas.height) { + + /* We get from the local storage the recored values of Zoom and OffSet during the last session using this app with this browser */ + + let savedZoomTargetLevel = window.localStorage.getItem('viewPort.zoomTargetLevel'); + + if (savedZoomTargetLevel !== null) { + + thisObject.zoomLevel = Number(savedZoomTargetLevel); + zoomTargetLevel = Number(savedZoomTargetLevel); + + INITIAL_TIME_PERIOD = recalculatePeriod(thisObject.zoomLevel); + } + + let savedOffset = window.localStorage.getItem('viewPort.offset'); + + if (savedOffset !== null) { + + offset = JSON.parse(savedOffset); + } + + let savedTargetOffset = window.localStorage.getItem('viewPort.targetOffset'); + + if (savedTargetOffset !== null) { + + targetOffset = JSON.parse(savedTargetOffset); + } + + } else { + + thisObject.zoomLevel = INITIAL_ZOOM_LEVEL; + zoomTargetLevel = INITIAL_ZOOM_LEVEL; + + INITIAL_TIME_PERIOD = recalculatePeriod(thisObject.zoomLevel); + } + } + + function raiseEvents() { + + let event = { + newOffset: offset + }; + + thisObject.eventHandler.raiseEvent("Offset Changed", event); + } function animate() { - if (viewPort.zoomLevel < zoomTargetLevel) { - if (zoomTargetLevel - viewPort.zoomLevel < ANIMATION_INCREMENT) { - ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - viewPort.zoomLevel); + if (thisObject.zoomLevel < zoomTargetLevel) { + if (zoomTargetLevel - thisObject.zoomLevel < ANIMATION_INCREMENT) { + ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - thisObject.zoomLevel); } - viewPort.zoomLevel = viewPort.zoomLevel + ANIMATION_INCREMENT; - changeZoom(viewPort.zoomLevel - ANIMATION_INCREMENT, viewPort.zoomLevel); + thisObject.zoomLevel = thisObject.zoomLevel + ANIMATION_INCREMENT; + changeZoom(thisObject.zoomLevel - ANIMATION_INCREMENT, thisObject.zoomLevel); } - if (viewPort.zoomLevel > zoomTargetLevel) { - if (viewPort.zoomLevel - zoomTargetLevel < ANIMATION_INCREMENT) { - ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - viewPort.zoomLevel); + if (thisObject.zoomLevel > zoomTargetLevel) { + if (thisObject.zoomLevel - zoomTargetLevel < ANIMATION_INCREMENT) { + ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - thisObject.zoomLevel); } - viewPort.zoomLevel = viewPort.zoomLevel - ANIMATION_INCREMENT; - changeZoom(viewPort.zoomLevel + ANIMATION_INCREMENT, viewPort.zoomLevel); + thisObject.zoomLevel = thisObject.zoomLevel - ANIMATION_INCREMENT; + changeZoom(thisObject.zoomLevel + ANIMATION_INCREMENT, thisObject.zoomLevel); } /* @@ -119,7 +169,9 @@ function newViewPort() { newOffset: offset }; - viewPort.eventHandler.raiseEvent("Offset Changed", event); + thisObject.eventHandler.raiseEvent("Offset Changed", event); + + window.localStorage.setItem('viewPort.offset', JSON.stringify(offset)); //console.log("displace produced new Offset x = " + offset.x + " y = " + offset.y); @@ -137,6 +189,8 @@ function newViewPort() { y: (targetOffset.y - offset.y) / 10 }; + window.localStorage.setItem('viewPort.targetOffset', JSON.stringify(targetOffset)); + //console.log("displaceTarget x = " + targetOffset.x + " y = " + targetOffset.y); } @@ -195,7 +249,7 @@ function newViewPort() { zoomTargetLevel = zoomTargetLevel + amount; - ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - viewPort.zoomLevel) / 3; + ANIMATION_INCREMENT = Math.abs(zoomTargetLevel - thisObject.zoomLevel) / 3; let event = { newLevel: zoomTargetLevel, @@ -211,24 +265,31 @@ function newViewPort() { //console.log("Zoom Changed > " + event.newLevel); - viewPort.eventHandler.raiseEvent("Zoom Changed", event); + thisObject.eventHandler.raiseEvent("Zoom Changed", event); + + window.localStorage.setItem('viewPort.zoomTargetLevel', zoomTargetLevel); + return true; } function changeZoom(oldLevel, newLevel) { - let mouseNoZoom = unzoomThisPoint(viewPort.mousePosition, oldLevel); + let mouseNoZoom = unzoomThisPoint(thisObject.mousePosition, oldLevel); let newMouse = zoomThisPoint(mouseNoZoom, newLevel); - offset.x = offset.x - newMouse.x + viewPort.mousePosition.x; - offset.y = offset.y - newMouse.y + viewPort.mousePosition.y; + offset.x = offset.x - newMouse.x + thisObject.mousePosition.x; + offset.y = offset.y - newMouse.y + thisObject.mousePosition.y; + + window.localStorage.setItem('viewPort.offset', JSON.stringify(offset)); //console.log("changeZoom produced new Offset x = " + offset.x + " y = " + offset.y); targetOffset.x = offset.x targetOffset.y = offset.y ; + window.localStorage.setItem('viewPort.targetOffset', JSON.stringify(targetOffset)); + offsetIncrement = { x: 0, y: 0 @@ -239,11 +300,11 @@ function newViewPort() { function zoomFontSize(baseSize, level) { - let zoomFactor = increment; // + increment * viewPort.zoomLevel / 100; + let zoomFactor = increment; // + increment * thisObject.zoomLevel / 100; if (level === undefined) { - baseSize = baseSize * (1 + zoomFactor * viewPort.zoomLevel); + baseSize = baseSize * (1 + zoomFactor * thisObject.zoomLevel); } else { @@ -259,20 +320,20 @@ function newViewPort() { /* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */ - if (point.x > viewPort.visibleArea.bottomRight.x + 1) { - point.x = viewPort.visibleArea.bottomRight.x + 1; + if (point.x > thisObject.visibleArea.bottomRight.x + 1) { + point.x = thisObject.visibleArea.bottomRight.x + 1; } - if (point.x < viewPort.visibleArea.topLeft.x - 1) { - point.x = viewPort.visibleArea.topLeft.x - 1; + if (point.x < thisObject.visibleArea.topLeft.x - 1) { + point.x = thisObject.visibleArea.topLeft.x - 1; } - if (point.y > viewPort.visibleArea.bottomRight.y + 1) { - point.y = viewPort.visibleArea.bottomRight.y + 1; + if (point.y > thisObject.visibleArea.bottomRight.y + 1) { + point.y = thisObject.visibleArea.bottomRight.y + 1; } - if (point.y < viewPort.visibleArea.topLeft.y - 1) { - point.y = viewPort.visibleArea.topLeft.y - 1; + if (point.y < thisObject.visibleArea.topLeft.y - 1) { + point.y = thisObject.visibleArea.topLeft.y - 1; } return point; @@ -281,12 +342,12 @@ function newViewPort() { function zoomThisPoint(point, level) { - let zoomFactor = increment; // + increment * viewPort.zoomLevel / 100; + let zoomFactor = increment; // + increment * thisObject.zoomLevel / 100; if (level === undefined) { - point.x = point.x * (1 + zoomFactor * viewPort.zoomLevel) + offset.x; - point.y = point.y * (1 + zoomFactor * viewPort.zoomLevel) + offset.y; + point.x = point.x * (1 + zoomFactor * thisObject.zoomLevel) + offset.x; + point.y = point.y * (1 + zoomFactor * thisObject.zoomLevel) + offset.y; } else { @@ -301,13 +362,13 @@ function newViewPort() { function unzoomThisPoint(pointWithZoom, level) { let pointWithoutZoom; - let zoomFactor = increment; // + increment * viewPort.zoomLevel / 100; + let zoomFactor = increment; // + increment * thisObject.zoomLevel / 100; if (level === undefined) { pointWithoutZoom = { - x: (pointWithZoom.x - offset.x) / (1 + zoomFactor * viewPort.zoomLevel), - y: (pointWithZoom.y - offset.y) / (1 + zoomFactor * viewPort.zoomLevel) + x: (pointWithZoom.x - offset.x) / (1 + zoomFactor * thisObject.zoomLevel), + y: (pointWithZoom.y - offset.y) / (1 + zoomFactor * thisObject.zoomLevel) }; } else { @@ -352,12 +413,12 @@ function newViewPort() { function drawGrid(step) { - let squareWidth = (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / step; - squareWidth = squareWidth + squareWidth * increment * viewPort.zoomLevel; + let squareWidth = (thisObject.visibleArea.bottomRight.x - thisObject.visibleArea.bottomLeft.x) / step; + squareWidth = squareWidth + squareWidth * increment * thisObject.zoomLevel; let startingX = offset.x - Math.trunc(offset.x / squareWidth) * squareWidth; let startingY = offset.y - Math.trunc(offset.y / squareWidth) * squareWidth; - let lineWidth = 10 / step + 10 / step * increment * viewPort.zoomLevel; + let lineWidth = 10 / step + 10 / step * increment * thisObject.zoomLevel; if (lineWidth < 0.5) { return; @@ -369,17 +430,17 @@ function newViewPort() { browserCanvasContext.beginPath(); - for (var i = startingX; i < viewPort.visibleArea.bottomRight.x; i = i + squareWidth) { + for (var i = startingX; i < thisObject.visibleArea.bottomRight.x; i = i + squareWidth) { - for (var j = startingY; j < viewPort.visibleArea.bottomRight.y; j = j + squareWidth) { + for (var j = startingY; j < thisObject.visibleArea.bottomRight.y; j = j + squareWidth) { let point1 = { - x: viewPort.visibleArea.bottomLeft.x, + x: thisObject.visibleArea.bottomLeft.x, y: j }; let point2 = { - x: viewPort.visibleArea.bottomRight.x, + x: thisObject.visibleArea.bottomRight.x, y: j }; @@ -389,12 +450,12 @@ function newViewPort() { let point3 = { x: i, - y: viewPort.visibleArea.topLeft.y + y: thisObject.visibleArea.topLeft.y }; let point4 = { x: i, - y: viewPort.visibleArea.bottomLeft.y + y: thisObject.visibleArea.bottomLeft.y }; browserCanvasContext.moveTo(point3.x, point3.y);