Functionnal toolbar and indicators

This commit is contained in:
l_samenv
2024-08-06 13:53:58 +02:00
parent 2b829248cd
commit 83d45e511f
5 changed files with 250 additions and 75 deletions

View File

@ -1,6 +1,6 @@
.control-global{ .control-global{
width: 30px; width: 28px;
height: 30px; height: 28px;
border: 1px solid dimgray; border: 1px solid dimgray;
box-sizing: border-box; box-sizing: border-box;
transition: border 0.25s; transition: border 0.25s;

View File

@ -1,18 +1,40 @@
class DatesIndicator extends HTMLElement{ class DatesIndicator extends HTMLElement{
constructor(oldestTimestamp, newestTimestamp){ constructor(timestamp){
super(); super();
this.oldestDate = this.timestampToString(oldestTimestamp); this.formattedDate = this.timestampToString(timestamp);
this.newestDate = this.timestampToString(newestTimestamp); }
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){ timestampToString(timestamp){
let date = new Date(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){ update(timestamp){
this.oldestDate = this.timestampToString(oldestTimestamp); this.formattedDate = this.timestampToString(timestamp);
this.newestDate = this.timestampToString(newestTimestamp);
this.render() this.render()
} }
@ -24,9 +46,7 @@ class DatesIndicator extends HTMLElement{
this.innerHTML = ` this.innerHTML = `
<link rel="stylesheet" href="components/states_indicator/dates/dates.css"> <link rel="stylesheet" href="components/states_indicator/dates/dates.css">
<div class="dates"> <div class="dates">
${this.oldestDate} ${this.formattedDate}
->
${this.newestDate}
</div> </div>
` `
} }

View File

@ -7,20 +7,21 @@
justify-content: flex-end; justify-content: flex-end;
} }
.panel.graphics span{ .panel.graphics span:first-child{
margin: 0 1em; display: none;
/* margin: 0 1em;
display: flex; display: flex;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none; */
} }
.panel.graphics div{ /* .panel.graphics div{
margin-left: 1em; margin-left: 1em;
cursor: pointer; cursor: pointer;
} } */
#control_bar{ #control_bar{
height: 100%; height: 28px;
background-color: dimgray; background-color: dimgray;
border-top-left-radius: 12px; border-top-left-radius: 12px;
border-top-right-radius: 12px; border-top-right-radius: 12px;
@ -28,7 +29,8 @@
padding-right: 12px; padding-right: 12px;
display: flex; display: flex;
column-gap: 5px; column-gap: 5px;
margin-left: 100px; margin-left: 120px;
margin-top: 2px;
} }
/*********************/ /*********************/

View File

@ -24,12 +24,15 @@
text-align: center; text-align: center;
background-color: #303030; background-color: #303030;
color: white; color: white;
padding: 6px 6px 6px 6px; /* padding: 6px 6px 6px 6px; */
position: absolute; position: absolute;
z-index: 20; z-index: 20;
width: 100%; width: 100%;
height: 30px; height: 30px;
} }
.panel:not(.graphics){
padding: 6px 6px 6px 6px;
}
.slide-close-icon { .slide-close-icon {
transition: 0.4s; transition: 0.4s;

View File

@ -217,26 +217,21 @@ let globalControls = (function (){
function loadControls(panel){ function loadControls(panel){
let controlBar = document.createElement("div"); let controlBar = document.createElement("div");
controlBar.id = "control_bar" controlBar.id = "control_bar";
panel.appendChild(controlBar); panel.appendChild(controlBar);
let jumpControl = new Control("res/jump.png", "res/jump_blocked.png", "Jump", dummyCallback); 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 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", dummyCallback); 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", dummyCallback); 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", dummyCallback); 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 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",dummyCallback); 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", dummyCallback, dummyCallback); let legendsControl = new Control("res/display_legends.png", "res/remove_legends.png", "Legends", graphs.displayAllLegends, graphs.hideAllLegends);
let now = Date.now();
let old = now - 1000*3600;
let dates = new DatesIndicator(old, now);
let liveState = new LiveStateIndicator();
controlBar.appendChild(jumpControl) controlBar.appendChild(jumpControl)
controlBar.appendChild(goToNowControl) controlBar.appendChild(goToNowControl)
@ -253,12 +248,6 @@ let globalControls = (function (){
controlBar.appendChild(legendsControl); controlBar.appendChild(legendsControl);
legendsControl.changeToAlt(); 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[jumpKey] = jumpControl;
controlsMap[goToNowKey] = goToNowControl; controlsMap[goToNowKey] = goToNowControl;
controlsMap[zoomInKey] = zoomInControl; controlsMap[zoomInKey] = zoomInControl;
@ -267,7 +256,7 @@ let globalControls = (function (){
controlsMap[shiftNewerKey] = shiftNewerControl; controlsMap[shiftNewerKey] = shiftNewerControl;
controlsMap[xyKey] = xyControl; controlsMap[xyKey] = xyControl;
controlsMap[cursorKey] = cursorControl; controlsMap[cursorKey] = cursorControl;
controlsMap[legendsKey] = legendsControl; controlsMap[legendsKey] = legendsControl;
} }
function getControlsMap(){ 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 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 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=[]; let blocks, liveMode=true, top_vars=[], bottom_vars=[];
@ -305,6 +327,8 @@ let graphs = (function (){
let resolution = undefined; let resolution = undefined;
let created = false;
let container = document.createElement('div'); let container = document.createElement('div');
container.classList.add("graphs-container"); container.classList.add("graphs-container");
@ -398,11 +422,17 @@ let graphs = (function (){
* @param {boolean} mode - Tells if we are in live mode or not * @param {boolean} mode - Tells if we are in live mode or not
*/ */
function setLiveMode(mode=null) { 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) if (liveMode && cursorLinePos === null)
gotoNowElm.innerHTML = ''; // gotoNowElm.innerHTML = '';
globalControls.getControlsMap()[goToNowKey].changeToAlt();
else 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){ function setMinMax(min, max){
currentMaxTime = max; currentMaxTime = max;
currentMinTime = min; currentMinTime = min;
globalIndicators.getIndicatorsMap()[datesKey].update(currentMinTime);
for (let gr of graph_array) { for (let gr of graph_array) {
if (gr) gr.setMinMax(min, max); if (gr) gr.setMinMax(min, max);
} }
@ -594,7 +625,8 @@ let graphs = (function (){
legendFlag = true; legendFlag = true;
let trect = evt.target.getBoundingClientRect(); let trect = evt.target.getBoundingClientRect();
let X = evt.clientX - trect.x, Y = evt.clientY - trect.y; let X = evt.clientX - trect.x, Y = evt.clientY - trect.y;
showLegends(true, false); displayAllLegends();
// showLegends(true, false);
cursorLine(X); cursorLine(X);
setLiveMode(); setLiveMode();
update(); 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. * 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 * 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) 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. * The function called when the viewing window is moved by the mouse.
* *
@ -826,6 +914,7 @@ let graphs = (function (){
*/ */
function gotoNow() { function gotoNow() {
cursorLine(null); cursorLine(null);
globalControls.getControlsMap()[cursorKey].changeToAlt();
if (!liveMode) { if (!liveMode) {
setMinMax(graphs.now() - (currentMaxTime - currentMinTime), graphs.now()); setMinMax(graphs.now() - (currentMaxTime - currentMinTime), graphs.now());
} }
@ -877,51 +966,58 @@ let graphs = (function (){
activateUpdates(); 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"; //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 // Removes the cursor then applies the changes
function removeCursor(evt=null) { // function removeCursor(evt=null) {
graphs.cursorLine(null); // graphs.cursorLine(null);
graphs.update(); // graphs.update();
} // }
if (isTouchDevice) { if (isTouchDevice) {
doubleTap(removeCursor); doubleTap(removeCursor);
} else { } else {
window.addEventListener('dblclick', removeCursor); window.addEventListener('dblclick', removeCursor);
showLegends(true, false); showLegends(true, false);
adjustLegends(); adjustLegends();
let zoomMode = document.createElement('div'); // let zoomMode = document.createElement('div');
/** /**
* Sets the HTML button for the y-zoom depending on the current mode * Sets the HTML button for the y-zoom depending on the current mode
*/ */
function setInnerZoomMode(){ // function setInnerZoomMode(){
if (currentZoomMode == 'y') { // if (currentZoomMode == 'y') {
zoomMode.innerHTML = "<strong>&#9746;</strong> y-zoom"; // zoomMode.innerHTML = "<strong>&#9746;</strong> y-zoom";
} else { // } else {
zoomMode.innerHTML = "<strong>&#9744;</strong> y-zoom"; // zoomMode.innerHTML = "<strong>&#9744;</strong> y-zoom";
} // }
prevTime = null; // reset zoom speed time // prevTime = null; // reset zoom speed time
} // }
setInnerZoomMode(); // setInnerZoomMode();
/** /**
* Inverts the zoom mode (x<->y) * Inverts the zoom mode (x<->y)
*/ */
function toggleZoomMode(){ // function toggleZoomMode(){
if (currentZoomMode == 'y') // if (currentZoomMode == 'y')
currentZoomMode = 'x'; // currentZoomMode = 'x';
else // else
currentZoomMode = 'y'; // currentZoomMode = 'y';
setInnerZoomMode(); // setInnerZoomMode();
for (let gr of graph_array) { // for (let gr of graph_array) {
if (gr) gr.setZoomMode(currentZoomMode); // if (gr) gr.setZoomMode(currentZoomMode);
} // }
} // }
zoomMode.addEventListener('click', toggleZoomMode); // zoomMode.addEventListener('click', toggleZoomMode);
container.parentNode.querySelector('.panel span').appendChild(zoomMode); // container.parentNode.querySelector('.panel span').appendChild(zoomMode);
} }
// The cross to display "main" panel at the location of the graphs // The cross to display "main" panel at the location of the graphs
@ -943,7 +1039,39 @@ let graphs = (function (){
console.log("MAIN") console.log("MAIN")
currentSwiper.slideNext(); 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); //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 * 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.display = 'block';
cursorElement.style.left = (cursorLinePos - 1) + 'px'; cursorElement.style.left = (cursorLinePos - 1) + 'px';
cursorElement.style.height = window.innerHeight + 'px'; cursorElement.style.height = window.innerHeight + 'px';
globalControls.getControlsMap()[cursorKey].changeToMain();
} }
return cursorLinePos; return cursorLinePos;
} }
@ -1141,6 +1280,16 @@ let graphs = (function (){
setLiveMode: setLiveMode, setLiveMode: setLiveMode,
cursorLine: cursorLine, cursorLine: cursorLine,
bringToFront: bringToFront, 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 { } else {
graphs.cursorLine(null); graphs.cursorLine(null);
legend.style.display = 'none'; legend.style.display = 'none';
globalControls.getControlsMap()[legendsKey].changeToMain();
} }
} }