Skip to content

Commit 901ec90

Browse files
graph performance improvements
* large sets are detected and only the last 3000 points are displayed * users can still zoomout to the entire graph via double clicking * a popup will warn users they are about to zoom out to the entire graph * nite overlay no longer snaps to valid data points * graph/marker clear when stopFollow() is issued
1 parent 84459be commit 901ec90

File tree

3 files changed

+67
-35
lines changed

3 files changed

+67
-35
lines changed

js/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ $(window).ready(function() {
421421
$("#telemetry_graph").on('mouseout','.holder', function() {
422422
nite.setDate(null);
423423
nite.refresh();
424+
if(polyMarker) polyMarker.setMap(null);
424425

425426
$("#timebox").removeClass('past').addClass('present');
426427
updateTimebox(new Date());

js/plot_config.js

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
11
// init plot
22
plot = $.plot(plot_holder, {}, plot_options);
33
var updateLegendTimeout = null;
4-
var latestPosition = null;
54
var polyMarker = null;
65

76
// updates legend with extrapolated values under the mouse position
8-
function updateLegend() {
7+
function updateLegend(pos) {
98
var legend = $(plot_holder + " .legendLabel");
109
$(plot_holder + " .legend table").css({'background-color':"rgba(255,255,255,0.9)","pointer-events":"none"});
1110
legend.each(function() {
1211
$(this).css({'padding-left':'3px'});
1312
});
1413

15-
updateLegendTimeout = null;
1614

17-
var pos = latestPosition;
15+
var i, j, ij, dataset = plot.getData();
16+
//var axes = plot.getAxes();
1817

19-
var axes = plot.getAxes();
20-
if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
21-
pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
22-
return;
23-
}
18+
if(dataset.length === 0) return;
2419

25-
var i, j, dataset = plot.getData();
20+
// this loop find the value for each series
21+
// and updates the legend
22+
//
23+
// here we don't snap to existing data point
2624
for (i = 0; i < dataset.length; ++i) {
2725

2826
var series = dataset[i];
@@ -34,6 +32,7 @@ function updateLegend() {
3432
break;
3533
}
3634
}
35+
if(i === 0) ij = j;
3736

3837
var y;
3938
if(series.noInterpolate > 0) { y = series.data[((j===0)?j:j-1)][1]; }
@@ -64,37 +63,32 @@ function updateLegend() {
6463
});
6564
}
6665

67-
if(dataset.length) {
68-
for (j = 0; j < dataset[0].data.length; ++j) {
69-
if (dataset[0].data[j][0] > pos.x) {
70-
break;
71-
}
72-
}
73-
}
74-
66+
// this loop finds an existing data point, so we can get coordinates
67+
// if the crosshair happens to be over null area, we snap to the previous data point
68+
//
69+
// to snap accurate to the corresponding LatLng, we need to count the number of null data points
70+
// then we remove them form the count and we get the index we need for the positions array
7571
if(follow_vehicle !== null && vehicles[follow_vehicle].positions.length) {
7672
// adjust index for null data points
7773
var null_count = 0;
7874
var data_ref = vehicles[follow_vehicle].graph_data[0];
7975

80-
if(j > data_ref.data.length / 2) {
81-
for(i = data_ref.data.length - 1; i > j; i--) null_count += (data_ref.data[i][1] === null) ? 1 : 0;
76+
if(ij > data_ref.data.length / 2) {
77+
for(i = data_ref.data.length - 1; i > ij; i--) null_count += (data_ref.data[i][1] === null) ? 1 : 0;
8278
null_count = data_ref.nulls - null_count * 2;
8379
} else {
84-
for(i = 0; i < j; i++) null_count += (data_ref.data[i][1] === null) ? 1 : 0;
80+
for(i = 0; i < ij; i++) null_count += (data_ref.data[i][1] === null) ? 1 : 0;
8581
null_count *= 2;
8682
}
8783

8884
// update position
89-
polyMarker.setPosition(vehicles[follow_vehicle].positions[j - null_count]);
85+
ij -= null_count + ((null_count===0||null_count===data_ref.nulls) ? 0 : 1);
86+
if(ij < 0) ij = 0;
87+
88+
polyMarker.setPosition(vehicles[follow_vehicle].positions[ij]);
9089

9190
// adjust nite overlay
92-
var date;
93-
try {
94-
date = new Date(data_ref.data[j][0]);
95-
} catch(e) {
96-
return;
97-
}
91+
var date = new Date(pos.x1);
9892

9993
nite.setDate(date);
10094
nite.refresh();
@@ -106,28 +100,45 @@ function updateLegend() {
106100

107101
// update legend values on mouse hover
108102
$(plot_holder).bind("plothover", function (event, pos, item) {
109-
latestPosition = pos;
110103
plot.lockCrosshair();
111104
plot.setCrosshair(pos);
112105
if (!updateLegendTimeout) {
113-
updateLegendTimeout = setTimeout(updateLegend, 40);
106+
updateLegend(pos);
107+
updateLegendTimeout = setTimeout(function() { updateLegendTimeout = null; }, 40);
114108
}
115109
});
116110

117111
// double click on the plot clears selection
118112
$(plot_holder).bind("dblclick", function () {
119-
if(plot_options.xaxis) delete plot_options.xaxis;
120-
plot = $.plot("#telemetry_graph .holder", plot.getData(), plot_options);
113+
if(!follow_vehicle) return;
114+
115+
if(plot_options.xaxis) {
116+
if(plot_options.xaxis.superzoom == 2) {
117+
delete plot_options.xaxis;
118+
}
119+
else {
120+
if(plot_options.xaxis.superzoom == 1) {
121+
if(!confirm("You are about to zoom out to the entire graph. It may hang your browser. Do you wish to continue?")) return;
122+
}
123+
plot_options.xaxis = {};
124+
}
125+
}
126+
127+
updateGraph(follow_vehicle);
121128
});
122129

123130
// limit range after selection
124131
$(plot_holder).bind("plotselected", function (event, ranges) {
125132
if(typeof ranges.xaxis == 'undefined') return;
126133

127-
plot = $.plot("#telemetry_graph .holder", plot.getData(), $.extend(true, plot_options, {
134+
if(plot_options.xaxis && plot_options.xaxis.superzoom) plot_options.xaxis.superzoom = 2;
135+
136+
$.extend(true, plot_options, {
128137
xaxis: {
129138
min: ranges.xaxis.from,
130139
max: ranges.xaxis.to
131140
}
132-
}));
141+
});
142+
143+
updateGraph(follow_vehicle);
133144
});

js/tracker.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ function stopFollow() {
653653
if(follow_vehicle in vehicles) vehicles[follow_vehicle].follow = false;
654654
follow_vehicle = null;
655655

656+
// clear graph
657+
plot = $.plot(plot_holder, {}, plot_options);
658+
656659
// reset nite overlay
657660
nite.setDate(null);
658661
nite.refresh();
@@ -1595,8 +1598,25 @@ function updateGraph(vcallsign, reset_selection) {
15951598
nite.refresh();
15961599
}
15971600

1601+
var series = vehicles[vcallsign].graph_data;
1602+
1603+
// if we are drawing the plot for the fisrt time
1604+
// and the dataset is too large, we set an initial selection of the last 7 days
1605+
if(!plot_options.hasOwnProperty('xaxis')) {
1606+
if(series.length && series[0].data.length > 4001) {
1607+
var end = series[0].data.length - 1;
1608+
1609+
plot_options.xaxis = {
1610+
superzoom: 1,
1611+
min: series[0].data[end-4000][0],
1612+
max: series[0].data[end][0],
1613+
};
1614+
1615+
}
1616+
}
1617+
15981618
// replot graph, with this vehicle data, and this vehicles yaxes config
1599-
plot = $.plot(plot_holder, vehicles[vcallsign].graph_data, $.extend(false, plot_options, {yaxes:vehicles[vcallsign].graph_yaxes}));
1619+
plot = $.plot(plot_holder, series, $.extend(false, plot_options, {yaxes:vehicles[vcallsign].graph_yaxes}));
16001620

16011621
vehicles[vcallsign].graph_data_updated = false;
16021622
}

0 commit comments

Comments
 (0)