make web client work

This commit is contained in:
2020-12-10 16:58:59 +01:00
parent 9e1d3b4e07
commit 1de819cd26
7 changed files with 380 additions and 209 deletions

View File

@ -86,7 +86,7 @@ function handleUpdateMessage(src, message) {
sizeChange();
} else {
clientTitle = message.instrument + " " + message.device;
console.log('loadBlocks')
console.log('loadBlocks', message);
loadFirstBlocks();
}
document.title = "SEA "+clientTitle;
@ -155,7 +155,6 @@ function handleUpdateMessage(src, message) {
case "graph-update":
//if (getUpdatesGraphics) {
//timeServer = message.time;
console.log("graph-update");
updateCharts2(message.graph);
//}
break;
@ -207,11 +206,12 @@ function updateValues(message, src) {
} else if (type == "input") {
var row = matches[j].parentNode.parentNode.parentNode;
row.style.backgroundColor = "white";
var oldValue = matches[j].getAttribute("oldValue")
|| matches[j].value;
if (value != matches[j].value && value != oldValue) {
var mval = matches[j].value;
var oldValue = matches[j].getAttribute("oldValue");
if (oldValue === null) oldValue = mval;
if (value != mval && parseFloat(value) != parseFloat(mval) && value != oldValue) {
if (matches[j] == document.activeElement
|| oldValue != matches[j].value) {
|| oldValue != mval) {
row.style.backgroundColor = "orange";
} else {
matches[j].value = value;

View File

@ -106,51 +106,20 @@ function doubleTap(callback){
return {stop: function(){ window.removeEventListener('touchend', handler) }}
}
function maxAr(array){
function maxAr(array, tmin, tmax){
return Math.max.apply(Math, array.map(function(o) {
if (o.y == null) return -1e99;
if (o.y == null || o.x < tmin || o.x > tmax) return -1e99;
return o.y;
}));
}
function minAr(array){
function minAr(array, tmin, tmax){
return Math.min.apply(Math, array.map(function(o) {
if (o.y == null) return 1e99;
if (o.y == null || o.x < tmin || o.x > tmax) return 1e99;
return o.y;
}));
}
function autoScale(chart) {
axis = chart.options.scales.yAxes[0]
datasets = chart.data.datasets;
let max = -1e99;
let min = 1e99;
for (testwidth = 1; testwidth >= 0; testwidth--) {
for(let i = 0; i < datasets.length; i++){
ds = datasets[i];
if (ds.borderWidth == testwidth) continue;
let lmax = maxAr(ds.data);
let lmin = minAr(ds.data);
if(lmax > max)
max = lmax;
if(lmin < min)
min = lmin;
}
if (min < max) {
break;
} else if (min == max) {
max = min + 0.5;
min = max - 1.0;
break;
}
}
//console.log('autoScale', min, max);
axis.ticks.min = min - (max - min) * 0.05;
axis.ticks.max = max + (max - min) * 0.01;
axis.min = axis.ticks.min;
axis.max = axis.ticks.max;
}
function strFormat(str, significant_digits) {
if (str == null) return '';
evalue = str.toExponential(significant_digits-1).replace(/0*e/, 'e').replace(/\.e/, 'e').replace("e+", "e");
@ -163,7 +132,7 @@ function strFormat(str, significant_digits) {
let graphs = (function (){
let dataset_to_graph_map = {},
blocks, doUpdates=true, top_vars=[], bottom_vars=[], zoomed =false;
blocks, liveMode=true, top_vars=[], bottom_vars=[], zoomed =false;
let type = 'linear';
@ -175,6 +144,8 @@ let graphs = (function (){
let container = document.createElement('div');
container.classList.add("graphs-container");
let currentMinTime = 0;
let currentMaxTime = 0;
for (let i = 0; i < ngraphs; i++) {
let gr = document.createElement('div');
@ -242,7 +213,7 @@ let graphs = (function (){
}
//let varlist = top_vars.concat(bottom_vars);
varlist = vars_array[gindex];
let el =graph_array[gindex];
let el = graph_array[gindex];
AJAX("http://" + hostPort + "/graph?time=" + minTime/1000 + "," + maxTime/1000 + "&variables=" + varlist + "&id=" + clientID).getJSON().then(function(data){
//console.log('Graph', block, data)
@ -255,13 +226,10 @@ let graphs = (function (){
}
let pdata = [];
for(let e of data.graph[key]){
//if(e[1] == null || e[1] == null){
// continue;
//}
pdata.push({x: e[0]*1000, y: e[1]});
}
if(pdata.length > 0){
addDataset(gindex, key, [dict[key].label, dict[key].color, pdata])
addDataset(gindex, key, [dict[key].label, dict[key].color, pdata, dict[key].continuous])
/*console.log(timeRange);
if(data[data.length-1].x-data[0].x > d && data[data.length-1].x-data[0].x < (30*60+10)*1000){ // Adjust to requested time
d = data[data.length-1].x-data[0].x
@ -271,20 +239,91 @@ let graphs = (function (){
}
}
chart.setMinMax(minTime,maxTime);
// chart.autoScaleChart();
chart.autoScaleIf();
chart.update();
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // why this?
result = AJAX( "http://" + hostPort +
"/updategraph?variables=" + variables() +
"&id=" + clientID).getJSON().then(function(data) {
liveMode = data.live;
console.log('LIVE create', liveMode)
})
//console.log('UPDATE LIVE', result);
})
}
// add dataset to graph with graph_id
function addDataset(gindex, key, dataset){
let g = chart_array[gindex];
dataset_to_graph_map[key] = [gindex, g.addDataset(dataset)];
dataset_to_graph_map[key] = [gindex, g.addDataset(key, dataset)];
}
function autoScale(chart) {
axis = chart.options.scales.yAxes[0];
tax = chart.options.scales.xAxes[0].ticks;
datasets = chart.data.datasets;
let max = -1e99;
let min = 1e99;
// if there are datasets with values and think lines,
// consider them only. if not, consider all (second pass in the following loop)
let extraMin = min;
let extraMax = max;
for (testwidth = 1; testwidth >= 0; testwidth--) {
for (let i = 0; i < datasets.length; i++){
ds = datasets[i];
if (ds.borderWidth <= testwidth) continue;
let lmax = maxAr(ds.data, tax.min, tax.max);
let lmin = minAr(ds.data, tax.min, tax.max);
if(lmax > max)
max = lmax;
if(lmin < min)
min = lmin;
if (ds.data.length && liveMode) {
lasty = ds.data.slice(-1)[0].y;
console.log('LASTY', lasty);
extraMin = Math.min(extraMin, lasty);
extraMax = Math.max(extraMax, lasty);
}
}
if (min > max) continue; // do a second pass over all curves
break;
}
if (min > max) return;
if (min == max) {
if (min == 0) {
ystep = 1;
} else {
ystep = Math.abs(min * 0.01);
}
min -= ystep;
max += ystep;
} else {
ystep = (max - min) * 0.1;
if (liveMode) {
extraMin = Math.min(min, extraMin - ystep);
extraMax = Math.max(max, extraMax + ystep);
} else {
extraMin = min - ystep * 0.5;
extraMax = max + ystep * 0.5;
}
if (min >= axis.ticks.min && axis.ticks.min >= extraMin &&
max <= axis.ticks.max && axis.ticks.max <= extraMax) {
console.log('NOCHANGE')
return; // do not yet change
}
console.log(min, axis.ticks.min, extraMin)
console.log(max, axis.ticks.max, extraMax)
min = extraMin;
max = extraMax;
}
//console.log('autoScale', min, max, tax.min, tax.max);
axis.min = axis.ticks.min = min;
axis.max = axis.ticks.max = max;
}
function setMinMax(min, max){
currentMaxTime = max;
currentMinTime = min;
for (let ch of chart_array) {
if (ch) ch.setMinMax(min, max);
}
@ -326,6 +365,16 @@ let graphs = (function (){
chart_array[i[0]].reloadData(i[1], data);
}
function variables() {
let vardict = {};
for (let vars of vars_array) {
for (let v of vars) {
vardict[v] = 1;
}
}
return Object.keys(vardict);
}
function reloadData(min, max){
min = min/1000;
@ -334,14 +383,8 @@ let graphs = (function (){
}else{
max = max/1000;
}
let vardict = {};
for (let vars of vars_array) {
for (let v of vars) {
vardict[v] = 1;
}
}
AJAX("http://" + hostPort + "/graph?time=" + min + ","+max+"&variables=" + Object.keys(vardict) + "&id=" + clientID).getJSON().then(function(data){
AJAX("http://" + hostPort + "/graph?time=" + min + ","+max+"&variables=" + variables() + "&id=" + clientID).getJSON().then(function(data){
for(let key in data.graph){
let pdata = [];
for(let e of data.graph[key]){
@ -354,10 +397,13 @@ let graphs = (function (){
reloadDataFlag(key, pdata);
}
}
for (let ch of chart_array) {
if (ch) ch.autoScaleChart(); // should depend on a flag
}
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // why this ?
// AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // activate updates
result = AJAX("http://" + hostPort +
"/updategraph?variables=" + variables() +
"&id=" + clientID).getJSON().then(function(data) {
liveMode = data.live;
console.log('LIVE reload', liveMode)
})
update();
});
}
@ -365,19 +411,21 @@ let graphs = (function (){
function checkReload(chart){
let xmin = chart.options.scales.xAxes[0].ticks.min,
xmax = chart.options.scales.xAxes[0].ticks.max;
if(xmax < now()-10000){ // was 100000 = 100sec
doUpdates = false;
if (xmax < now()-100000) { // was 100000 = 100sec
if (liveMode) console.log('UPDATES OFF?')
//doUpdates = false;
}else{
doUpdates = true;
if (!liveMode) console.log('UPDATES ON?')
//doUpdates = true;
}
if(xmin < minTime || xmax > maxTime || xmax - xmin < 0.5 * (maxTime - minTime)){
if (xmin < minTime || xmax > maxTime || xmax - xmin < 0.5 * (maxTime - minTime)) {
//TODO: the criterium for getting finer resolution data should depend, if better res. is available
// this information has to come from the server
reloadData(xmin, xmax);
minTime = xmin;
maxTime = xmax;
} else {
autoScale(chart); // TODO: must depend on autoScale flag
if (chart.autoScaleFlag) autoScale(chart);
chart.update();
}
}
@ -387,7 +435,9 @@ let graphs = (function (){
xmax = chart.options.scales.xAxes[0].ticks.max;
setMinMax(xmin,xmax);
//console.log('zoompan', autoScaleFlag);
for (let ch of chart_array) {
ch.autoScaleIf();
if (ch) ch.redraw(redrawX);
}
update();
@ -399,15 +449,27 @@ let graphs = (function (){
}
}
let g_varlist = [];
function updateAllDisabled(){
// not used anymore?
AJAX("http://" + hostPort + "/graph?time="+timeRange+"&variables=" + g_varlist + "&id=" + clientID).getJSON().then(function(a){
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON()
});
function updateAuto(){
if (liveMode) {
max = now();
if (currentMaxTime && max > currentMaxTime) {
max = currentMaxTime + Math.min(60000, 0.1 * (currentMaxTime - currentMinTime));
setMinMax(currentMinTime, max);
reloadData(currentMinTime, max);
return;
}
}
for (let ch of chart_array) {
if (ch) {
ch.autoScaleIf();
ch.update();
}
}
}
/*
let g_varlist = [];
function getVarlist(blocks){
var varlist = [];
for (var i = 0; i < blocks.length; i++) {
@ -417,6 +479,7 @@ let graphs = (function (){
}
return varlist;
}
*/
let startTime, recvTime, minTime, maxTime;
@ -425,13 +488,14 @@ let graphs = (function (){
minTime = timeRange[0]*1000;
AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){
startTime = data.time[1]*1000;
maxTime = startTime;
maxTime = startTime + 60000;
console.log('MAXTIME', maxTime - Date.now());
minTime = data.time[0]*1000;
recvTime = performance.now();
});
g_varlist = getVarlist(nblocks)
// g_varlist = getVarlist(nblocks)
let f = 0;
insertSlide(f, "graphics", "graphics", container);
blocks = nblocks;
@ -514,13 +578,15 @@ let graphs = (function (){
zoompan: zoompan,
receivedVars: receivedVars,
createSelection: createSelection,
doUpdates: function(){return doUpdates},
doUpdates: function(){return liveMode},
update: update,
updateAuto: updateAuto,
now: now,
zoomed: zoomed,
checkReload: checkReload,
getBlocks: getBlocks,
createGraph: createGraph,
autoScale: autoScale,
}
})();
@ -567,7 +633,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
y1 = ticks[0];
y0 = ticks.slice(-1)[0];
span = y1 - y0;
step = Math.abs(span * 0.1).toExponential(0);
step = Math.abs(span * 0.3).toExponential(0);
if (step[0] > '5') {
step = '5' + step.substr(1);
} else if (step[0] > '2') {
@ -651,6 +717,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
}
});
let autoScaleFlag = true;
//console.log('create legend')
let legend = document.createElement('div');
@ -724,9 +791,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
graphs.zoompan(chart);
});*/
addControl("Autoscale Y", function(){
autoScale(chart);
update();
let autoScaleRow = addControl("Autoscale Y <strong>on</strong> off", function(){
toggleAutoScale();
});
addControl("Go to now", function(){
@ -847,60 +913,91 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
chart.update();
}
function addDataset(data){
function addDataset(key, data){
let dataset_index = chart.data.datasets.length;
chart.data.datasets.push({data: data[2], label: data[0], origLabel: data[0],
spanGaps: false, lineJoin: 'round', borderWidth: 2,
chart.data.datasets.push({data: data[2], label: data[0], key: key,
spanGaps: false, lineJoin: 'round', borderWidth: 2, steppedLine: data[3] == 0,
borderColor: data[1],fill: false, pointRadius: 0, tension:0, showLine: true});
let dataset = chart.data.datasets[dataset_index];
let legendel = document.createElement('div');
let legendelvalue = document.createElement('div');
legendelvalue.classList.add('value');
legendels[data[0]] = legendelvalue;
legendels[key] = legendelvalue;
legendel.classList.add('legendel')
let color = document.createElement('div');
color.classList.add('color')
color.style.backgroundColor = dataset.borderColor;
legendel.appendChild(color);
legendel.innerHTML += dataset.label;
legendel.addEventListener('click', function(){
let dlabel = document.createElement('div');
dlabel.innerHTML = dataset.label;
dlabel.addEventListener('click', function(evt){
/*
console.log('LABEL', evt.target)
if(legendmoving)
return
let meta = dataset._meta[Object.keys(dataset._meta)[0]]
/*
if(meta.hidden == null){
meta.hidden = true;
addClass(legendel, 'hidden');
}else{
meta.hidden = null;
delClass(legendel, 'hidden');
}
legendel.firstChild.style.height = '2px';
dataset.borderWidth = 2;
labelClicked = true;
//console.log('LABEL', evt.target)
*/
if (dataset.borderWidth == 1) {
dataset.borderWidth = 2;
} else {
dataset.borderWidth = 1;
}
autoScale(chart);
chart.update();
})
});
legendel.appendChild(dlabel);
legendel.appendChild(legendelvalue);
legendel.addEventListener('click', function(evt){
if (legendmoving) return;
for (let k in legendels) {
// set all labels to normal font
legendels[k].parentNode.children[1].style.fontWeight = 400;
}
if (evt.target == dlabel) {
// disable all
for (let k in legendels) {
legendels[k].parentNode.firstChild.style.height = '1px';
}
for (ds of chart.data.datasets) {
ds.borderWidth = 1;
}
color.style.height = '2px';
dataset.borderWidth = 2;
dlabel.style.fontWeight = 700; // bold
} else {
if (dataset.borderWidth == 1) {
legendel.firstChild.style.height = '2px';
dataset.borderWidth = 2;
} else {
legendel.firstChild.style.height = '1px';
dataset.borderWidth = 1;
}
}
graphs.autoScale(chart);
chart.update();
});
legend.appendChild(legendel);
return dataset_index;
}
function autoScaleChart() {
autoScale(chart);
function autoScaleIf() {
if (autoScaleFlag) graphs.autoScale(chart);
}
function pushData(dataset_index, data_point){
chart.data.datasets[dataset_index].data.push(data_point);
if(!graphs.zoomed){
chart.options.scales.xAxes[0].ticks.max = data_point.x;
}else{
update_max = data_point.x;
data = chart.data.datasets[dataset_index].data;
//if (chart.data.datasets[dataset_index].key == 'tt:target')
// console.log('BEFORE', data.slice(-3))
if (data.slice(-1)[0] && data.slice(-1)[0].x >= data_point.x) {
removed = data.pop();
}
data.push(data_point);
//if (chart.data.datasets[dataset_index].key == 'tt:target')
// console.log('PUSHED', data.slice(-3))
/*
if (graphs.zoomed) {
update_max = data_point.x;
} else {
chart.options.scales.xAxes[0].ticks.max = data_point.x;
}
*/
}
function reloadData(index, data){
@ -959,6 +1056,17 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
ax.ticks.min = min;
}
function toggleAutoScale () {
autoScaleFlag = !autoScaleFlag;
if (autoScaleFlag) {
graphs.autoScale(chart);
update();
autoScaleRow.innerHTML = "Autoscale <strong>on</strong> off";
} else {
autoScaleRow.innerHTML = "Autoscale on <strong>off</strong>";
}
}
function toggleAxesType(){
setAxesType((chart.options.scales.yAxes[0].type=== 'linear') ? 'logarithmic' : 'linear');
}
@ -972,6 +1080,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
}
chart.options.scales.yAxes[0].type = type;
chart.options.animation.duration = 800;
if (autoScaleFlag) graphs.autoScale(chart);
update();
setTimeout(function(){chart.options.animation.duration = 0;},850)
}
@ -996,7 +1105,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
let d2 = Math.abs(dp._model.x - x)
if(d == 0 || d2 < d){
d = d2;
legendels[chart.data.datasets[i].label].innerHTML =
legendels[chart.data.datasets[i].key].innerHTML =
strFormat(chart.data.datasets[i].data[dp._index].y, 6);
test[i]=dp
}
@ -1045,7 +1154,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
redraw: redraw,
update: update,
reloadData: reloadData,
autoScaleChart: autoScaleChart,
autoScaleIf: autoScaleIf,
chart: chart,
}
}
@ -1096,13 +1206,17 @@ function updateCharts2(graph){
return;
}
for(let key in graph){
for (pt of graph[key]) {
if (graph[key][1] != null) {
// there is at least ONE valid datapoint
graphs.newDataHandler(key, {x: graph[key][0][0]*1000, y: graph[key][0][1]});
break;
if (graph[key][0] != null) {
// there is at least ONE valid datapoint
for (pt of graph[key]) {
graphs.newDataHandler(key, {x: pt[0]*1000, y: pt[1]});
}
}
}
graphs.update();
graphs.updateAuto();
// graphs.update();
}
function createCharts2(arg) {
console.log('C2', arg)
}

View File

@ -250,6 +250,10 @@ function createInput(s, name, title, info) {
input.setAttribute("name", name);
input.setAttribute("__ctype__", "input");
input.style.width = "100px";
input.addEventListener("focus", function(evt) {
let elm = evt.target;
setTimeout(function(){elm.setSelectionRange(0, elm.value.length);},0);
});
input.onkeydown = function (e) {
if (e.which === 27 || e.key == "Escape") {
@ -281,7 +285,8 @@ function createInput(s, name, title, info) {
input.setAttribute("actualValue", oldValue);
}
var actualValue = input.getAttribute("actualValue");
if (value === actualValue || value === oldValue) {
if (value == actualValue || value == oldValue ||
parseFloat(value) == parseFloat(actualValue) || parseFloat(value) == parseFloat(oldValue)) {
input.value = actualValue;
// nothing to do.
row.style.backgroundColor = "white";