Files
eacp_webapp/htdocs/stattest/index.html
T
2026-06-16 11:24:50 +08:00

279 lines
8.6 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- <link href="https://cdn.jsdelivr.net/npm/nvd3@1.8.6/build/nv.d3.min.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js" charset="utf-8"></script>
<script src="https://cdn.jsdelivr.net/npm/nvd3@1.8.6/build/nv.d3.min.js"></script>
<script src="http://nvd3.org/assets/js/data/stream_layers.js"></script>-->
<link rel="stylesheet" src="//cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/dygraphs@2.0.0/src/extras/crosshair.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>
<body>
<style>
.dygraph-label { text-align: center; }
.dygraph-xlabel{
position: relative;
right: 130px;
text-anchor:center;
text-align:right;
}
.dygraph-ylabel {
position: relative;
top: 25px;
left: 20px;
text-align:right;
transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
}
</style>
<div id="noroll" style="width:400px; height:300px;border:1px solid black"></div>
<script type="text/javascript">
var seriesKeys = [ //"allframespersecond",
"aclist_size",
"aclist_listed",
"aclist_nof_adsb",
"aclist_nof_mlat",
"aclist_nof_flawa",
"aclist_nof_ogn",
"aclist_nof_flarm"
];
$(document).ready(function () {
var data = [ [new Date()].concat(Array(seriesKeys.length).fill(0)) ];
var userIsInteracting = false;
const myInteractions = Object.assign({}, Dygraph.defaultInteractionModel, {
mousedown: (event, g, context) => {
console.log("start mousedown");
userIsInteracting = true;
context.initializeMouseDown(event, g, context);
Dygraph.startPan(event, g, context);
},
mouseup: (event, g, context) => {
console.log("mouseup", event, g, context);
userIsInteracting = false;
Dygraph.endPan(event, g, context);
context.isPanning = false;
}
});
function zeropad(x) {
if (x < 10) return "0" + x;else return "" + x;
}
var g = new Dygraph(
document.getElementById("noroll"),
data,
{
customBars: false, // no error bars
labels: ["Date", /*"Frames/s",*/ "Total", "Listed", "ADS-B", "MLAT", "FlAwa", "OGN", "FLARM"],
title: 'AC Stats',
ylabel:'Number of Aircrafts',
xlabel:'Time (UTC)',
//legend: 'always',
axisLineWidth:2.0,
interactionModel: myInteractions,
plugins: [
new Dygraph.Plugins.Crosshair({
direction: "vertical"
})
],
series:{
'Total': {
strokePattern: Dygraph.DOT_DASH_LINE
},
'Recent':{
strokePattern: Dygraph.DASHED_LINE
}
},
axes: {
'x': {
axisLabelFormatter: function(d, gran) {
return zeropad(d.getHours()) + ":"
+ zeropad(d.getMinutes()) + ":"
+ zeropad(d.getSeconds());
}
}
},
digitsAfterDecimal:0, // always display same-length of date
strokeWidth: 3,
showRangeSelector: true,
rangeSelectorHeight: 40,
axisLabelFontSize: 15,
labelsUTC:true,
//showRoller: true,
rollPeriod: 10,
drawPoints:false,
rangeSelectorPlotFillColor: "#A7B1C4"
}
);
var plotRefresh = function(userIsInteracting) {
if(userIsInteracting){
console.log("inhibiting");
return;
}
const fetchStatisticData = unit =>
fetch('/statistic.json?select='+unit, {credentials: 'include'}).then(function(rawResponse) {
return rawResponse.json();
}).then(function(arg){
var result = {
unit: unit, // unit to which the arrayfragment belongs
arrayFragment: parseBaseData({json:arg, unit:unit}) // parse json and return part of that array
}
return result;
});
var units = ["seconds", "minutes", "hours"];
/* Determine whether we need to clamp the window right or left or not at all */
// start and end timestamp of previous run's data arrays
var dateWindow = g.dateWindow_; // get currently set dateWindow
var oldLastDate = data[data.length-1][0].getTime();
var oldFirstDate = data[0][0].getTime();
var clampRight = false;
var clampLeft = false;
if(dateWindow != null){
if(dateWindow[1] == oldLastDate){
clampRight=true;
}
// update date window to clamp series left
if(dateWindow[0] == oldFirstDate){
clampLeft=true;
}
}
// clear base data to visualize
data = [];
// submit all unit URL fetches simultaneously
Promise
.all(units.map(fetchStatisticData))
// then collect results
.then(function(resultSet){
// sort result array by their
/* ATTENTION: this assumes that the timeranges returned are not overlapping */
/*resultSet.sort(function(a, b) {
return units.indexOf(b) - units.indexOf(a);
});*/
// merge arrays into one
resultSet.forEach(function(resultObj){
data = data.concat(resultObj.arrayFragment)
});
console.log(data);
console.log("refreshing plot");
// prepare and initialize re-rendering on last fetched unit
// sort base data by time (FIXME: can this be avoided?)
data.sort(function(a, b){ return a[0] - b[0]; });
// clamp to edges and exchange base dataset on graph
if(dateWindow != null){
var currentLastDate = data[data.length-1][0].getTime();
var currentFirstDate = data[0][0].getTime();
clampedDateWindow = [];
var diffToLastRun = 0;
if(clampRight){
diffToLastRun = currentLastDate - dateWindow[1];
} else if(clampLeft){
diffToLastRun = currentFirstDate - dateWindow[0];
}
clampedDateWindow = [dateWindow[0]+diffToLastRun, dateWindow[1]+diffToLastRun]
g.updateOptions( { 'file': data,
dateWindow: clampedDateWindow
}
);
} else {
g.updateOptions( { 'file': data } );
}
})
.catch(function(e) {
if(!e.message.includes("Failed to fetch")){
console.log("A problem occurred: "+e.message);
if (!e.stack)
try {
// IE requires the Error to actually be thrown or else the
// Error's 'stack' property is undefined.
throw e;
} catch (e) {
if (!e.stack) {
//return 0; // IE < 10, likely
}
}
var stack = e.stack.toString().split(/\r\n|\n/);
msg = e.message;
if (msg === '') {
msg = '""';
}
console.log(msg, ' [' + stack[1] + ']');
}
});
}
plotRefresh();
window.intervalId = setInterval(function(){plotRefresh(userIsInteracting);}, 1000);
});
/* FIXME: on dragging, pause updates!! */
function parseBaseData(args) {
var json = args.json;
var unit = args.unit;
var arrayFragment = [];
var resolution = json.resolution;
var firstElementTime = json.time; // unix ts of first arr element
seriesLength = json.allframespersecond.length;
var currentElementTime = firstElementTime;
var timeIncrement = 1;
if(unit == "minutes"){
timeIncrement = 60;
} else if(unit == "hours"){
timeIncrement = 60*60;
}
for(var i=0; i<seriesLength; i++){
row = [new Date(currentElementTime * 1000)];
currentElementTime+=timeIncrement;
seriesKeys.forEach(function(key){
row.push(json[key][i]);
});
arrayFragment.push(row);
}
return arrayFragment;
}
</script>
</body>
</html>