From 83d45e511f455566ff8497fb7804197e9f0ee4cd Mon Sep 17 00:00:00 2001 From: l_samenv Date: Tue, 6 Aug 2024 13:53:58 +0200 Subject: [PATCH] Functionnal toolbar and indicators --- client/components/control/control.css | 4 +- .../states_indicator/dates/dates.js | 40 ++- client/cssFiles/SEAWebClientGraphics.css | 16 +- client/cssFiles/SEAWebClientSwiper.css | 5 +- client/jsFiles/SEAWebClientGraphics.js | 260 ++++++++++++++---- 5 files changed, 250 insertions(+), 75 deletions(-) diff --git a/client/components/control/control.css b/client/components/control/control.css index 702b3c7..1cdf07f 100644 --- a/client/components/control/control.css +++ b/client/components/control/control.css @@ -1,6 +1,6 @@ .control-global{ - width: 30px; - height: 30px; + width: 28px; + height: 28px; border: 1px solid dimgray; box-sizing: border-box; transition: border 0.25s; diff --git a/client/components/states_indicator/dates/dates.js b/client/components/states_indicator/dates/dates.js index 543d59e..63ccd24 100644 --- a/client/components/states_indicator/dates/dates.js +++ b/client/components/states_indicator/dates/dates.js @@ -1,18 +1,40 @@ class DatesIndicator extends HTMLElement{ - constructor(oldestTimestamp, newestTimestamp){ + constructor(timestamp){ super(); - this.oldestDate = this.timestampToString(oldestTimestamp); - this.newestDate = this.timestampToString(newestTimestamp); + this.formattedDate = this.timestampToString(timestamp); + } + + dayNumberToName(dayNumber){ + switch(dayNumber){ + case 0: + return "Sun"; + case 1: + return "Mon"; + case 2: + return "Tue"; + case 3: + return "Wed"; + case 4: + return "Thu"; + case 5: + return "Fri"; + case 6: + return "Sat"; + } } timestampToString(timestamp){ let date = new Date(timestamp); - return date.toUTCString(); + let dayName = this.dayNumberToName(date.getDay()); + let day = date.getDate(); + let month = date.getMonth(); + let year = date.getFullYear(); + + return dayName + ", " + day.toString().padStart(2, "0") + "/" + month.toString().padStart(2, "0") + "/" + year ; } - update(oldestTimestamp, newestTimestamp){ - this.oldestDate = this.timestampToString(oldestTimestamp); - this.newestDate = this.timestampToString(newestTimestamp); + update(timestamp){ + this.formattedDate = this.timestampToString(timestamp); this.render() } @@ -24,9 +46,7 @@ class DatesIndicator extends HTMLElement{ this.innerHTML = `
- ${this.oldestDate} - -> - ${this.newestDate} + ${this.formattedDate}
` } diff --git a/client/cssFiles/SEAWebClientGraphics.css b/client/cssFiles/SEAWebClientGraphics.css index 2760d91..84cad61 100644 --- a/client/cssFiles/SEAWebClientGraphics.css +++ b/client/cssFiles/SEAWebClientGraphics.css @@ -7,20 +7,21 @@ justify-content: flex-end; } -.panel.graphics span{ - margin: 0 1em; +.panel.graphics span:first-child{ + display: none; + /* margin: 0 1em; display: flex; user-select: none; - -webkit-user-select: none; + -webkit-user-select: none; */ } -.panel.graphics div{ +/* .panel.graphics div{ margin-left: 1em; cursor: pointer; -} +} */ #control_bar{ - height: 100%; + height: 28px; background-color: dimgray; border-top-left-radius: 12px; border-top-right-radius: 12px; @@ -28,7 +29,8 @@ padding-right: 12px; display: flex; column-gap: 5px; - margin-left: 100px; + margin-left: 120px; + margin-top: 2px; } /*********************/ diff --git a/client/cssFiles/SEAWebClientSwiper.css b/client/cssFiles/SEAWebClientSwiper.css index 7538cec..ee3a515 100644 --- a/client/cssFiles/SEAWebClientSwiper.css +++ b/client/cssFiles/SEAWebClientSwiper.css @@ -24,12 +24,15 @@ text-align: center; background-color: #303030; color: white; - padding: 6px 6px 6px 6px; + /* padding: 6px 6px 6px 6px; */ position: absolute; z-index: 20; width: 100%; height: 30px; } +.panel:not(.graphics){ + padding: 6px 6px 6px 6px; +} .slide-close-icon { transition: 0.4s; diff --git a/client/jsFiles/SEAWebClientGraphics.js b/client/jsFiles/SEAWebClientGraphics.js index e6fbc89..bdad279 100644 --- a/client/jsFiles/SEAWebClientGraphics.js +++ b/client/jsFiles/SEAWebClientGraphics.js @@ -217,26 +217,21 @@ let globalControls = (function (){ function loadControls(panel){ let controlBar = document.createElement("div"); - controlBar.id = "control_bar" + controlBar.id = "control_bar"; panel.appendChild(controlBar); let jumpControl = new Control("res/jump.png", "res/jump_blocked.png", "Jump", dummyCallback); - let goToNowControl = new Control("res/go_to_now.png", "res/go_to_now_blocked.png", "Go to now", dummyCallback); + let goToNowControl = new Control("res/go_to_now.png", "res/go_to_now_blocked.png", "Go to now", graphs.gotoNow); - let zoomInControl = new Control("res/zoom_in.png", "res/zoom_in_blocked.png", "Zoom in", dummyCallback); - let zoomOutControl = new Control("res/zoom_out.png", "res/zoom_out_blocked.png", "Zoon out", dummyCallback); - let shiftOlderControl = new Control("res/shift_older.png", "res/shift_older_blocked.png", "Shift to older", dummyCallback); - let shiftNewerControl = new Control("res/shift_newer.png", "res/shift_newer_blocked.png", "Shift to newer", dummyCallback); + let zoomInControl = new Control("res/zoom_in.png", "res/zoom_in_blocked.png", "Zoom in (time)", graphs.zoomIn); + let zoomOutControl = new Control("res/zoom_out.png", "res/zoom_out_blocked.png", "Zoon out (time)", graphs.zoomOut); + let shiftOlderControl = new Control("res/shift_older.png", "res/shift_older_blocked.png", "Shift to older", graphs.shiftOlder); + let shiftNewerControl = new Control("res/shift_newer.png", "res/shift_newer_blocked.png", "Shift to newer", graphs.shiftNewer); - let xyControl = new Control("res/y_direction.png", "res/x_direction.png", "Time<->Y zoom", dummyCallback, dummyCallback); - let cursorControl = new Control("res/remove_cursor.png", "res/remove_cursor_blocked.png", "Remove cursor",dummyCallback); - let legendsControl = new Control("res/display_legends.png", "res/remove_legends.png", "Legends", dummyCallback, dummyCallback); - - let now = Date.now(); - let old = now - 1000*3600; - let dates = new DatesIndicator(old, now); - let liveState = new LiveStateIndicator(); + let xyControl = new Control("res/y_direction.png", "res/x_direction.png", "Time<->Y zoom (one graph)", graphs.toggleZoomMode, graphs.toggleZoomMode); + let cursorControl = new Control("res/remove_cursor.png", "res/remove_cursor_blocked.png", "Remove cursor", graphs.removeCursor); + let legendsControl = new Control("res/display_legends.png", "res/remove_legends.png", "Legends", graphs.displayAllLegends, graphs.hideAllLegends); controlBar.appendChild(jumpControl) controlBar.appendChild(goToNowControl) @@ -253,12 +248,6 @@ let globalControls = (function (){ controlBar.appendChild(legendsControl); legendsControl.changeToAlt(); - panel.appendChild(dates) - panel.appendChild(liveState); - liveState.changeToDisable(); - liveState.style.marginLeft = "auto"; //sticks element to the right - dates.style.marginLeft = "auto"; - controlsMap[jumpKey] = jumpControl; controlsMap[goToNowKey] = goToNowControl; controlsMap[zoomInKey] = zoomInControl; @@ -267,7 +256,7 @@ let globalControls = (function (){ controlsMap[shiftNewerKey] = shiftNewerControl; controlsMap[xyKey] = xyControl; controlsMap[cursorKey] = cursorControl; - controlsMap[legendsKey] = legendsControl; + controlsMap[legendsKey] = legendsControl; } function getControlsMap(){ @@ -280,6 +269,39 @@ let globalControls = (function (){ } })(); +let datesKey = "dates-indicator"; +let liveKey = "live-indicator"; + +let globalIndicators = (function (){ + + let indicatorsMap = {} + + function loadIndicators(panel){ + let leftDate = Date.now() - 30*60*1000; + let datesIndicator = new DatesIndicator(leftDate); + let liveIndicator = new LiveStateIndicator(); + + panel.appendChild(datesIndicator); + panel.appendChild(liveIndicator); + liveIndicator.changeToDisable(); + liveIndicator.style.marginLeft = "auto"; //sticks element to the right + datesIndicator.style.marginLeft = "auto"; + + indicatorsMap[datesKey] = datesIndicator; + indicatorsMap[liveKey] = liveIndicator; + } + + function getIndicatorsMap(){ + return indicatorsMap; + } + + return { + loadIndicators: loadIndicators, + getIndicatorsMap: getIndicatorsMap + } + +})() + let graphs = (function (){ let dataset_to_graph_map = {}; // a dictionnary mapping a variable name to a two values array, containing its graph index and its position inside the graph let blocks, liveMode=true, top_vars=[], bottom_vars=[]; @@ -305,6 +327,8 @@ let graphs = (function (){ let resolution = undefined; + let created = false; + let container = document.createElement('div'); container.classList.add("graphs-container"); @@ -398,11 +422,17 @@ let graphs = (function (){ * @param {boolean} mode - Tells if we are in live mode or not */ function setLiveMode(mode=null) { - if (mode !== null) liveMode = mode; + if (mode !== null){ + liveMode = mode; + if(mode) globalIndicators.getIndicatorsMap()[liveKey].changeToEnable(); + else globalIndicators.getIndicatorsMap()[liveKey].changeToDisable(); + } if (liveMode && cursorLinePos === null) - gotoNowElm.innerHTML = ''; + // gotoNowElm.innerHTML = ''; + globalControls.getControlsMap()[goToNowKey].changeToAlt(); else - gotoNowElm.innerHTML = 'go to now'; + // gotoNowElm.innerHTML = 'go to now'; + globalControls.getControlsMap()[goToNowKey].changeToMain(); } /** @@ -564,6 +594,7 @@ let graphs = (function (){ function setMinMax(min, max){ currentMaxTime = max; currentMinTime = min; + globalIndicators.getIndicatorsMap()[datesKey].update(currentMinTime); for (let gr of graph_array) { if (gr) gr.setMinMax(min, max); } @@ -594,7 +625,8 @@ let graphs = (function (){ legendFlag = true; let trect = evt.target.getBoundingClientRect(); let X = evt.clientX - trect.x, Y = evt.clientY - trect.y; - showLegends(true, false); + displayAllLegends(); + // showLegends(true, false); cursorLine(X); setLiveMode(); update(); @@ -720,6 +752,36 @@ let graphs = (function (){ } } + function zoomIn(){ + console.log("Zoomed in !"); + + let someGraph = graph_array[0]; + let xTk = someGraph.chart.options.scales.xAxes[0].ticks; + let pZoom = 0.2; //window width for the zoom (a proportion of the current window, centered) + let delta = (xTk.max - xTk.min)*pZoom/2; + xTk.max -= delta; + xTk.min += delta; + + if (liveMode && xTk.max < lastTime) setLiveMode(false); + setMinMax(xTk.min, xTk.max); + updateAuto(); + } + + function zoomOut(){ + console.log("Zoomed out !"); + + let someGraph = graph_array[0]; + let xTk = someGraph.chart.options.scales.xAxes[0].ticks; + let pZoom = 0.2; //window width for the zoom (a proportion of the current window, centered) + let delta = (xTk.max - xTk.min)*pZoom/2; + xTk.max += delta; + xTk.min -= delta; + + if (liveMode && xTk.max < lastTime) setLiveMode(false); + setMinMax(xTk.min, xTk.max); + updateAuto(); + } + /** * Function called at each mouse wheel step. * If zoom mode in x mode, disables liveMode if the visualisaiton window is older than the last known value and sets axis min and max @@ -778,6 +840,32 @@ let graphs = (function (){ resolution = Math.ceil((timeDelta / container.getBoundingClientRect().width)/1000) } + function shiftOlder(){ + + let someGraph = graph_array[0]; + let xTk = someGraph.chart.options.scales.xAxes[0].ticks; + let pShift = 0.2; //shift size the pan (a proportion of the current window) + let delta = (xTk.max - xTk.min)*pShift; + xTk.max -= delta; + xTk.min -= delta; + if (liveMode && xTk.max < lastTime) setLiveMode(false); + setMinMax(xTk.min,xTk.max); + updateAuto(); + } + + function shiftNewer(){ + + let someGraph = graph_array[0]; + let xTk = someGraph.chart.options.scales.xAxes[0].ticks; + let pShift = 0.2; //shift size the pan (a proportion of the current window) + let delta = (xTk.max - xTk.min)*pShift; + xTk.max += delta; + xTk.min += delta; + if (liveMode && xTk.max < lastTime) setLiveMode(false); + setMinMax(xTk.min,xTk.max); + updateAuto(); + } + /** * The function called when the viewing window is moved by the mouse. * @@ -826,6 +914,7 @@ let graphs = (function (){ */ function gotoNow() { cursorLine(null); + globalControls.getControlsMap()[cursorKey].changeToAlt(); if (!liveMode) { setMinMax(graphs.now() - (currentMaxTime - currentMinTime), graphs.now()); } @@ -877,51 +966,58 @@ let graphs = (function (){ activateUpdates(); - container.parentNode.querySelector('.panel').classList.add('graphics'); + let graphicsPanel = container.parentNode.querySelector('.panel') + graphicsPanel.classList.add('graphics'); + if(!created){ + globalControls.loadControls(graphicsPanel); + globalIndicators.loadIndicators(graphicsPanel); + } + - gotoNowElm.addEventListener('click', gotoNow); + + // gotoNowElm.addEventListener('click', gotoNow); //gotoNowElm.innerHTML = "go to now"; - container.parentNode.querySelector('.panel span').appendChild(gotoNowElm); + // container.parentNode.querySelector('.panel span').appendChild(gotoNowElm); // Removes the cursor then applies the changes - function removeCursor(evt=null) { - graphs.cursorLine(null); - graphs.update(); - } + // function removeCursor(evt=null) { + // graphs.cursorLine(null); + // graphs.update(); + // } if (isTouchDevice) { doubleTap(removeCursor); } else { window.addEventListener('dblclick', removeCursor); showLegends(true, false); adjustLegends(); - let zoomMode = document.createElement('div'); + // let zoomMode = document.createElement('div'); /** * Sets the HTML button for the y-zoom depending on the current mode */ - function setInnerZoomMode(){ - if (currentZoomMode == 'y') { - zoomMode.innerHTML = " y-zoom"; - } else { - zoomMode.innerHTML = " y-zoom"; - } - prevTime = null; // reset zoom speed time - } - setInnerZoomMode(); + // function setInnerZoomMode(){ + // if (currentZoomMode == 'y') { + // zoomMode.innerHTML = " y-zoom"; + // } else { + // zoomMode.innerHTML = " y-zoom"; + // } + // prevTime = null; // reset zoom speed time + // } + // setInnerZoomMode(); /** * Inverts the zoom mode (x<->y) */ - function toggleZoomMode(){ - if (currentZoomMode == 'y') - currentZoomMode = 'x'; - else - currentZoomMode = 'y'; - setInnerZoomMode(); - for (let gr of graph_array) { - if (gr) gr.setZoomMode(currentZoomMode); - } - } - zoomMode.addEventListener('click', toggleZoomMode); - container.parentNode.querySelector('.panel span').appendChild(zoomMode); + // function toggleZoomMode(){ + // if (currentZoomMode == 'y') + // currentZoomMode = 'x'; + // else + // currentZoomMode = 'y'; + // setInnerZoomMode(); + // for (let gr of graph_array) { + // if (gr) gr.setZoomMode(currentZoomMode); + // } + // } + // zoomMode.addEventListener('click', toggleZoomMode); + // container.parentNode.querySelector('.panel span').appendChild(zoomMode); } // The cross to display "main" panel at the location of the graphs @@ -943,7 +1039,39 @@ let graphs = (function (){ console.log("MAIN") currentSwiper.slideNext(); }); - container.parentNode.querySelector('.panel span').appendChild(gotoMainElm); + // container.parentNode.querySelector('.panel span').appendChild(gotoMainElm); + if(!created){ + graphicsPanel.appendChild(gotoMainElm); + created = true; + } + } + + + function setInnerZoomMode(){ + if (currentZoomMode == 'y') { + globalControls.getControlsMap()[xyKey].changeToAlt(); + } else { + globalControls.getControlsMap()[xyKey].changeToMain(); + } + prevTime = null; // reset zoom speed time + } + + // Callbacks + function toggleZoomMode(){ + if (currentZoomMode == 'y') + currentZoomMode = 'x'; + else + currentZoomMode = 'y'; + setInnerZoomMode(); + for (let gr of graph_array) { + if (gr) gr.setZoomMode(currentZoomMode); + } + } + + function removeCursor(evt=null) { + graphs.cursorLine(null); + globalControls.getControlsMap()[cursorKey].changeToAlt(); + graphs.update(); } /** @@ -981,6 +1109,16 @@ let graphs = (function (){ //bringToFront(null); } + function displayAllLegends(){ + showLegends(true, false); + globalControls.getControlsMap()[legendsKey].changeToAlt(); + } + + function hideAllLegends(){ + showLegends(false, false); + globalControls.getControlsMap()[legendsKey].changeToMain(); + } + /** * Adjust the legend window depending on the position of the last legend */ @@ -1080,6 +1218,7 @@ let graphs = (function (){ cursorElement.style.display = 'block'; cursorElement.style.left = (cursorLinePos - 1) + 'px'; cursorElement.style.height = window.innerHeight + 'px'; + globalControls.getControlsMap()[cursorKey].changeToMain(); } return cursorLinePos; } @@ -1141,6 +1280,16 @@ let graphs = (function (){ setLiveMode: setLiveMode, cursorLine: cursorLine, bringToFront: bringToFront, + // Exposing callbacks for controls and indicators + gotoNow: gotoNow, + displayAllLegends: displayAllLegends, + hideAllLegends: hideAllLegends, + toggleZoomMode: toggleZoomMode, + removeCursor: removeCursor, + zoomOut: zoomOut, + zoomIn: zoomIn, + shiftOlder: shiftOlder, + shiftNewer: shiftNewer, } })(); @@ -1484,6 +1633,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){ } else { graphs.cursorLine(null); legend.style.display = 'none'; + globalControls.getControlsMap()[legendsKey].changeToMain(); } }