jroplots.js
454 lines
| 13.8 KiB
| application/javascript
|
JavascriptLexer
r0 | ||||
class PcolorBuffer{ | ||||
constructor({div, data, key, props}){ | ||||
this.div = document.getElementById(div); | ||||
this.n = 0 | ||||
this.divs = []; | ||||
this.wait = false; | ||||
this.key = key; | ||||
this.timer = (props.throttle || 30)*1000; | ||||
this.lastRan = Date.now(); | ||||
this.lastFunc = null; | ||||
this.zbuffer = []; | ||||
this.xbuffer = []; | ||||
this.empty = Array(data.yrange.length).fill(null); | ||||
this.props = props; | ||||
this.setup(data); | ||||
} | ||||
setup(data){ | ||||
this.last = data.time.slice(-1); | ||||
if (data.time.length == 1){ | ||||
var values = { 'time': data.time, 'data': data[this.key].map(function(x) {return [x]})}; | ||||
}else{ | ||||
var values = this.fill_gaps(data.time, data[this.key], data.interval, data[this.key].length); | ||||
} | ||||
var t = values.time.map(function(x) { return new Date(x*1000); }); | ||||
for (var i = 0; i < data[this.key].length; i++){ | ||||
var layout = { | ||||
xaxis: { | ||||
title: 'Time', | ||||
showgrid: false, | ||||
}, | ||||
yaxis: { | ||||
title: 'km', | ||||
showgrid: false, | ||||
}, | ||||
titlefont: { | ||||
size: 14, | ||||
} | ||||
}; | ||||
var iDiv = document.createElement('div'); | ||||
iDiv.id = 'plot-' + i; | ||||
this.zbuffer.push([]); | ||||
this.n = this.n + 1; | ||||
this.div.appendChild(iDiv); | ||||
this.divs.push(iDiv.id); | ||||
var trace = { | ||||
z: values.data[i], | ||||
x: t, | ||||
y: data.yrange, | ||||
colorscale: this.props.colormap || 'Viridis', | ||||
transpose: true, | ||||
type: 'heatmap' | ||||
}; | ||||
if (this.props.zmin) {trace.zmin = this.props.zmin} | ||||
if (this.props.zmax) {trace.zmax = this.props.zmax} | ||||
layout.title = 'Channel ' + i + ' - ' + t.slice(-1).toLocaleString(); | ||||
var conf = { | ||||
modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], | ||||
displaylogo: false, | ||||
showTips: true | ||||
}; | ||||
Plotly.newPlot('plot-'+i, [trace], layout, conf); | ||||
} | ||||
} | ||||
getSize(){ | ||||
var div = document.getElementById(this.divs[0]); | ||||
var t = this.xbuffer.slice(-1)[0]; | ||||
var n = 0; | ||||
var timespan = (this.props.timespan || 8)*1000*60*60; | ||||
while ((t-div.data[0].x[n]) > timespan){ | ||||
n += 1; | ||||
} | ||||
return n; | ||||
} | ||||
fill_gaps(xBuffer, zBuffer, interval, N){ | ||||
var x = [xBuffer[0]]; | ||||
var z = []; | ||||
var last; | ||||
for (var j = 0; j < N; j++){ | ||||
z.push([zBuffer[j][0]]); | ||||
} | ||||
for (var i = 1; i < xBuffer.length; i++){ | ||||
var cnt = 0; | ||||
last = x.slice(-1)[0]; | ||||
while (Math.abs(parseFloat(xBuffer[i])-last-parseFloat(interval))>0.5){ | ||||
cnt += 1; | ||||
last = last+interval; | ||||
x.push(last); | ||||
for (var j = 0; j < N; j++){ | ||||
z[j].push(this.empty); | ||||
} | ||||
// Avoid infinite loop | ||||
if (cnt==100){break;} | ||||
} | ||||
x.push(xBuffer[i]); | ||||
for (var j = 0; j < N; j++){ | ||||
z[j].push(zBuffer[j][i]); | ||||
} | ||||
} | ||||
return {'time':x, 'data':z}; | ||||
} | ||||
plot(){ | ||||
// add new data to plots and empty buffers | ||||
var N = this.getSize(); | ||||
console.log('Plotting...'); | ||||
for (var i = 0; i < this.n; i++){ | ||||
var div = document.getElementById(this.divs[i]); | ||||
if (N > 0){ | ||||
div.data[0].z = div.data[0].z.slice(N,) | ||||
div.data[0].x = div.data[0].x.slice(N,) | ||||
} | ||||
Plotly.extendTraces(div, { | ||||
z: [this.zbuffer[i]], | ||||
x: [this.xbuffer] | ||||
}, [0]); | ||||
this.zbuffer[i] = []; | ||||
} | ||||
this.xbuffer = []; | ||||
} | ||||
update(obj){ | ||||
// fill data gaps | ||||
var cnt = 0; | ||||
while (Math.abs(parseFloat(obj.time[0])-this.last-parseFloat(obj.interval))>0.5){ | ||||
cnt += 1; | ||||
this.last += obj.interval; | ||||
var newt = new Date((this.last)*1000); | ||||
this.xbuffer.push(newt); | ||||
for (var i = 0; i < obj[this.key].length; i++){ | ||||
this.zbuffer[i].push(this.empty); | ||||
} | ||||
// Avoid infinite loop | ||||
if (cnt==100){break;} | ||||
} | ||||
// update buffers | ||||
this.last = parseFloat(obj.time[0]); | ||||
var t = new Date(obj.time[0]*1000); | ||||
this.xbuffer.push(t); | ||||
for (var i = 0; i < obj[this.key].length; i++){ | ||||
this.zbuffer[i].push(obj[this.key][i]); | ||||
// update title | ||||
var div = document.getElementById(this.divs[i]); | ||||
Plotly.relayout(div, { | ||||
title: 'Channel ' + i + ' - ' + t.toLocaleString(), | ||||
}); | ||||
} | ||||
// plot when ready (every 10 secs) | ||||
if (!this.wait){ | ||||
this.plot(); | ||||
this.wait = true; | ||||
} else { | ||||
clearTimeout(this.lastFunc) | ||||
this.lastFunc = setTimeout(function(scope) { | ||||
if ((Date.now() - scope.lastRan) >= scope.timer) { | ||||
scope.plot() | ||||
scope.lastRan = Date.now() | ||||
} | ||||
}, this.timer - (Date.now() - this.lastRan), this) | ||||
} | ||||
} | ||||
} | ||||
class Pcolor{ | ||||
constructor({div, data, props}){ | ||||
this.div = document.getElementById(div); | ||||
this.n = 0 | ||||
this.divs = []; | ||||
this.props = props; | ||||
this.setup(data); | ||||
} | ||||
setup(data){ | ||||
console.log(data); | ||||
for (var i = 0; i < data.spc.length; i++){ | ||||
var layout = { | ||||
height: 400, | ||||
xaxis: { | ||||
title: 'Velocity', | ||||
showgrid: false, | ||||
zeroline: false, | ||||
domain: [0, 0.7], | ||||
}, | ||||
yaxis: { | ||||
title: 'km', | ||||
showgrid: false, | ||||
}, | ||||
xaxis2: { | ||||
title: 'dB', | ||||
domain: [0.75, 1], | ||||
ticks: 'outside', | ||||
}, | ||||
titlefont: { | ||||
size: 14, | ||||
} | ||||
}; | ||||
var iDiv = document.createElement('div'); | ||||
iDiv.id = 'plot-' + i; | ||||
iDiv.className += iDiv.className ? ' col-md-6' : 'col-md-6'; | ||||
this.n = this.n + 1; | ||||
this.div.appendChild(iDiv); | ||||
this.divs.push(iDiv.id); | ||||
var trace1 = { | ||||
z: data.spc[i], | ||||
x: data.xrange, | ||||
y: data.yrange, | ||||
colorscale: this.props.colormap || 'Viridis', | ||||
transpose: true, | ||||
type: 'heatmap' | ||||
}; | ||||
var trace2 = { | ||||
x: data.rti[i], | ||||
y: data.yrange, | ||||
xaxis: 'x2', | ||||
yaxis: 'y', | ||||
type: 'scatter', | ||||
}; | ||||
if (this.props.zmin) { | ||||
trace1.zmin = this.props.zmin | ||||
} | ||||
if (this.props.zmax) { | ||||
trace1.zmax = this.props.zmax; | ||||
layout.xaxis2.range = [this.props.zmin, this.props.zmax] | ||||
} | ||||
var t = new Date(data.time*1000); | ||||
layout.title = 'Channel ' + i + ': ' + data.noise[i]+'dB - ' + t.toLocaleString(); | ||||
var conf = { | ||||
modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], | ||||
displaylogo: false, | ||||
showTips: true | ||||
}; | ||||
Plotly.newPlot('plot-'+i, [trace1, trace2], layout, conf); | ||||
} | ||||
} | ||||
plot(obj){ | ||||
// add new data to plots and empty buffers | ||||
console.log('Plotting...'); | ||||
var t = new Date(obj.time[0]*1000); | ||||
for (var i = 0; i < this.n; i++){ | ||||
var div = document.getElementById(this.divs[i]); | ||||
Plotly.relayout(div, { | ||||
title: 'Channel ' + i + ': ' + obj.noise[i]+'dB - ' + t.toLocaleString(), | ||||
}); | ||||
Plotly.restyle(div, { | ||||
z: [obj.spc[i], null], | ||||
x: [obj.xrange, obj.rti[i]] | ||||
}, [0, 1]); | ||||
} | ||||
} | ||||
} | ||||
class Scatter{ | ||||
constructor({div, data, key, props}){ | ||||
this.div = document.getElementById(div); | ||||
this.n = 0 | ||||
this.key = key; | ||||
this.wait = false; | ||||
this.timer = (props.throttle || 30)*1000; | ||||
this.lastRan = Date.now(); | ||||
this.lastFunc = null; | ||||
this.ybuffer = []; | ||||
this.xbuffer = []; | ||||
this.props = props; | ||||
this.setup(data); | ||||
} | ||||
setup(data){ | ||||
var traces = []; | ||||
this.last = data.time.slice(-1); | ||||
if (data.time.length == 1){ | ||||
var values = { 'time': data.time, 'data': data[this.key] }; | ||||
}else{ | ||||
var values = this.fill_gaps(data.time, data[this.key], data.interval, data[this.key].length); | ||||
} | ||||
var t = values.time.map(function(x) { return new Date(x*1000); }); | ||||
for (var i = 0; i < data[this.key].length; i++){ | ||||
this.n = this.n + 1; | ||||
this.ybuffer.push([]); | ||||
var trace = { | ||||
x: t, | ||||
y: data[this.key][i], | ||||
mode: 'lines', | ||||
type: 'scatter', | ||||
name: 'Channel ' + i | ||||
}; | ||||
traces.push(trace); | ||||
} | ||||
var title = this.props.title || '' | ||||
var layout = { | ||||
// autosize: false, | ||||
// width: 800, | ||||
// height: 400, | ||||
title: title + ' - ' + t.slice(-1).toLocaleString(), | ||||
xaxis: { | ||||
title: 'Time', | ||||
linecolor: 'black', | ||||
}, | ||||
yaxis: { | ||||
title: this.props.ylabel || 'dB', | ||||
linecolor: 'black', | ||||
}, | ||||
titlefont: { | ||||
size: 14, | ||||
} | ||||
}; | ||||
if (this.props.ymin) {layout.yaxis.range = [this.props.ymin, this.props.ymax] } | ||||
var conf = { | ||||
modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], | ||||
displaylogo: false, | ||||
showTips: true | ||||
}; | ||||
Plotly.newPlot('plot', traces, layout, conf); | ||||
} | ||||
getSize(){ | ||||
var t = this.xbuffer.slice(-1)[0]; | ||||
var n = 0; | ||||
var timespan = (this.props.timespan || 12)*1000*60*60; | ||||
while ((t-this.div.data[0].x[n]) > timespan){ | ||||
n += 1; | ||||
} | ||||
return n; | ||||
} | ||||
fill_gaps(xBuffer, yBuffer, interval, N){ | ||||
var x = [xBuffer[0]]; | ||||
var y = []; | ||||
for (var j = 0; j < N; j++){ | ||||
y.push([yBuffer[j][0]]); | ||||
} | ||||
var last; | ||||
for (var i = 1; i < xBuffer.length; i++){ | ||||
var cnt = 0; | ||||
last = x.slice(-1)[0]; | ||||
while (Math.abs(parseFloat(xBuffer[i])-last-parseFloat(interval))>0.5){ | ||||
cnt += 1; | ||||
last = last+interval; | ||||
x.push(last); | ||||
for (var j = 0; j < N; j++){ | ||||
z[j].push(null); | ||||
} | ||||
// Avoid infinite loop | ||||
if (cnt==100){break;} | ||||
} | ||||
x.push(xBuffer[i]); | ||||
for (var j = 0; j < N; j++){ | ||||
y[j].push(yBuffer[j][i]); | ||||
} | ||||
} | ||||
return {'time':x, 'data':y}; | ||||
} | ||||
plot(){ | ||||
// add new data to plots and empty buffers | ||||
var xvalues = []; | ||||
var yvalues = []; | ||||
var traces = []; | ||||
var N = this.getSize(); | ||||
console.log('Plotting...'); | ||||
for (var i = 0; i < this.n; i++){ | ||||
if (N > 0){ | ||||
this.div.data[i].y = this.div.data[i].y.slice(N,) | ||||
this.div.data[i].x = this.div.data[i].x.slice(N,) | ||||
} | ||||
yvalues.push(this.ybuffer[i]); | ||||
xvalues.push(this.xbuffer); | ||||
traces.push(i); | ||||
this.ybuffer[i] = []; | ||||
} | ||||
Plotly.extendTraces(this.div, { | ||||
y: yvalues, | ||||
x: xvalues | ||||
}, traces); | ||||
this.xbuffer = []; | ||||
} | ||||
update(obj){ | ||||
// fill data gaps | ||||
var cnt = 0; | ||||
while (Math.abs(parseFloat(obj.time[0])-this.last-parseFloat(obj.interval))>0.5){ | ||||
cnt += 1; | ||||
this.last += obj.interval; | ||||
var newt = new Date((this.last)*1000); | ||||
this.xbuffer.push(newt); | ||||
for (var i = 0; i < this.n; i++){ | ||||
this.ybuffer[i].push(null); | ||||
} | ||||
// Avoid infinite loop | ||||
if (cnt==100){break;} | ||||
} | ||||
// update buffers | ||||
this.last = parseFloat(obj.time[0]); | ||||
var t = new Date(obj.time[0]*1000); | ||||
this.xbuffer.push(t); | ||||
for (var i = 0; i < this.n; i++){ | ||||
this.ybuffer[i].push(obj[this.key][i][0]); | ||||
} | ||||
var title = this.props.title || '' | ||||
Plotly.relayout(this.div, { | ||||
title: title + ' - ' + t.toLocaleString(), | ||||
}); | ||||
// plot when ready (every 10 secs) | ||||
if (!this.wait){ | ||||
this.plot(); | ||||
this.wait = true; | ||||
} else { | ||||
clearTimeout(this.lastFunc) | ||||
this.lastFunc = setTimeout(function(scope) { | ||||
if ((Date.now() - scope.lastRan) >= scope.timer) { | ||||
scope.plot() | ||||
scope.lastRan = Date.now() | ||||
} | ||||
}, this.timer - (Date.now() - this.lastRan), this) | ||||
} | ||||
} | ||||
} | ||||