make web client work
This commit is contained in:
@ -86,7 +86,7 @@ function handleUpdateMessage(src, message) {
|
|||||||
sizeChange();
|
sizeChange();
|
||||||
} else {
|
} else {
|
||||||
clientTitle = message.instrument + " " + message.device;
|
clientTitle = message.instrument + " " + message.device;
|
||||||
console.log('loadBlocks')
|
console.log('loadBlocks', message);
|
||||||
loadFirstBlocks();
|
loadFirstBlocks();
|
||||||
}
|
}
|
||||||
document.title = "SEA "+clientTitle;
|
document.title = "SEA "+clientTitle;
|
||||||
@ -155,7 +155,6 @@ function handleUpdateMessage(src, message) {
|
|||||||
case "graph-update":
|
case "graph-update":
|
||||||
//if (getUpdatesGraphics) {
|
//if (getUpdatesGraphics) {
|
||||||
//timeServer = message.time;
|
//timeServer = message.time;
|
||||||
console.log("graph-update");
|
|
||||||
updateCharts2(message.graph);
|
updateCharts2(message.graph);
|
||||||
//}
|
//}
|
||||||
break;
|
break;
|
||||||
@ -207,11 +206,12 @@ function updateValues(message, src) {
|
|||||||
} else if (type == "input") {
|
} else if (type == "input") {
|
||||||
var row = matches[j].parentNode.parentNode.parentNode;
|
var row = matches[j].parentNode.parentNode.parentNode;
|
||||||
row.style.backgroundColor = "white";
|
row.style.backgroundColor = "white";
|
||||||
var oldValue = matches[j].getAttribute("oldValue")
|
var mval = matches[j].value;
|
||||||
|| matches[j].value;
|
var oldValue = matches[j].getAttribute("oldValue");
|
||||||
if (value != matches[j].value && value != oldValue) {
|
if (oldValue === null) oldValue = mval;
|
||||||
|
if (value != mval && parseFloat(value) != parseFloat(mval) && value != oldValue) {
|
||||||
if (matches[j] == document.activeElement
|
if (matches[j] == document.activeElement
|
||||||
|| oldValue != matches[j].value) {
|
|| oldValue != mval) {
|
||||||
row.style.backgroundColor = "orange";
|
row.style.backgroundColor = "orange";
|
||||||
} else {
|
} else {
|
||||||
matches[j].value = value;
|
matches[j].value = value;
|
||||||
|
@ -106,51 +106,20 @@ function doubleTap(callback){
|
|||||||
return {stop: function(){ window.removeEventListener('touchend', handler) }}
|
return {stop: function(){ window.removeEventListener('touchend', handler) }}
|
||||||
}
|
}
|
||||||
|
|
||||||
function maxAr(array){
|
function maxAr(array, tmin, tmax){
|
||||||
return Math.max.apply(Math, array.map(function(o) {
|
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;
|
return o.y;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function minAr(array){
|
function minAr(array, tmin, tmax){
|
||||||
return Math.min.apply(Math, array.map(function(o) {
|
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;
|
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) {
|
function strFormat(str, significant_digits) {
|
||||||
if (str == null) return '';
|
if (str == null) return '';
|
||||||
evalue = str.toExponential(significant_digits-1).replace(/0*e/, 'e').replace(/\.e/, 'e').replace("e+", "e");
|
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 graphs = (function (){
|
||||||
let dataset_to_graph_map = {},
|
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';
|
let type = 'linear';
|
||||||
|
|
||||||
@ -175,6 +144,8 @@ let graphs = (function (){
|
|||||||
|
|
||||||
let container = document.createElement('div');
|
let container = document.createElement('div');
|
||||||
container.classList.add("graphs-container");
|
container.classList.add("graphs-container");
|
||||||
|
let currentMinTime = 0;
|
||||||
|
let currentMaxTime = 0;
|
||||||
|
|
||||||
for (let i = 0; i < ngraphs; i++) {
|
for (let i = 0; i < ngraphs; i++) {
|
||||||
let gr = document.createElement('div');
|
let gr = document.createElement('div');
|
||||||
@ -242,7 +213,7 @@ let graphs = (function (){
|
|||||||
}
|
}
|
||||||
//let varlist = top_vars.concat(bottom_vars);
|
//let varlist = top_vars.concat(bottom_vars);
|
||||||
varlist = vars_array[gindex];
|
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){
|
AJAX("http://" + hostPort + "/graph?time=" + minTime/1000 + "," + maxTime/1000 + "&variables=" + varlist + "&id=" + clientID).getJSON().then(function(data){
|
||||||
|
|
||||||
//console.log('Graph', block, data)
|
//console.log('Graph', block, data)
|
||||||
@ -255,13 +226,10 @@ let graphs = (function (){
|
|||||||
}
|
}
|
||||||
let pdata = [];
|
let pdata = [];
|
||||||
for(let e of data.graph[key]){
|
for(let e of data.graph[key]){
|
||||||
//if(e[1] == null || e[1] == null){
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
pdata.push({x: e[0]*1000, y: e[1]});
|
pdata.push({x: e[0]*1000, y: e[1]});
|
||||||
}
|
}
|
||||||
if(pdata.length > 0){
|
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);
|
/*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
|
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
|
d = data[data.length-1].x-data[0].x
|
||||||
@ -271,20 +239,91 @@ let graphs = (function (){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
chart.setMinMax(minTime,maxTime);
|
chart.setMinMax(minTime,maxTime);
|
||||||
// chart.autoScaleChart();
|
chart.autoScaleIf();
|
||||||
chart.update();
|
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
|
// add dataset to graph with graph_id
|
||||||
function addDataset(gindex, key, dataset){
|
function addDataset(gindex, key, dataset){
|
||||||
let g = chart_array[gindex];
|
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){
|
function setMinMax(min, max){
|
||||||
|
currentMaxTime = max;
|
||||||
|
currentMinTime = min;
|
||||||
for (let ch of chart_array) {
|
for (let ch of chart_array) {
|
||||||
if (ch) ch.setMinMax(min, max);
|
if (ch) ch.setMinMax(min, max);
|
||||||
}
|
}
|
||||||
@ -326,6 +365,16 @@ let graphs = (function (){
|
|||||||
chart_array[i[0]].reloadData(i[1], data);
|
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){
|
function reloadData(min, max){
|
||||||
|
|
||||||
min = min/1000;
|
min = min/1000;
|
||||||
@ -334,14 +383,8 @@ let graphs = (function (){
|
|||||||
}else{
|
}else{
|
||||||
max = max/1000;
|
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){
|
for(let key in data.graph){
|
||||||
let pdata = [];
|
let pdata = [];
|
||||||
for(let e of data.graph[key]){
|
for(let e of data.graph[key]){
|
||||||
@ -354,10 +397,13 @@ let graphs = (function (){
|
|||||||
reloadDataFlag(key, pdata);
|
reloadDataFlag(key, pdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let ch of chart_array) {
|
// AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // activate updates
|
||||||
if (ch) ch.autoScaleChart(); // should depend on a flag
|
result = AJAX("http://" + hostPort +
|
||||||
}
|
"/updategraph?variables=" + variables() +
|
||||||
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // why this ?
|
"&id=" + clientID).getJSON().then(function(data) {
|
||||||
|
liveMode = data.live;
|
||||||
|
console.log('LIVE reload', liveMode)
|
||||||
|
})
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -365,19 +411,21 @@ let graphs = (function (){
|
|||||||
function checkReload(chart){
|
function checkReload(chart){
|
||||||
let xmin = chart.options.scales.xAxes[0].ticks.min,
|
let xmin = chart.options.scales.xAxes[0].ticks.min,
|
||||||
xmax = chart.options.scales.xAxes[0].ticks.max;
|
xmax = chart.options.scales.xAxes[0].ticks.max;
|
||||||
if(xmax < now()-10000){ // was 100000 = 100sec
|
if (xmax < now()-100000) { // was 100000 = 100sec
|
||||||
doUpdates = false;
|
if (liveMode) console.log('UPDATES OFF?')
|
||||||
|
//doUpdates = false;
|
||||||
}else{
|
}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
|
//TODO: the criterium for getting finer resolution data should depend, if better res. is available
|
||||||
// this information has to come from the server
|
// this information has to come from the server
|
||||||
reloadData(xmin, xmax);
|
reloadData(xmin, xmax);
|
||||||
minTime = xmin;
|
minTime = xmin;
|
||||||
maxTime = xmax;
|
maxTime = xmax;
|
||||||
} else {
|
} else {
|
||||||
autoScale(chart); // TODO: must depend on autoScale flag
|
if (chart.autoScaleFlag) autoScale(chart);
|
||||||
chart.update();
|
chart.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,7 +435,9 @@ let graphs = (function (){
|
|||||||
xmax = chart.options.scales.xAxes[0].ticks.max;
|
xmax = chart.options.scales.xAxes[0].ticks.max;
|
||||||
|
|
||||||
setMinMax(xmin,xmax);
|
setMinMax(xmin,xmax);
|
||||||
|
//console.log('zoompan', autoScaleFlag);
|
||||||
for (let ch of chart_array) {
|
for (let ch of chart_array) {
|
||||||
|
ch.autoScaleIf();
|
||||||
if (ch) ch.redraw(redrawX);
|
if (ch) ch.redraw(redrawX);
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
@ -399,15 +449,27 @@ let graphs = (function (){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAuto(){
|
||||||
let g_varlist = [];
|
if (liveMode) {
|
||||||
function updateAllDisabled(){
|
max = now();
|
||||||
// not used anymore?
|
if (currentMaxTime && max > currentMaxTime) {
|
||||||
AJAX("http://" + hostPort + "/graph?time="+timeRange+"&variables=" + g_varlist + "&id=" + clientID).getJSON().then(function(a){
|
max = currentMaxTime + Math.min(60000, 0.1 * (currentMaxTime - currentMinTime));
|
||||||
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON()
|
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){
|
function getVarlist(blocks){
|
||||||
var varlist = [];
|
var varlist = [];
|
||||||
for (var i = 0; i < blocks.length; i++) {
|
for (var i = 0; i < blocks.length; i++) {
|
||||||
@ -417,6 +479,7 @@ let graphs = (function (){
|
|||||||
}
|
}
|
||||||
return varlist;
|
return varlist;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
let startTime, recvTime, minTime, maxTime;
|
let startTime, recvTime, minTime, maxTime;
|
||||||
|
|
||||||
@ -425,13 +488,14 @@ let graphs = (function (){
|
|||||||
minTime = timeRange[0]*1000;
|
minTime = timeRange[0]*1000;
|
||||||
AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){
|
AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){
|
||||||
startTime = data.time[1]*1000;
|
startTime = data.time[1]*1000;
|
||||||
maxTime = startTime;
|
maxTime = startTime + 60000;
|
||||||
|
console.log('MAXTIME', maxTime - Date.now());
|
||||||
minTime = data.time[0]*1000;
|
minTime = data.time[0]*1000;
|
||||||
recvTime = performance.now();
|
recvTime = performance.now();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
g_varlist = getVarlist(nblocks)
|
// g_varlist = getVarlist(nblocks)
|
||||||
let f = 0;
|
let f = 0;
|
||||||
insertSlide(f, "graphics", "graphics", container);
|
insertSlide(f, "graphics", "graphics", container);
|
||||||
blocks = nblocks;
|
blocks = nblocks;
|
||||||
@ -514,13 +578,15 @@ let graphs = (function (){
|
|||||||
zoompan: zoompan,
|
zoompan: zoompan,
|
||||||
receivedVars: receivedVars,
|
receivedVars: receivedVars,
|
||||||
createSelection: createSelection,
|
createSelection: createSelection,
|
||||||
doUpdates: function(){return doUpdates},
|
doUpdates: function(){return liveMode},
|
||||||
update: update,
|
update: update,
|
||||||
|
updateAuto: updateAuto,
|
||||||
now: now,
|
now: now,
|
||||||
zoomed: zoomed,
|
zoomed: zoomed,
|
||||||
checkReload: checkReload,
|
checkReload: checkReload,
|
||||||
getBlocks: getBlocks,
|
getBlocks: getBlocks,
|
||||||
createGraph: createGraph,
|
createGraph: createGraph,
|
||||||
|
autoScale: autoScale,
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -567,7 +633,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
|||||||
y1 = ticks[0];
|
y1 = ticks[0];
|
||||||
y0 = ticks.slice(-1)[0];
|
y0 = ticks.slice(-1)[0];
|
||||||
span = y1 - y0;
|
span = y1 - y0;
|
||||||
step = Math.abs(span * 0.1).toExponential(0);
|
step = Math.abs(span * 0.3).toExponential(0);
|
||||||
if (step[0] > '5') {
|
if (step[0] > '5') {
|
||||||
step = '5' + step.substr(1);
|
step = '5' + step.substr(1);
|
||||||
} else if (step[0] > '2') {
|
} 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')
|
//console.log('create legend')
|
||||||
let legend = document.createElement('div');
|
let legend = document.createElement('div');
|
||||||
@ -724,9 +791,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
|||||||
graphs.zoompan(chart);
|
graphs.zoompan(chart);
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
addControl("Autoscale Y", function(){
|
let autoScaleRow = addControl("Autoscale Y <strong>on</strong> off", function(){
|
||||||
autoScale(chart);
|
toggleAutoScale();
|
||||||
update();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addControl("Go to now", function(){
|
addControl("Go to now", function(){
|
||||||
@ -847,60 +913,91 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
|||||||
chart.update();
|
chart.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDataset(data){
|
function addDataset(key, data){
|
||||||
let dataset_index = chart.data.datasets.length;
|
let dataset_index = chart.data.datasets.length;
|
||||||
chart.data.datasets.push({data: data[2], label: data[0], origLabel: data[0],
|
chart.data.datasets.push({data: data[2], label: data[0], key: key,
|
||||||
spanGaps: false, lineJoin: 'round', borderWidth: 2,
|
spanGaps: false, lineJoin: 'round', borderWidth: 2, steppedLine: data[3] == 0,
|
||||||
borderColor: data[1],fill: false, pointRadius: 0, tension:0, showLine: true});
|
borderColor: data[1],fill: false, pointRadius: 0, tension:0, showLine: true});
|
||||||
|
|
||||||
let dataset = chart.data.datasets[dataset_index];
|
let dataset = chart.data.datasets[dataset_index];
|
||||||
let legendel = document.createElement('div');
|
let legendel = document.createElement('div');
|
||||||
let legendelvalue = document.createElement('div');
|
let legendelvalue = document.createElement('div');
|
||||||
legendelvalue.classList.add('value');
|
legendelvalue.classList.add('value');
|
||||||
legendels[data[0]] = legendelvalue;
|
legendels[key] = legendelvalue;
|
||||||
legendel.classList.add('legendel')
|
legendel.classList.add('legendel')
|
||||||
let color = document.createElement('div');
|
let color = document.createElement('div');
|
||||||
color.classList.add('color')
|
color.classList.add('color')
|
||||||
color.style.backgroundColor = dataset.borderColor;
|
color.style.backgroundColor = dataset.borderColor;
|
||||||
legendel.appendChild(color);
|
legendel.appendChild(color);
|
||||||
legendel.innerHTML += dataset.label;
|
let dlabel = document.createElement('div');
|
||||||
legendel.addEventListener('click', function(){
|
dlabel.innerHTML = dataset.label;
|
||||||
|
dlabel.addEventListener('click', function(evt){
|
||||||
|
/*
|
||||||
|
console.log('LABEL', evt.target)
|
||||||
if(legendmoving)
|
if(legendmoving)
|
||||||
return
|
return
|
||||||
let meta = dataset._meta[Object.keys(dataset._meta)[0]]
|
legendel.firstChild.style.height = '2px';
|
||||||
/*
|
dataset.borderWidth = 2;
|
||||||
if(meta.hidden == null){
|
labelClicked = true;
|
||||||
meta.hidden = true;
|
//console.log('LABEL', evt.target)
|
||||||
addClass(legendel, 'hidden');
|
|
||||||
}else{
|
|
||||||
meta.hidden = null;
|
|
||||||
delClass(legendel, 'hidden');
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
if (dataset.borderWidth == 1) {
|
});
|
||||||
dataset.borderWidth = 2;
|
legendel.appendChild(dlabel);
|
||||||
} else {
|
|
||||||
dataset.borderWidth = 1;
|
|
||||||
}
|
|
||||||
autoScale(chart);
|
|
||||||
chart.update();
|
|
||||||
})
|
|
||||||
legendel.appendChild(legendelvalue);
|
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);
|
legend.appendChild(legendel);
|
||||||
return dataset_index;
|
return dataset_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function autoScaleChart() {
|
function autoScaleIf() {
|
||||||
autoScale(chart);
|
if (autoScaleFlag) graphs.autoScale(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushData(dataset_index, data_point){
|
function pushData(dataset_index, data_point){
|
||||||
chart.data.datasets[dataset_index].data.push(data_point);
|
data = chart.data.datasets[dataset_index].data;
|
||||||
if(!graphs.zoomed){
|
//if (chart.data.datasets[dataset_index].key == 'tt:target')
|
||||||
chart.options.scales.xAxes[0].ticks.max = data_point.x;
|
// console.log('BEFORE', data.slice(-3))
|
||||||
}else{
|
if (data.slice(-1)[0] && data.slice(-1)[0].x >= data_point.x) {
|
||||||
update_max = 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){
|
function reloadData(index, data){
|
||||||
@ -959,6 +1056,17 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
|||||||
ax.ticks.min = min;
|
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(){
|
function toggleAxesType(){
|
||||||
setAxesType((chart.options.scales.yAxes[0].type=== 'linear') ? 'logarithmic' : 'linear');
|
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.scales.yAxes[0].type = type;
|
||||||
chart.options.animation.duration = 800;
|
chart.options.animation.duration = 800;
|
||||||
|
if (autoScaleFlag) graphs.autoScale(chart);
|
||||||
update();
|
update();
|
||||||
setTimeout(function(){chart.options.animation.duration = 0;},850)
|
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)
|
let d2 = Math.abs(dp._model.x - x)
|
||||||
if(d == 0 || d2 < d){
|
if(d == 0 || d2 < d){
|
||||||
d = d2;
|
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);
|
strFormat(chart.data.datasets[i].data[dp._index].y, 6);
|
||||||
test[i]=dp
|
test[i]=dp
|
||||||
}
|
}
|
||||||
@ -1045,7 +1154,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
|||||||
redraw: redraw,
|
redraw: redraw,
|
||||||
update: update,
|
update: update,
|
||||||
reloadData: reloadData,
|
reloadData: reloadData,
|
||||||
autoScaleChart: autoScaleChart,
|
autoScaleIf: autoScaleIf,
|
||||||
|
chart: chart,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,13 +1206,17 @@ function updateCharts2(graph){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(let key in graph){
|
for(let key in graph){
|
||||||
for (pt of graph[key]) {
|
if (graph[key][0] != null) {
|
||||||
if (graph[key][1] != null) {
|
// there is at least ONE valid datapoint
|
||||||
// there is at least ONE valid datapoint
|
for (pt of graph[key]) {
|
||||||
graphs.newDataHandler(key, {x: graph[key][0][0]*1000, y: graph[key][0][1]});
|
graphs.newDataHandler(key, {x: pt[0]*1000, y: pt[1]});
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
graphs.update();
|
graphs.updateAuto();
|
||||||
|
// graphs.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCharts2(arg) {
|
||||||
|
console.log('C2', arg)
|
||||||
|
}
|
@ -250,6 +250,10 @@ function createInput(s, name, title, info) {
|
|||||||
input.setAttribute("name", name);
|
input.setAttribute("name", name);
|
||||||
input.setAttribute("__ctype__", "input");
|
input.setAttribute("__ctype__", "input");
|
||||||
input.style.width = "100px";
|
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) {
|
input.onkeydown = function (e) {
|
||||||
if (e.which === 27 || e.key == "Escape") {
|
if (e.which === 27 || e.key == "Escape") {
|
||||||
@ -281,7 +285,8 @@ function createInput(s, name, title, info) {
|
|||||||
input.setAttribute("actualValue", oldValue);
|
input.setAttribute("actualValue", oldValue);
|
||||||
}
|
}
|
||||||
var actualValue = input.getAttribute("actualValue");
|
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;
|
input.value = actualValue;
|
||||||
// nothing to do.
|
// nothing to do.
|
||||||
row.style.backgroundColor = "white";
|
row.style.backgroundColor = "white";
|
||||||
|
@ -166,18 +166,25 @@ All other connections are to be closed (getJSON):
|
|||||||
|
|
||||||
*********************************************************************************************************************************
|
*********************************************************************************************************************************
|
||||||
|
|
||||||
/updategraph?id=<id>
|
/updategraph?id=<id>[&variables=<variable list>]
|
||||||
|
|
||||||
|
if <variables list> is given, the given variables will be updated with the graph-update-message
|
||||||
|
|
||||||
response: <accept-graph-message>
|
response: <accept-graph-message>
|
||||||
|
|
||||||
<accept-graph-message> = = {
|
<accept-graph-message> = = {
|
||||||
"type": "accept-graph"
|
"type": "accept-graph",
|
||||||
|
"live": true/false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
the "live" flag is true when the last /graph query was including the actual time
|
||||||
|
|
||||||
*********************************************************************************************************************************
|
*********************************************************************************************************************************
|
||||||
|
|
||||||
/graph?time=<start>,<end>&variables=<variable list>&id=<id>
|
/graph?time=<start>,<end>&variables=<variable list>&id=<id>
|
||||||
|
|
||||||
|
the given variables are added to the list of variables being updated with the graph-update-message
|
||||||
|
|
||||||
response: <graph-draw-message>
|
response: <graph-draw-message>
|
||||||
|
|
||||||
<graph-draw-message> = = {
|
<graph-draw-message> = = {
|
||||||
|
111
histgraph.py
111
histgraph.py
@ -18,51 +18,67 @@ def get_abs_time(*times):
|
|||||||
|
|
||||||
|
|
||||||
class ColorMap(object):
|
class ColorMap(object):
|
||||||
'''
|
""""
|
||||||
ColorMap is using official CSS color names, with the exception of Green, as this
|
ColorMap is using official CSS color names, with the exception of Green, as this
|
||||||
is defined differently with X11 colors than in SEA, and used heavily in config files.
|
is defined differently with X11 colors than in SEA, and used heavily in config files.
|
||||||
Here Green is an alias to Lime (#00FF00) and MidGreen is #008000, which is called Green in CSS.
|
Here Green is an alias to Lime (#00FF00) and MidGreen is #008000, which is called Green in CSS.
|
||||||
The function to_code is case insensitive and accepts also names with underscores.
|
The function to_code is case insensitive and accepts also names with underscores.
|
||||||
The order is choosen by M. Zolliker for the SEA client, originally only the first 16 were used.
|
The order is choosen by M. Zolliker for the SEA client, originally only the first 16 were used.
|
||||||
'''
|
"""
|
||||||
hex_name = (("#FFFFFF","White"), ("#FF0000","Red"), ("#00FF00","Lime"), ("#0000FF","Blue"), ("#FF00FF","Magenta"),
|
hex_name = (
|
||||||
("#FFFF00","Yellow"), ("#00FFFF","Cyan"), ("#000000","Black"), ("#FFA500","Orange"), ("#006400","DarkGreen"),
|
("#FFFFFF", "White"), ("#FF0000", "Red"), ("#00FF00", "Lime"), ("#0000FF", "Blue"), ("#FF00FF", "Magenta"),
|
||||||
("#9400D3","DarkViolet"), ("#A52A2A","Brown"), ("#87CEEB","SkyBlue"), ("#808080","Gray"), ("#FF69B4","HotPink"),
|
("#FFFF00", "Yellow"), ("#00FFFF", "Cyan"), ("#000000", "Black"), ("#FFA500", "Orange"),
|
||||||
("#FFFFE0","LightYellow"), ("#00FF7F","SpringGreen"), ("#000080","Navy"), ("#1E90FF","DodgerBlue"),
|
("#006400", "DarkGreen"), ("#9400D3", "DarkViolet"), ("#A52A2A", "Brown"), ("#87CEEB", "SkyBlue"),
|
||||||
("#9ACD32","YellowGreen"), ("#008B8B","DarkCyan"), ("#808000","Olive"), ("#DEB887","BurlyWood"),
|
("#808080", "Gray"), ("#FF69B4", "HotPink"), ("#FFFFE0", "LightYellow"), ("#00FF7F", "SpringGreen"),
|
||||||
("#7B68EE","MediumSlateBlue"), ("#483D8B","DarkSlateBlue"), ("#98FB98","PaleGreen"), ("#FF1493","DeepPink"),
|
("#000080", "Navy"), ("#1E90FF", "DodgerBlue"), ("#9ACD32", "YellowGreen"), ("#008B8B", "DarkCyan"),
|
||||||
("#FF6347","Tomato"), ("#32CD32","LimeGreen"), ("#DDA0DD","Plum"), ("#7FFF00","Chartreuse"), ("#800080","Purple"),
|
("#808000", "Olive"), ("#DEB887", "BurlyWood"),
|
||||||
("#00CED1","DarkTurquoise"), ("#8FBC8F","DarkSeaGreen"), ("#4682B4","SteelBlue"), ("#800000","Maroon"),
|
("#7B68EE", "MediumSlateBlue"), ("#483D8B", "DarkSlateBlue"), ("#98FB98", "PaleGreen"), ("#FF1493", "DeepPink"),
|
||||||
("#3CB371","MediumSeaGreen"), ("#FF4500","OrangeRed"), ("#BA55D3","MediumOrchid"), ("#2F4F4F","DarkSlateGray"),
|
("#FF6347", "Tomato"), ("#32CD32", "LimeGreen"), ("#DDA0DD", "Plum"), ("#7FFF00", "Chartreuse"),
|
||||||
("#CD853F","Peru"), ("#228B22","ForestGreen"), ("#48D1CC","MediumTurquoise"), ("#DC143C","Crimson"),
|
("#800080", "Purple"), ("#00CED1", "DarkTurquoise"), ("#8FBC8F", "DarkSeaGreen"), ("#4682B4", "SteelBlue"),
|
||||||
("#D3D3D3","LightGray"), ("#ADFF2F","GreenYellow"), ("#7FFFD4","Aquamarine"), ("#BC8F8F","RosyBrown"),
|
("#800000", "Maroon"),
|
||||||
("#20B2AA","LightSeaGreen"), ("#C71585","MediumVioletRed"), ("#F0E68C","Khaki"), ("#6495ED","CornflowerBlue"),
|
("#3CB371", "MediumSeaGreen"), ("#FF4500", "OrangeRed"), ("#BA55D3", "MediumOrchid"),
|
||||||
("#556B2F","DarkOliveGreen"), ("#CD5C5C","IndianRed "), ("#2E8B57","SeaGreen"), ("#F08080","LightCoral"),
|
("#2F4F4F", "DarkSlateGray"), ("#CD853F", "Peru"), ("#228B22", "ForestGreen"), ("#48D1CC", "MediumTurquoise"),
|
||||||
("#8A2BE2","BlueViolet"), ("#AFEEEE","PaleTurquoise"), ("#4169E1","RoyalBlue"), ("#0000CD","MediumBlue"),
|
("#DC143C", "Crimson"),
|
||||||
("#B8860B","DarkGoldenRod"), ("#00BFFF","DeepSkyBlue"), ("#FFC0CB","Pink"), ("#4B0082","Indigo "), ("#A0522D","Sienna"),
|
("#D3D3D3", "LightGray"), ("#ADFF2F", "GreenYellow"), ("#7FFFD4", "Aquamarine"), ("#BC8F8F", "RosyBrown"),
|
||||||
("#FFD700","Gold"), ("#F4A460","SandyBrown"), ("#DAA520","GoldenRod"), ("#DA70D6","Orchid"), ("#E6E6FA","Lavender"),
|
("#20B2AA", "LightSeaGreen"), ("#C71585", "MediumVioletRed"), ("#F0E68C", "Khaki"),
|
||||||
("#5F9EA0","CadetBlue"), ("#D2691E","Chocolate"), ("#66CDAA","MediumAquaMarine"), ("#6B8E23","OliveDrab"),
|
("#6495ED", "CornflowerBlue"),
|
||||||
("#A9A9A9","DarkGray"), ("#BDB76B","DarkKhaki"), ("#696969","DimGray"), ("#B0C4DE","LightSteelBlue"),
|
("#556B2F", "DarkOliveGreen"), ("#CD5C5C", "IndianRed "), ("#2E8B57", "SeaGreen"), ("#F08080", "LightCoral"),
|
||||||
("#191970","MidnightBlue"), ("#FFE4C4","Bisque"), ("#6A5ACD","SlateBlue"), ("#EE82EE","Violet"),
|
("#8A2BE2", "BlueViolet"), ("#AFEEEE", "PaleTurquoise"), ("#4169E1", "RoyalBlue"), ("#0000CD", "MediumBlue"),
|
||||||
("#8B4513","SaddleBrown"), ("#FF7F50","Coral"), ("#008000","MidGreen"), ("#DB7093","PaleVioletRed"), ("#C0C0C0","Silver"),
|
("#B8860B", "DarkGoldenRod"), ("#00BFFF", "DeepSkyBlue"), ("#FFC0CB", "Pink"), ("#4B0082", "Indigo "),
|
||||||
("#E0FFFF","LightCyan"), ("#9370DB","MediumPurple"), ("#FF8C00","DarkOrange"), ("#00FA9A","MediumSpringGreen"),
|
("#A0522D", "Sienna"),
|
||||||
("#E9967A","DarkSalmon"), ("#778899","LightSlateGray"), ("#9932CC","DarkOrchid"), ("#EEE8AA","PaleGoldenRod"),
|
("#FFD700", "Gold"), ("#F4A460", "SandyBrown"), ("#DAA520", "GoldenRod"), ("#DA70D6", "Orchid"),
|
||||||
("#F8F8FF","GhostWhite"), ("#FFA07A","LightSalmon"), ("#ADD8E6","LightBlue"), ("#D8BFD8","Thistle"),
|
("#E6E6FA", "Lavender"),
|
||||||
("#FFE4E1","MistyRose"), ("#FFDEAD","NavajoWhite"), ("#40E0D0","Turquoise"), ("#90EE90","LightGreen"),
|
("#5F9EA0", "CadetBlue"), ("#D2691E", "Chocolate"), ("#66CDAA", "MediumAquaMarine"), ("#6B8E23", "OliveDrab"),
|
||||||
("#B22222","FireBrick"), ("#008080","Teal"), ("#F0FFF0","HoneyDew"), ("#FFFACD","LemonChiffon"), ("#FFF5EE","SeaShell"),
|
("#A9A9A9", "DarkGray"), ("#BDB76B", "DarkKhaki"), ("#696969", "DimGray"), ("#B0C4DE", "LightSteelBlue"),
|
||||||
("#F5F5DC","Beige"), ("#DCDCDC","Gainsboro"), ("#FA8072","Salmon"), ("#8B008B","DarkMagenta"), ("#FFB6C1","LightPink"),
|
("#191970", "MidnightBlue"), ("#FFE4C4", "Bisque"), ("#6A5ACD", "SlateBlue"), ("#EE82EE", "Violet"),
|
||||||
("#708090","SlateGray"), ("#87CEFA","LightSkyBlue"), ("#FFEFD5","PapayaWhip"), ("#D2B48C","Tan"), ("#FFFFF0","Ivory"),
|
("#8B4513", "SaddleBrown"), ("#FF7F50", "Coral"), ("#008000", "MidGreen"), ("#DB7093", "PaleVioletRed"),
|
||||||
("#F0FFFF","Azure"), ("#F5DEB3","Wheat"), ("#00008B","DarkBlue"), ("#FFDAB9","PeachPuff"), ("#8B0000","DarkRed"),
|
("#C0C0C0", "Silver"),
|
||||||
("#FAF0E6","Linen"), ("#B0E0E6","PowderBlue"), ("#FFE4B5","Moccasin"), ("#F5F5F5","WhiteSmoke"), ("#FFF8DC","Cornsilk"),
|
("#E0FFFF", "LightCyan"), ("#9370DB", "MediumPurple"), ("#FF8C00", "DarkOrange"),
|
||||||
("#FFFAFA","Snow"), ("#FFF0F5","LavenderBlush"), ("#FFEBCD","BlanchedAlmond"), ("#F0F8FF","AliceBlue"),
|
("#00FA9A", "MediumSpringGreen"),
|
||||||
("#FAEBD7","AntiqueWhite"), ("#FDF5E6","OldLace"), ("#FAFAD2","LightGoldenRodYellow"), ("#F5FFFA","MintCream"),
|
("#E9967A", "DarkSalmon"), ("#778899", "LightSlateGray"), ("#9932CC", "DarkOrchid"),
|
||||||
("#FFFAF0","FloralWhite"), ("#7CFC00","LawnGreen"), ("#663399","RebeccaPurple"))
|
("#EEE8AA", "PaleGoldenRod"),
|
||||||
|
("#F8F8FF", "GhostWhite"), ("#FFA07A", "LightSalmon"), ("#ADD8E6", "LightBlue"), ("#D8BFD8", "Thistle"),
|
||||||
|
("#FFE4E1", "MistyRose"), ("#FFDEAD", "NavajoWhite"), ("#40E0D0", "Turquoise"), ("#90EE90", "LightGreen"),
|
||||||
|
("#B22222", "FireBrick"), ("#008080", "Teal"), ("#F0FFF0", "HoneyDew"), ("#FFFACD", "LemonChiffon"),
|
||||||
|
("#FFF5EE", "SeaShell"),
|
||||||
|
("#F5F5DC", "Beige"), ("#DCDCDC", "Gainsboro"), ("#FA8072", "Salmon"), ("#8B008B", "DarkMagenta"),
|
||||||
|
("#FFB6C1", "LightPink"),
|
||||||
|
("#708090", "SlateGray"), ("#87CEFA", "LightSkyBlue"), ("#FFEFD5", "PapayaWhip"), ("#D2B48C", "Tan"),
|
||||||
|
("#FFFFF0", "Ivory"),
|
||||||
|
("#F0FFFF", "Azure"), ("#F5DEB3", "Wheat"), ("#00008B", "DarkBlue"), ("#FFDAB9", "PeachPuff"),
|
||||||
|
("#8B0000", "DarkRed"),
|
||||||
|
("#FAF0E6", "Linen"), ("#B0E0E6", "PowderBlue"), ("#FFE4B5", "Moccasin"), ("#F5F5F5", "WhiteSmoke"),
|
||||||
|
("#FFF8DC", "Cornsilk"),
|
||||||
|
("#FFFAFA", "Snow"), ("#FFF0F5", "LavenderBlush"), ("#FFEBCD", "BlanchedAlmond"), ("#F0F8FF", "AliceBlue"),
|
||||||
|
("#FAEBD7", "AntiqueWhite"), ("#FDF5E6", "OldLace"), ("#FAFAD2", "LightGoldenRodYellow"),
|
||||||
|
("#F5FFFA", "MintCream"),
|
||||||
|
("#FFFAF0", "FloralWhite"), ("#7CFC00", "LawnGreen"), ("#663399", "RebeccaPurple"))
|
||||||
codes = {}
|
codes = {}
|
||||||
for i, pair in enumerate(hex_name):
|
for i, pair in enumerate(hex_name):
|
||||||
codes[pair[0]] = i
|
codes[pair[0]] = i
|
||||||
low = pair[1].lower()
|
low = pair[1].lower()
|
||||||
codes[low] = i
|
codes[low] = i
|
||||||
codes[low.replace("gray","grey")] = i
|
codes[low.replace("gray", "grey")] = i
|
||||||
codes["green"] = 2
|
codes["green"] = 2
|
||||||
codes["fuchsia"] = 4
|
codes["fuchsia"] = 4
|
||||||
codes["aqua"] = 6
|
codes["aqua"] = 6
|
||||||
@ -72,7 +88,7 @@ class ColorMap(object):
|
|||||||
try:
|
try:
|
||||||
return int(colortext)
|
return int(colortext)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return ColorMap.codes.get(colortext.lower().replace("_",""),-1)
|
return ColorMap.codes.get(colortext.lower().replace("_", ""),-1)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_hex(code):
|
def check_hex(code):
|
||||||
@ -96,7 +112,6 @@ class ColorMap(object):
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_vars(main, time):
|
def get_vars(main, time):
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
@ -112,10 +127,13 @@ def get_vars(main, time):
|
|||||||
vars.append(vars[0])
|
vars.append(vars[0])
|
||||||
if len(vars) == 3:
|
if len(vars) == 3:
|
||||||
vars.append("")
|
vars.append("")
|
||||||
name, unit, label, color = vars
|
if len(vars) == 4:
|
||||||
|
vars.append("") # exact flag
|
||||||
|
name, unit, label, color, continuous = vars
|
||||||
|
continuous = int(continuous) if continuous else 0
|
||||||
if not unit in result:
|
if not unit in result:
|
||||||
result[unit] = dict(tag = unit, unit = unit.split("_")[0], curves=Dict())
|
result[unit] = dict(tag=unit, unit=unit.split("_")[0], curves=Dict())
|
||||||
result[unit]["curves"][name] = dict(name=name, label=label, color=color)
|
result[unit]["curves"][name] = dict(name=name, label=label, color=color, continuous=continuous)
|
||||||
|
|
||||||
for unit, curvegroup in result.items():
|
for unit, curvegroup in result.items():
|
||||||
color_set = set()
|
color_set = set()
|
||||||
@ -137,14 +155,19 @@ def get_vars(main, time):
|
|||||||
color_set.add(c)
|
color_set.add(c)
|
||||||
curve["original_color"] = col
|
curve["original_color"] = col
|
||||||
curve["color"] = ColorMap.to_hex(c)
|
curve["color"] = ColorMap.to_hex(c)
|
||||||
c = 1 # omit white
|
c = 1 # omit white
|
||||||
for curve in auto_curves:
|
for curve in auto_curves:
|
||||||
while c in color_set: c += 1 # find unused color
|
while c in color_set:
|
||||||
|
c += 1 # find unused color
|
||||||
curve["color"] = ColorMap.to_hex(c)
|
curve["color"] = ColorMap.to_hex(c)
|
||||||
c += 1
|
c += 1
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_curves(main, keys, timerange, show_empty=True):
|
def get_curves(main, keys, timerange, cut_begin=True):
|
||||||
curves = main.get_curves(keys, get_abs_time(*timerange), maxpoints=500)
|
curves = main.get_curves(keys, get_abs_time(*timerange), maxpoints=500, cut_begin=cut_begin)
|
||||||
|
#if 'tt:target' in curves:
|
||||||
|
# print('---')
|
||||||
|
# print(curves['tt:target'].fmtm())
|
||||||
|
# print('TT', curves['tt:target'].for_json()[-5:])
|
||||||
return {k: c.for_json() for k, c in curves.items()}
|
return {k: c.for_json() for k, c in curves.items()}
|
||||||
|
101
seaweb_hist.py
101
seaweb_hist.py
@ -64,7 +64,7 @@ def get_update(path=None):
|
|||||||
@flask.stream_with_context
|
@flask.stream_with_context
|
||||||
def generator():
|
def generator():
|
||||||
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1]))
|
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1]))
|
||||||
msg = dict(type='id', id=client.id, title=instrument.title, device=instrument.device);
|
msg = dict(type='id', id=client.id, instrument=instrument.title, device=instrument.device);
|
||||||
yield to_json_sse(msg)
|
yield to_json_sse(msg)
|
||||||
try:
|
try:
|
||||||
lastmsg = time.time()
|
lastmsg = time.time()
|
||||||
@ -130,6 +130,7 @@ def reply():
|
|||||||
try:
|
try:
|
||||||
id = kwargs.pop('id')
|
id = kwargs.pop('id')
|
||||||
client = instrument.clients[id]
|
client = instrument.clients[id]
|
||||||
|
print('PATH', path)
|
||||||
msg = getattr(client, "w_" + path[1:])(**kwargs)
|
msg = getattr(client, "w_" + path[1:])(**kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('%s', traceback.format_exc())
|
logging.error('%s', traceback.format_exc())
|
||||||
@ -257,6 +258,7 @@ class Instrument:
|
|||||||
self.clients[client.id] = client
|
self.clients[client.id] = client
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
class SeaInstrument(Instrument):
|
class SeaInstrument(Instrument):
|
||||||
# convert SEA layout tag like "-W" to more meaningful name.
|
# convert SEA layout tag like "-W" to more meaningful name.
|
||||||
# the code: 0: modifier, 1: enum name, 2: input element
|
# the code: 0: modifier, 1: enum name, 2: input element
|
||||||
@ -502,17 +504,18 @@ class SeaGraph:
|
|||||||
LIVE = 2
|
LIVE = 2
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.livemode = self.HISTORICAL
|
self.livemode = self.ACTUAL
|
||||||
self.time = [0, 0]
|
self.time = [0, 0]
|
||||||
self.lastvalues = {}
|
self.lastvalues = {}
|
||||||
|
self.variables = []
|
||||||
|
|
||||||
def graphpoll(self):
|
def graphpoll(self):
|
||||||
if self.livemode == self.LIVE:
|
if self.livemode == self.LIVE:
|
||||||
self.time[1], = get_abs_time(0)
|
self.time[1], = get_abs_time(0)
|
||||||
else:
|
else:
|
||||||
self.time[1] = self.time[0] # do not update
|
self.time[1] = self.time[0] # do not update
|
||||||
if self.time[1] > self.time[0]:
|
if self.time[1] > self.time[0]:
|
||||||
result = get_curves(main_cache, self.variables, self.time, show_empty=False)
|
result = get_curves(main_cache, self.variables, self.time, cut_begin=False)
|
||||||
self.strip_future(result)
|
self.strip_future(result)
|
||||||
if int(self.time[1] / 60) != int(self.time[0] / 60):
|
if int(self.time[1] / 60) != int(self.time[0] / 60):
|
||||||
# update unchanged values
|
# update unchanged values
|
||||||
@ -533,14 +536,8 @@ class SeaGraph:
|
|||||||
self.lastvalues[var] = (endtime, lastx)
|
self.lastvalues[var] = (endtime, lastx)
|
||||||
|
|
||||||
def strip_future(self, result):
|
def strip_future(self, result):
|
||||||
"""strip future points (happens only on dummy test_day)"""
|
"""strip future points (implemented on dummy test_day)"""
|
||||||
# if self.livemode == self.LIVE:
|
pass # do nothing here
|
||||||
for c in result.values():
|
|
||||||
while len(c):
|
|
||||||
lastt, lastx = c[-1]
|
|
||||||
if lastt <= self.time[1]:
|
|
||||||
break
|
|
||||||
c.pop()
|
|
||||||
|
|
||||||
def w_gettime(self, time):
|
def w_gettime(self, time):
|
||||||
result = get_abs_time(*[float(t) for t in time.split(',')])
|
result = get_abs_time(*[float(t) for t in time.split(',')])
|
||||||
@ -552,7 +549,8 @@ class SeaGraph:
|
|||||||
self.last_t = 0
|
self.last_t = 0
|
||||||
start, end, now = get_abs_time(*time, 0)
|
start, end, now = get_abs_time(*time, 0)
|
||||||
self.time = [start, end]
|
self.time = [start, end]
|
||||||
self.variables = variables.split(',')
|
oldvars = set(self.variables)
|
||||||
|
self.variables.extend((v for v in variables.split(',') if v not in oldvars))
|
||||||
self.livemode = self.ACTUAL if end >= now else self.HISTORICAL
|
self.livemode = self.ACTUAL if end >= now else self.HISTORICAL
|
||||||
logging.info('LIVE %g %g %d %d', end, now, end >= now, self.livemode)
|
logging.info('LIVE %g %g %d %d', end, now, end >= now, self.livemode)
|
||||||
# self.scanner = seagraph.NumericScanner(instrument.logger_dir, instrument.test_day)
|
# self.scanner = seagraph.NumericScanner(instrument.logger_dir, instrument.test_day)
|
||||||
@ -561,7 +559,7 @@ class SeaGraph:
|
|||||||
self.strip_future(result)
|
self.strip_future(result)
|
||||||
logging.info('VARIABLES: %r %r %r', self.variables, start-now, end-now)
|
logging.info('VARIABLES: %r %r %r', self.variables, start-now, end-now)
|
||||||
for var, curve in list(result.items()):
|
for var, curve in list(result.items()):
|
||||||
logging.info(' %s %r len=%d', var, curve[-1][0] - curve[0][0], len(curve))
|
logging.info(' %s %r len=%d', var, curve[-1][0] - curve[0][0] if len(curve) else None, len(curve))
|
||||||
self.complete_to_end(result, end)
|
self.complete_to_end(result, end)
|
||||||
self.time[0] = self.time[1]
|
self.time[0] = self.time[1]
|
||||||
# reduction not yet implemented
|
# reduction not yet implemented
|
||||||
@ -575,8 +573,10 @@ class SeaGraph:
|
|||||||
logging.info('GotVARS %r', result)
|
logging.info('GotVARS %r', result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def w_updategraph(self):
|
def w_updategraph(self, variables=''):
|
||||||
logging.info("UPD GRAPH %d", self.livemode)
|
if variables:
|
||||||
|
self.variables = variables.split(',')
|
||||||
|
logging.info("UPD GRAPH %d %r", self.livemode, self.variables)
|
||||||
if self.livemode == self.HISTORICAL:
|
if self.livemode == self.HISTORICAL:
|
||||||
return dict(type='accept-graph', live=False)
|
return dict(type='accept-graph', live=False)
|
||||||
else:
|
else:
|
||||||
@ -658,7 +658,7 @@ class SeaClient(SeaGraph):
|
|||||||
|
|
||||||
|
|
||||||
class DummyClient(SeaGraph):
|
class DummyClient(SeaGraph):
|
||||||
async = set(('id','update','redraw','command','reply','graph-update','graph-redraw'))
|
asynch = set(('id','update','redraw','command','reply','graph-update','graph-redraw'))
|
||||||
|
|
||||||
def __init__(self, host_port):
|
def __init__(self, host_port):
|
||||||
self.linesocket = tcp_lineserver.LineClient(host_port)
|
self.linesocket = tcp_lineserver.LineClient(host_port)
|
||||||
@ -678,7 +678,7 @@ class DummyClient(SeaGraph):
|
|||||||
line = self.linesocket.get_line()
|
line = self.linesocket.get_line()
|
||||||
if line != None:
|
if line != None:
|
||||||
msg = json.loads(line)
|
msg = json.loads(line)
|
||||||
if msg.type in self.async:
|
if msg.type in self.asynch:
|
||||||
t = 0
|
t = 0
|
||||||
# print 'PUSH',msg, replytype
|
# print 'PUSH',msg, replytype
|
||||||
self.queue.append(msg)
|
self.queue.append(msg)
|
||||||
@ -693,6 +693,12 @@ class DummyClient(SeaGraph):
|
|||||||
logging.error('REPLY MISMATCH %s %s <> %s', command, replytype, msg.type)
|
logging.error('REPLY MISMATCH %s %s <> %s', command, replytype, msg.type)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def strip_future(self, result):
|
||||||
|
for c in result.values():
|
||||||
|
while len(c):
|
||||||
|
if c[-1][0] <= self.time[1]:
|
||||||
|
break
|
||||||
|
c.pop()
|
||||||
|
|
||||||
def w_getblock(self, path):
|
def w_getblock(self, path):
|
||||||
return self.cmd_reply(dict(type='getblock', path=path, id=self.id), 'draw')
|
return self.cmd_reply(dict(type='getblock', path=path, id=self.id), 'draw')
|
||||||
@ -718,7 +724,7 @@ class DummyClient(SeaGraph):
|
|||||||
messages = []
|
messages = []
|
||||||
if line:
|
if line:
|
||||||
msg = json.loads(line)
|
msg = json.loads(line)
|
||||||
if msg.type in self.async:
|
if msg.type in self.asynch:
|
||||||
messages.append(msg)
|
messages.append(msg)
|
||||||
else:
|
else:
|
||||||
self.syncreply.append(msg)
|
self.syncreply.append(msg)
|
||||||
@ -761,7 +767,7 @@ class SecopMsg:
|
|||||||
self.par = sl[1]
|
self.par = sl[1]
|
||||||
if len(sl) > 2:
|
if len(sl) > 2:
|
||||||
self.value = json.loads(' '.join(sl[2:]))
|
self.value = json.loads(' '.join(sl[2:]))
|
||||||
self.async = self.type in ('update', 'error_update')
|
self.asynch = self.type in ('update', 'error_update')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
value = repr(self.value)
|
value = repr(self.value)
|
||||||
@ -828,15 +834,15 @@ class SecopClient(SeaGraph):
|
|||||||
msg = self.syncreply.pop(0)
|
msg = self.syncreply.pop(0)
|
||||||
break
|
break
|
||||||
line = self.linesocket.get_line()
|
line = self.linesocket.get_line()
|
||||||
if line != None:
|
if line is not None:
|
||||||
msg = SecopMsg(line)
|
msg = SecopMsg(line)
|
||||||
if msg.async:
|
if msg.asynch:
|
||||||
self.consolequeue.append(dict(type='reply',line=line,origin='async'))
|
self.consolequeue.append(dict(type='reply',line=line,origin='async'))
|
||||||
else:
|
else:
|
||||||
self.consolequeue.append(dict(type='reply',line=line,origin='other'))
|
self.consolequeue.append(dict(type='reply',line=line,origin='other'))
|
||||||
if self.out: self.out.write("<"+line+"\n")
|
if self.out: self.out.write("<"+line+"\n")
|
||||||
#print '<', msg.type, msg.par
|
#print '<', msg.type, msg.par
|
||||||
if msg.async and replytype != msg.type + "=" + msg.par:
|
if msg.asynch and replytype != msg.type + "=" + msg.par:
|
||||||
t = 0
|
t = 0
|
||||||
self.queue.append(msg)
|
self.queue.append(msg)
|
||||||
else:
|
else:
|
||||||
@ -895,31 +901,41 @@ class SecopClient(SeaGraph):
|
|||||||
if not command:
|
if not command:
|
||||||
return dict(type='accept-command')
|
return dict(type='accept-command')
|
||||||
cmd = "change " + command
|
cmd = "change " + command
|
||||||
return self.cmd_reply(cmd, 'changed ' + command.split(' ')[0])
|
self.cmd_reply(cmd, 'changed ' + command.split(' ')[0])
|
||||||
|
return dict(type='accept-command')
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
|
messages = []
|
||||||
if self.consolequeue:
|
if self.consolequeue:
|
||||||
messages = self.consolequeue
|
messages.extend(self.consolequeue)
|
||||||
self.consolequeue = []
|
self.consolequeue = []
|
||||||
return messages
|
|
||||||
if self.queue:
|
if self.queue:
|
||||||
messages = convert_event(self.queue)
|
messages.extend(convert_event(self.queue))
|
||||||
self.queue = []
|
self.queue = []
|
||||||
return messages
|
while True:
|
||||||
line = self.linesocket.get_line()
|
line = self.linesocket.get_line()
|
||||||
# logging.info('poll %s', line)
|
if not line:
|
||||||
if line:
|
break
|
||||||
if self.out: self.out.write("<"+line+"\n")
|
# logging.info('poll %s', line)
|
||||||
|
if self.out:
|
||||||
|
self.out.write("<"+line+"\n")
|
||||||
msg = SecopMsg(line)
|
msg = SecopMsg(line)
|
||||||
if msg.async: # do not flood console with updates
|
if msg.asynch: # do not flood console with updates
|
||||||
self.consolequeue.append(dict(type='reply',line=line,origin='async'))
|
if msg.par == 'tt:target':
|
||||||
|
print(msg)
|
||||||
|
self.consolequeue.append(dict(type='reply', line=line, origin='async'))
|
||||||
else:
|
else:
|
||||||
self.consolequeue.append(dict(type='reply',line=line,origin='other'))
|
self.consolequeue.append(dict(type='reply', line=line, origin='other'))
|
||||||
# logging.info('GOT MSG %r %r', msg.async, convert_event(SecopMsg(line)))
|
# logging.info('GOT MSG %r %r', msg.asynch, convert_event(SecopMsg(line)))
|
||||||
if msg.async:
|
if msg.asynch:
|
||||||
return convert_event(SecopMsg(line))
|
messages.extend(convert_event(SecopMsg(line)))
|
||||||
self.syncreply.append(msg)
|
else:
|
||||||
return []
|
self.syncreply.append(msg)
|
||||||
|
# graph messages
|
||||||
|
msg = self.graphpoll()
|
||||||
|
if msg:
|
||||||
|
messages.append(msg)
|
||||||
|
return messages
|
||||||
|
|
||||||
def info(self):
|
def info(self):
|
||||||
return ["na"]
|
return ["na"]
|
||||||
@ -939,6 +955,7 @@ class SecopInstrument(Instrument):
|
|||||||
def newClient(self):
|
def newClient(self):
|
||||||
cl = SecopClient(self.host_port)
|
cl = SecopClient(self.host_port)
|
||||||
self.device = cl.description['equipment_id']
|
self.device = cl.description['equipment_id']
|
||||||
|
print('EQU', self.device)
|
||||||
logging.info('init done %s %s', self.host_port, self.device)
|
logging.info('init done %s %s', self.host_port, self.device)
|
||||||
return self.register(cl)
|
return self.register(cl)
|
||||||
|
|
||||||
@ -989,8 +1006,8 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
instrument_config = instrument_list[inst_name]
|
instrument_config = instrument_list[inst_name]
|
||||||
|
|
||||||
frd = FrappyReader('/home/l_samenv/sea/%s' % inst_name, gevent=gevent)
|
frd = FrappyReader('/Users/zolliker/frappyhist/%s' % inst_name, gevent=gevent)
|
||||||
main_cache = MainCache('/home/l_samenv/histreader/%s_hist' % inst_name, frd, gevent=gevent)
|
main_cache = MainCache('/Users/zolliker/frappyhist/%s_hist' % inst_name, frd, gevent=gevent)
|
||||||
|
|
||||||
# logging.basicConfig(filename=inst_name+".log", filemode='w', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
|
# logging.basicConfig(filename=inst_name+".log", filemode='w', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
|
||||||
|
@ -5,6 +5,7 @@ import re
|
|||||||
import circularlog
|
import circularlog
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class LineHandler(asyncore.dispatcher_with_send):
|
class LineHandler(asyncore.dispatcher_with_send):
|
||||||
|
|
||||||
def __init__(self, sock):
|
def __init__(self, sock):
|
||||||
@ -38,6 +39,7 @@ class LineHandler(asyncore.dispatcher_with_send):
|
|||||||
'''
|
'''
|
||||||
self.send_line("> " + line)
|
self.send_line("> " + line)
|
||||||
|
|
||||||
|
|
||||||
class LineServer(asyncore.dispatcher):
|
class LineServer(asyncore.dispatcher):
|
||||||
|
|
||||||
def __init__(self, host, port, lineHandlerClass):
|
def __init__(self, host, port, lineHandlerClass):
|
||||||
@ -58,9 +60,11 @@ class LineServer(asyncore.dispatcher):
|
|||||||
def loop(self):
|
def loop(self):
|
||||||
asyncore.loop()
|
asyncore.loop()
|
||||||
|
|
||||||
|
|
||||||
class Disconnected(Exception):
|
class Disconnected(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class LineClient(object):
|
class LineClient(object):
|
||||||
|
|
||||||
def __init__(self, host_port, announcement=None, filter_ascii=False, ridername="r"):
|
def __init__(self, host_port, announcement=None, filter_ascii=False, ridername="r"):
|
||||||
@ -122,7 +126,8 @@ class LineClient(object):
|
|||||||
def close(self):
|
def close(self):
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
server = LineServer("localhost", 9999, LineHandler)
|
server = LineServer("localhost", 9999, LineHandler)
|
||||||
server.loop()
|
server.loop()
|
||||||
|
Reference in New Issue
Block a user