Take last 30s values for live update (influx), added doc in Js Graphics
This commit is contained in:
35
README.md
35
README.md
@ -4,10 +4,45 @@ The WEB GUI client of SEA.
|
||||
|
||||
This repository contains the code of the server for the control and graphical parts, plus the client code (HTML, CSS, JS)
|
||||
|
||||
## Global architecture
|
||||
|
||||
The current server exposes some routes for the graphical part and the control part. It also serves the client files.
|
||||
|
||||
## Installation (!!! WIP !!!)
|
||||
|
||||
1. Clone this repository on the `~` folder on your machine
|
||||
2. If not done yet, activate a Python environnment
|
||||
3. Run the command `cd seaweb`
|
||||
|
||||
## Configuring the application (!!! WIP !!!)
|
||||
|
||||
|
||||
## Starting the application (!!! WIP !!!)
|
||||
|
||||
1. Run the command `cd ~/seaweb`
|
||||
|
||||
# Stopping the application (!!! WIP !!!)
|
||||
|
||||
1. Run the command `ps ax | grep seaweb`
|
||||
2. In the output of the previous command, identifiy the PID corresponding to the server process
|
||||
3. Run the command `kill <previously_identified_PID>`
|
||||
|
||||
## InfluxDB
|
||||
|
||||
(24/07/24) The InfluxDB instance is fed every 30 seconds with the last values contained in the timerange [now - 30s, now]. We do not know if this process is synchronized for all the measurements or not.
|
||||
|
||||
## Server
|
||||
|
||||
## Client
|
||||
|
||||
The way the main page is served (where you can select the instrument you want to interact with) has not been decided yet, even if its code is in this repository.
|
||||
|
||||
### Process
|
||||
|
||||
For a selected instrument, there is a single HTML file that holds the application : the `SEAWebClient.html` file, which is served as the main route. It includes all the JS files needed, meaning all the JS files located in the `client/jsFiles` folder excepted `SeaWebClientStart.js`, plus the external librairies (`client/externalFiles/`).
|
||||
|
||||
The entry point is the `SEAWebClientMain.js`, which has a `window.onload` function and which initiates all the content of the page, plus the responsitivity.
|
||||
|
||||
### External libraries
|
||||
|
||||
| Name | Version | Website |
|
||||
|
@ -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>☒</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()) {
|
||||
|
20
influxdb.py
20
influxdb.py
@ -98,16 +98,16 @@ class InfluxDataGetter:
|
||||
|
||||
return res
|
||||
|
||||
def poll_last_value(self, variables, time):
|
||||
def poll_last_values(self, variables, time):
|
||||
"""
|
||||
Polls the last value for the given variables that are not more recent that time[1].
|
||||
Polls the lastest values for the given variables that are in the range [time[1]-30s, time[1]].
|
||||
|
||||
Parameters :
|
||||
variables ([(str)]) : an array of variable names (Influx) to get the last known values for
|
||||
time ([int]) : the current asked timerange in the calling polling function (only second value used). It consists of two values which are Unix timestamps in seconds, first included, second excluded.
|
||||
|
||||
Returns :
|
||||
{(str):[[(int), (float)]]} : a dictionnary of points. The key is the name of the influx variable, and the value is an array of one pair (also array), the first value being the Unix timestamp in second (x), the seconds being the value (y).
|
||||
{(str):[[(int), (float)]]} : a dictionnary of points. The key is the name of the influx variable, and the value is an array of pairs (also array), the first value being the Unix timestamp in second (x), the seconds being the value (y).
|
||||
"""
|
||||
res = {}
|
||||
for variable in variables:
|
||||
@ -118,8 +118,9 @@ class InfluxDataGetter:
|
||||
variable_name_for_query = variable_name_for_query[:-len(".target")]
|
||||
is_target = True
|
||||
|
||||
point = self._get_last_value(variable_name_for_query, is_target, time)
|
||||
res[variable] = point
|
||||
points = self._get_last_values(variable_name_for_query, is_target, time)
|
||||
if len(points) > 0 :
|
||||
res[variable] = points
|
||||
return res
|
||||
|
||||
# ----- PRIVATE METHODS
|
||||
@ -366,9 +367,9 @@ class InfluxDataGetter:
|
||||
curve.insert(0, [time[0], value])
|
||||
return curve
|
||||
|
||||
def _get_last_value(self, variable, is_target, time):
|
||||
def _get_last_values(self, variable, is_target, time):
|
||||
"""
|
||||
Gets the last value for the given variable that are not more recent that time[1].
|
||||
Gets the lastest values for the given variable that are in [time[1]-30s, time[1]].
|
||||
|
||||
Parameters :
|
||||
variable (str) : the name (Influx) of the variable we want the last value of.
|
||||
@ -376,16 +377,15 @@ class InfluxDataGetter:
|
||||
time ([int]) : the current asked timerange in the calling polling function (only second value used). It consists of two values which are Unix timestamps in seconds, first included, second excluded.
|
||||
|
||||
Returns :
|
||||
[[(int), (float)]] : a point encapsuled in an array. The first value is the Unix timestamp in second (x), the seconds is the value (y)
|
||||
[[(int), (float)]] : an array of points (also arrays). The first value is the Unix timestamp in second (x), the seconds is the value (y)
|
||||
"""
|
||||
|
||||
res = []
|
||||
query = f"""
|
||||
from(bucket: "{self._bucket}")
|
||||
|> range(start: 0, stop: {time[1] + 1})
|
||||
|> range(start: {time[1]-30}, stop: {time[1]+1})
|
||||
|> filter(fn : (r) => r._measurement == "{variable}")
|
||||
|> filter(fn : (r) => r._field == "{"target_float" if is_target else "value_float"}")
|
||||
|> last()
|
||||
|> keep(columns: ["_time","_value"])
|
||||
|> yield(name: "res")
|
||||
"""
|
||||
|
@ -184,13 +184,13 @@ class InfluxGraph:
|
||||
else:
|
||||
self.time[1] = self.time[0] # Do not update (the current requested value is the last)
|
||||
if self.time[1] > self.time[0]:
|
||||
result = self.influx_data_getter.poll_last_value(self.variables, self.time)
|
||||
|
||||
result = self.influx_data_getter.poll_last_values(self.variables, self.time)
|
||||
for variable in self.lastvalues.keys():
|
||||
if result[variable][-1][0] > self.lastvalues[variable][0]:
|
||||
self.lastvalues[variable] = (result[variable][-1][0], result[variable][-1][1])
|
||||
else:
|
||||
del result[variable]
|
||||
if variable in result.keys():
|
||||
if result[variable][-1][0] > self.lastvalues[variable][0]:
|
||||
self.lastvalues[variable] = (result[variable][-1][0], result[variable][-1][1])
|
||||
else:
|
||||
del result[variable]
|
||||
|
||||
if int(self.time[1] / 60) != int(self.time[0] / 60):
|
||||
# Update unchanged values every plain minute
|
||||
|
Reference in New Issue
Block a user