Take last 30s values for live update (influx), added doc in Js Graphics

This commit is contained in:
l_samenv
2024-07-25 10:43:44 +02:00
parent 5a82601e8e
commit 676e7e4f10
4 changed files with 242 additions and 38 deletions

View File

@ -246,8 +246,8 @@ let graphs = (function (){
/**
*
* @param {*} gindex
* Creates the "unit" selection block in the given gindex div graph container
* @param {number} gindex - The id of the graph container element where to display the selection block
*/
function createSelection(gindex){
let graph_elm = graph_elm_array[gindex];
@ -316,10 +316,17 @@ let graphs = (function (){
gotoNowElm.innerHTML = 'go to now';
}
/**
* Calls the /graph route with the variables of the block
* Adds the received dataset in the graph being created
* Sets the visualization window, conditionnaly autoscale, applies the changes, and show the legend
* @param {number} gindex - The position of the graph in the container
* @param {{tag:string, unit:string, curves:[{name:string, label:string, color:string, original_color:string}]}} block - The information of the block to create
*/
function createGraph(gindex, block){
clear(gindex);
tag_dict[block.tag] = gindex;
let dict = {} //
let dict = {} // {string: [name:string, label:string, color:string, original_color:string]}
for (let curve of block.curves) {
if (curve.show !== false) {
vars_array[gindex].push(curve.name);
@ -359,6 +366,7 @@ let graphs = (function (){
showLegends(legendFlag, false);
if (legendFlag) adjustLegends();
// Was here before
// result = AJAX( "http://" + hostPort +
// "/updategraph?variables=" + variables() +
// "&id=" + clientID).getJSON().then(function(data) {
@ -388,6 +396,11 @@ let graphs = (function (){
dataset_to_graph_map[key] = [gindex, graph.addDataset(key, data, data_opts)];
}
/**
* Sets the y-axis of the chart to scale the curves (window matches the maximum amd minimum of all the curves)
* @param {*} chart - The chart with whihch to scale the y-axis
* @returns If the minimun y-value of all the curves of the charts is greater than the maximum y-value (same)
*/
function autoScale(chart) {
axis = chart.options.scales.yAxes[0];
tax = chart.options.scales.xAxes[0].ticks;
@ -464,7 +477,11 @@ let graphs = (function (){
}
/**
* Responsible for new data being displayed on chart */
* Adds a data point to the variable's curve
* @param {string} key - The name of the variable the data point is being added to
* @param {{x: number, y: number}} data - The new data point to append
* @returns If the variable is not in the displayed graphs
* */
function newDataHandler(key, data){
if(!(key in dataset_to_graph_map))
return
@ -473,6 +490,12 @@ let graphs = (function (){
graph_array[i[0]].pushData(i[1], data)
}
/**
* Function called when the graph container is clicked
* Shows the legend, disable livemode, put a cursor then applies the changes
* If the click is located on the legend, brings it to the front
* @param {*} evt - The JS event triggered by the click
*/
function clickHandler(evt) {
if(evt.target.tagName == "CANVAS"){
legendFlag = true;
@ -492,6 +515,12 @@ let graphs = (function (){
}
container.addEventListener('click', clickHandler)
/**
* Sets (overwrite) the data (curve) of the given variable
* @param {string} key - The name of the variable to set the data for
* @param {[{x: number y: number}]} data - The data to set
* @returns If the variable is not in the graphs
*/
function setDataFromKey(key, data){
if(!(key in dataset_to_graph_map))
return
@ -499,6 +528,10 @@ let graphs = (function (){
graph_array[i[0]].setData(i[1], data);
}
/**
* Gets the available variables
* @returns An array of strings containing the name of the available variables
*/
function variables() {
let vardict = {};
for (let vars of vars_array) {
@ -509,6 +542,12 @@ let graphs = (function (){
return Object.keys(vardict);
}
/**
* Gets the curve for all the variables within a timerange then updates the charts. Called in checkReload
* This method is almost the same as createGraph. The main difference is that this one does not create new dataset for the variable, but sets its values (overwrite)
* @param {number} min - The lower bound of the timerange, which is a unix timestamp in milliseconds
* @param {number} max - The upper bound of previous
*/
function reloadData(min, max){
min = min/1000;
@ -531,6 +570,7 @@ let graphs = (function (){
}
}
console.log("RELOAD")
// Was here before
// AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // activate updates
// result = AJAX("http://" + hostPort +
// "/updategraph?variables=" + variables() +
@ -539,18 +579,17 @@ let graphs = (function (){
// console.log('LIVE reload', liveMode)
// })
// result = AJAX("http://" + hostPort +
// "/updategraph?"+
// "id=" + clientID).getJSON().then(function(data) {
// setLiveMode(data.live);
// console.log('LIVE reload', liveMode)
// })
updateAuto(false);
//update();
});
}
/**
* If the visualisation window is bigger than the time extremas of the curves, ask for the data, then autoscale if needed and apply the changes
* Called in updateAuto (conditionnal)
* @param {*} graph - The graph object to check if reload is needed
* @returns When data is received (no need to autoScale and update as it is done in reloadData)
*/
function checkReload(graph){
let tk = graph.chart.options.scales.xAxes[0].ticks;
let xmin = tk.min, xmax = tk.max;
@ -575,12 +614,22 @@ let graphs = (function (){
graph.update();
}
/**
* Triggers the update of each graph
*/
function update(){
for (let gr of graph_array.slice(0, ngraphs)) {
if (gr) gr.update();
}
}
/**
* 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 in y mode, disable the autoscale
* then applies the changes
* @param {*} graph - The graph Object on which the zoom callback has to be called
*/
function zoomCallback(graph){
let tk, min, max;
if (currentZoomMode == 'y') {
@ -624,6 +673,14 @@ let graphs = (function (){
update();
}
/**
* The function called when the viewing window is moved by the mouse.
*
* Disables live mode if the new max time of the viewing window is lesser than the last known value,
* then sets the min ans max time axis for all the graphs
* then applies changes
* @param {*} graph - The graph for which the function has to be called
*/
function panCallback(graph){
let tk = graph.chart.options.scales.xAxes[0].ticks;
let xmin = tk.min, xmax = tk.max;
@ -632,7 +689,11 @@ let graphs = (function (){
update();
}
/**
* Sets the viewing window for all graphs if upper bound of the displayed time range is greater than now in live mode,
* then checks if the data has to be reloaded or simply conditionnaly autoscales then applies the changes
* @param {*} check - Tells if the data has to be potentially reloaded
*/
function updateAuto(check=true){
if (liveMode) {
max = now();
@ -645,7 +706,7 @@ let graphs = (function (){
}
for (let gr of graph_array.slice(0, ngraphs)) {
if (gr) {
if (check) {
if (check) { // autoscaleIf and update are done in checkReload
checkReload(gr);
} else {
gr.autoScaleIf();
@ -655,6 +716,9 @@ let graphs = (function (){
}
}
/**
* Removes the cursor, sets the window visualisation to [now-previousDelta, now], goes for live mode and updates
*/
function gotoNow() {
cursorLine(null);
if (!liveMode) {
@ -678,6 +742,11 @@ let graphs = (function (){
}
*/
/**
* Holds the received variables from the /getvars call, gets the server time, insert slide (?),
* create the graphs, activate SSE graph-update messages, sets the different event listeners
* @param {[{tag:string, unit:string, curves:[{name:string, label:string, color:string, original_color:string}]}]} blocks_arg -
*/
function receivedVars(blocks_arg){
maxTime = timeRange[1]*1000;
minTime = timeRange[0]*1000;
@ -709,6 +778,7 @@ let graphs = (function (){
//gotoNowElm.innerHTML = "go to now";
container.parentNode.querySelector('.panel span').appendChild(gotoNowElm);
// Removes the cursor then applies the changes
function removeCursor(evt=null) {
graphs.cursorLine(null);
graphs.update();
@ -720,6 +790,9 @@ let graphs = (function (){
showLegends(true, false);
adjustLegends();
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 = "<strong>&#9746;</strong> y-zoom";
@ -729,7 +802,9 @@ let graphs = (function (){
prevTime = null; // reset zoom speed time
}
setInnerZoomMode();
/**
* Inverts the zoom mode (x<->y)
*/
function toggleZoomMode(){
if (currentZoomMode == 'y')
currentZoomMode = 'x';
@ -766,7 +841,7 @@ let graphs = (function (){
}
/**
* New function to activate the graph updates
* New function to activate the graph updates (API call to enbale SSE on the server for the curves)
*/
function activateUpdates(){
@ -779,10 +854,16 @@ let graphs = (function (){
}
// Obvious
function getBlocks(){
return blocks;
}
/**
* Triggers the showLegend method of each graph and updates them if needed
* @param {*} flag - Tells if the legends has to be shown
* @param {*} doUpdate - Tells if the graphs have to update
*/
function showLegends(flag, doUpdate) {
for (let gr of graph_array) {
if (gr) {
@ -794,6 +875,9 @@ let graphs = (function (){
//bringToFront(null);
}
/**
* Adjust the legend window depending on the position of the last legend
*/
function adjustLegends() {
let lastx = 0, lasty = 0, lasty0 = 0, lasty1 = 0, miny = 0;
let ys = 22;
@ -818,6 +902,9 @@ let graphs = (function (){
}
}
/**
* Creates the graphs or selection for each displayed graph
*/
function createGraphs() {
let n = Math.max(2, Math.floor(window.innerHeight / 200));
@ -868,6 +955,12 @@ let graphs = (function (){
cursorElement.classList.add('cursorline');
container.appendChild(cursorElement);
/**
* Displays the cursor line at the given x position
* @param {number} setpos - The x position in pixels of the cursor to display
* @param {boolean} query - (Never set to true in any of the calls)
* @returns The x position in pixels of the cursor
*/
function cursorLine(setpos, query=false) {
if (query) {
if (!legendFlag) return null;
@ -885,6 +978,9 @@ let graphs = (function (){
return cursorLinePos;
}
/**
* On resize, recreate the graphs and their legend, amd removes the cursor if displayed
*/
function resizeHandler() {
if (blocks) { // prevent error when graphics are not used
createGraphs();
@ -900,6 +996,10 @@ let graphs = (function (){
let frontLegend = null;
/**
* Brings the given legend to the front
* @param {*} legend - The legend to put at the front
*/
function bringToFront(legend) {
if (legend != frontLegend) {
if (frontLegend) {
@ -948,7 +1048,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
let parent = document.createElement("div");
parent.classList.add("chart-container");
let dselect = document.createElement('div');
let dselect = document.createElement('div'); //the clickable unit to select the curves we want to display
dselect.classList.add('dselect');
dselect.innerHTML = "[" + tag + "]";
dselect.addEventListener('click', function(e){
@ -1094,6 +1194,12 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
controls.classList.add('controls');
legend.appendChild(controls);
/**
* Adds the HTML content into the contols (legend top bar) of each legend, with a callback when the added control is clicked
* @param {*} inner - The HTML content to add
* @param {*} callback - The callback triggered on click
* @returns The added HTML content with its callback
*/
function addControl(inner, callback){
let c = document.createElement('div');
c.classList.add('control');
@ -1161,6 +1267,12 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
let startX=0,startY=0, startElX=0, startElY=0,legendmoving=false;
/**
* Position the legend window at the given x and y (potentially adjusted)
* @param {number} x - The x position of the top left hand corner
* @param {number} y - The y position of the top left hand corner
* @returns If the legend cannot be displayed
*/
function positionLegend(x, y) {
let lrect = legend.getBoundingClientRect();
let prect = parent.getBoundingClientRect();
@ -1192,6 +1304,11 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
legendAnchor.style.top = y + 'px';
}
/**
* The callback called if the legend is moving. Sets the position of the legend at the mouse position.
* @param {*} e The JS event
* @return If the mouse does not move enough
*/
function legendmousemove(e){
if (Math.abs(e.pageX-startX) + Math.abs(e.pageY-startY) < 4) return;
legendmoving = true;
@ -1199,6 +1316,10 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
positionLegend(x, y);
}
/**
* Removes the different listeners on the legend when the mouse press is finished (within 200ms)
* @param {*} e - The JS event
*/
function legendmouseup(e){
setTimeout(function(){
legendmoving=false;
@ -1208,6 +1329,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
window.removeEventListener('blur', legendmouseup);
}
// Adds the different event listeners on the legend when it is clicked
legend.addEventListener('mousedown', function(e){
if(e.which !== 1){
return;
@ -1222,6 +1344,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
window.addEventListener('blur', legendmouseup);
})
// Brings the legend to the front is the mouse hovers it
legend.addEventListener('mouseover', function(e){
graphs.bringToFront(legend);
});
@ -1245,6 +1368,10 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
graphs.bringToFront(legend);
});
/**
* Shows the legend or hide it with the cursor
* @param {*} flag - Tells if we need to show or note (+ cursor)
*/
function showLegend(flag){
if (flag) {
legend.style.display = 'flex';
@ -1254,14 +1381,20 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
}
/**
* Sets the zoom mode of the current graph
* @param {string} to - The zoom mode to set
*/
function setZoomMode(to){
chart.options.zoom.mode = to;
}
// Unused
function setPanOnOff(to){
chart.options.pan.enabled = to;
}
// Unused
function addTime(data){
console.log('OBSOLETE addTime');
chart.data.labels = data
@ -1269,7 +1402,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
/**
* Adds a dataset (curve) to the current graph, and manages the legend for it
* Adds a dataset (curve) to the current graph, and adds its legend entry in the graph legend
* @param {string} key - The curve name (variable)
* @param {*} data - The corresponding data points for this curve
* @param {*} opts - Some options for the curve (color, label)
@ -1358,11 +1491,20 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
return dataset_index;
}
/**
* Autoscale the graphs or reset the autoscale button of each graph
* @param {boolean} clear - Tells if the autoscale button has to be reset
*/
function autoScaleIf(clear=false) {
if (clear) setAutoScale(false);
if (autoScaleFlag) graphs.autoScale(chart);
}
/**
* Appends the data_point at the end of the dataset at the given dataset_index in the current Graph
* @param {number} dataset_index - The index of the dataset (curve) in the current Graph
* @param {{x: number, y: number}} data_point - The new data point to append
*/
function pushData(dataset_index, data_point){
data = chart.data.datasets[dataset_index].data;
//if (chart.data.datasets[dataset_index].key == 'tt:target')
@ -1374,12 +1516,17 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
data.push(data_point);
}
/**
* Sets (overwrites) the data for a curve (variable)
* @param {*} index - The index of the curve (variable) in its graph object (Chart)
* @param {*} data - The data to set at the given index curve
*/
function setData(index, data){
chart.data.datasets[index].data = data;
}
/**
* Sets the current viewing window to min and max
* Sets the current viewing window (axis) to min and max (for x values)
* @param {number} min - The minimum timestamp in milliseconds of the viewing window
* @param {number} max - The maximum timestamp in milliseconds of the viewing window
*/
@ -1435,6 +1582,10 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
ax.ticks.min = min;
}
/**
* Triggers the autocale of all the Graphs, then applies the changes to them, and finally updates the HTML autoscale button
* @param {boolean} flag - Tells if the autoscale has been set or not
*/
function setAutoScale(flag) {
autoScaleFlag = flag;
if (autoScaleFlag) {
@ -1446,10 +1597,18 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
}
/**
* Inverts the type of the y-axis (linear <-> logarithmic)
* Called when log button in the legend is clicked
*/
function toggleAxesType(){
setAxesType((chart.options.scales.yAxes[0].type=== 'linear') ? 'logarithmic' : 'linear');
}
/**
* Sets the y-axis type with a 800ms animation, then applies the changes
* @param {string} type - The axis type to set
*/
function setAxesType(type){
scaleType = type;
if(type == "linear"){
@ -1464,7 +1623,10 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
setTimeout(function(){chart.options.animation.duration = 0;},850)
}
/**
* Updates the single value point in the legend for each curve in each graph based on the position of the cursor.
* @returns if there is no cursor (so nothing to show)
*/
function redraw(){
x = graphs.cursorLine(canvas.clientWidth, true);
if (x === null) return;
@ -1501,11 +1663,18 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
*/
}
/**
* Applies the changes to the chart object and redraws the legend (single value)
*/
function update(){
chart.update();
redraw();
}
/**
* Sets the digits of the legend labels depending on the extremas of the curves for this graph
* @param {number} min - The mimimum y-value of all the curves of the graph
* @param {number} max - The maximum y-value of all the curves of the graph
*/
function setLabelDigits(min, max) {
let dig = parseInt(Math.max(-min, max) / (max - min)).toFixed(0).length + 3;
let l = 0;
@ -1548,9 +1717,9 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
/**
* Called when new data is received from the server.
* Called when new data is received from the server (SSE).
* Appends new data to the corresponding curves' datasets
* @param {*} graph - The graph response from the server
* @param {{type:"graph-update", reduced:boolean, time:number, graph:{string:[[(number),(number)]]}}} graph - The graph response from the server
*/
function updateCharts2(graph){
if(!graphs.doUpdates()) {