fixed syncronization of dygraphs on zoom-out
Costa Tsaousis (ktsaou) committed
Dec 6, 2015 at 04:21 UTC
276065a13caf893ae1ca7b5da766058d073ab872
1 file changed
+201
-68
web/dashboard.js
+201
-68
@@ -99,7 +99,8 @@
99
idle_between_loops: 200,
100
idle_lost_focus: 500,
101
global_pan_sync_time: 500,
102
- fast_render_timeframe: 200 // render continously for these many ms
102
+ fast_render_timeframe: 200, // render continously for these many ms
103
+ sync_delay: 1500 // how much time after an operation to setup synced selections?
104
},
105
106
debug: {
@@ -271,6 +272,7 @@
272
validated: false, // boolean - has the chart been validated?
273
enabled: true, // boolean - is the chart enabled for refresh?
274
paused: false, // boolean - is the chart paused for any reason?
275
+ selected: false, // boolean - is the chart shown a selection?
276
debug: false,
277
updates_counter: 0, // numeric - the number of refreshes made so far
278
@@ -337,17 +339,33 @@
339
},
340
341
setSelection: function(t) {
340
- if(typeof this.library.setSelection == 'function')
341
- return this.library.setSelection(this, t);
342
- else
343
- return false;
342
+ if(typeof this.library.setSelection == 'function') {
343
+ if(this.library.setSelection(this, t))
344
+ this.selected = true;
345
+ else
346
+ this.selected = false;
347
+ }
348
+ else this.selected = true;
349
+
350
+ if(this.selected && this.debug) this.log('selection set to ' + t.toString());
351
+
352
+ return this.selected;
353
},
354
355
clearSelection: function() {
347
- if(typeof this.library.clearSelection == 'function')
348
- return this.library.clearSelection(this);
349
- else
350
- return false;
356
+ if(this.selected) {
357
+ if(typeof this.library.clearSelection == 'function') {
358
+ if(this.library.clearSelection(this))
359
+ this.selected = false;
360
+ else
361
+ this.selected = true;
362
+ }
363
+ else this.selected = false;
364
+
365
+ if(!this.selected && this.debug) this.log('selection cleared');
366
+ }
367
+
368
+ return this.selected;
369
},
370
371
timeIsVisible: function(t) {
@@ -366,11 +384,17 @@
384
},
385
386
pauseChart: function() {
369
- this.paused = true;
387
+ if(!this.paused) {
388
+ if(this.debug) this.log('paused');
389
+ this.paused = true;
390
+ }
391
},
392
393
unpauseChart: function() {
373
- this.paused = false;
394
+ if(this.paused) {
395
+ if(this.debug) this.log('unpaused');
396
+ this.paused = false;
397
+ }
398
},
399
400
resetChart: function() {
@@ -385,6 +409,7 @@
409
this.mode.last_updated_ms = 0;
410
this.follows_global = 0;
411
this.paused = false;
412
+ this.selected = false;
413
this.enabled = true;
414
this.debug = false;
415
@@ -674,27 +699,44 @@
699
var now = new Date().getTime();
700
701
if(this.updates_counter && !NETDATA.options.page_is_visible) {
677
- if(NETDATA.options.debug.focus || this.debug) this.log('page does not have focus');
702
+ if(NETDATA.options.debug.focus || this.debug) this.log('canBeAutoRefreshed(): page does not have focus');
703
return false;
704
}
705
706
if(!auto_refresher) return true;
707
683
- if(!self.visible(true)) return false;
708
+ if(!self.visible(true)) {
709
+ if(this.debug) this.log('canBeAutoRefreshed(): I am not visible.');
710
+ return false;
711
+ }
712
713
// options valid only for autoRefresh()
714
if(NETDATA.options.auto_refresher_stop_until == 0 || NETDATA.options.auto_refresher_stop_until < now) {
715
if(NETDATA.globalPanAndZoom.state) {
688
- if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this))
716
+ if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) {
717
+ if(this.debug) this.log('canBeAutoRefreshed(): global panning: I need an update.');
718
return true;
690
- else
719
+ }
720
+ else {
721
+ if(this.debug) this.log('canBeAutoRefreshed(): global panning: I am already up to date.');
722
return false;
723
+ }
724
}
725
694
- if(this.paused) return false;
726
+ if(this.selected) {
727
+ if(this.debug) this.log('canBeAutoRefreshed(): I have a selection in place.');
728
+ return false;
729
+ }
730
696
- if(now - this.mode.last_updated_ms > this.mode.view_update_every)
731
+ if(this.paused) {
732
+ if(this.debug) this.log('canBeAutoRefreshed(): I am paused.');
733
+ return false;
734
+ }
735
+
736
+ if(now - this.mode.last_updated_ms > this.mode.view_update_every) {
737
+ if(this.debug) this.log('canBeAutoRefreshed(): It is time to update me.');
738
return true;
739
+ }
740
}
741
}
742
@@ -1163,50 +1205,96 @@
1205
// dygraph
1206
1207
NETDATA.dygraph = {
1208
+ state: null,
1209
sync: false,
1167
- paused: []
1210
+ dont_sync_before: 0,
1211
+ slaves: []
1212
};
1213
1214
NETDATA.dygraph.syncStart = function(state, event, x, points, row, seriesName) {
1171
- if(NETDATA.options.debug.dygraph || state.debug) console.log('dygraph.syncStart()');
1172
- state.pauseChart();
1215
+ if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStart()');
1216
+
1217
+ //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
1218
+ // state.log('sync: I am not the sync master.');
1219
+ // return;
1220
+ //}
1221
+ // state.debug = true;
1222
+
1223
+ var t = state.mode.after_ms + row * state.mode.view_update_every;
1224
+ // console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t == x)?'SAME':'DIFFERENT'));
1225
+
1226
+ now = new Date().getTime();
1227
+ if(now < NETDATA.dygraph.dont_sync_before) {
1228
+ if(state.debug) st.log('sync: cannot sync yet.');
1229
+ return;
1230
+ }
1231
+
1232
+ // since we are the sync master, we should not call state.setSelection()
1233
+ // dygraphs is taking care of visualizing our selection.
1234
+ state.selected = true;
1235
1236
var dygraph = state.dygraph_instance;
1237
1238
if(!NETDATA.dygraph.sync) {
1239
+ if(state.debug) st.log('sync: setting up...');
1240
$.each(NETDATA.options.targets, function(i, target) {
1241
var st = NETDATA.chartState(target);
1179
- if(typeof st.dygraph_instance == 'object' && st.library_name == state.library_name && st.canBeAutoRefreshed(false)) {
1180
- NETDATA.dygraph.paused.push(st);
1242
+ if(st == state) {
1243
+ if(state.debug) st.log('sync: not adding me to sync');
1244
+ }
1245
+ else {
1246
+ if(typeof st.dygraph_instance == 'object' && st.library_name == state.library_name && st.canBeAutoRefreshed(false)) {
1247
+ NETDATA.dygraph.slaves.push(st);
1248
+ if(state.debug) st.log('sync: added slave to sync');
1249
+ }
1250
}
1251
});
1252
+ NETDATA.dygraph.sync = true;
1253
}
1254
1185
- $.each(NETDATA.dygraph.paused, function(i, st) {
1186
- st.setSelection(x);
1255
+ $.each(NETDATA.dygraph.slaves, function(i, st) {
1256
+ if(st == state) {
1257
+ if(state.debug) st.log('sync: ignoring me from set selection');
1258
+ }
1259
+ else {
1260
+ if(state.debug) st.log('sync: showing master selection');
1261
+ st.setSelection(t);
1262
+ }
1263
});
1188
-
1264
}
1265
1266
NETDATA.dygraph.syncStop = function(state) {
1192
- if(NETDATA.options.debug.dygraph || state.debug) console.log('dygraph.syncStop()');
1193
-
1194
- if(!NETDATA.dygraph.sync) {
1195
- $.each(NETDATA.dygraph.paused, function(i, st) {
1196
- st.clearSelection();
1267
+ if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStop()');
1268
+
1269
+ //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
1270
+ // state.log('sync: I am not the sync master.');
1271
+ // return;
1272
+ //}
1273
+
1274
+ if(NETDATA.dygraph.sync) {
1275
+ if(state.debug) st.log('sync: cleaning up...');
1276
+ $.each(NETDATA.dygraph.slaves, function(i, st) {
1277
+ if(st == state) {
1278
+ if(state.debug) st.log('sync: not adding me to sync stop');
1279
+ }
1280
+ else {
1281
+ if(state.debug) st.log('sync: removed slave from sync');
1282
+ st.clearSelection();
1283
+ }
1284
});
1285
1286
+ NETDATA.dygraph.slaves = [];
1287
NETDATA.dygraph.sync = false;
1200
- NETDATA.dygraph.paused = [];
1288
}
1289
1203
- state.unpauseChart();
1290
+ // since we are the sync master, we should not call state.clearSelection()
1291
+ // dygraphs is taking care of visualizing our selection.
1292
+ state.selected = false;
1293
}
1294
1206
- NETDATA.dygraph.resetChart = function(element, dygraph) {
1207
- if(NETDATA.options.debug.dygraph) console.log('dygraph.resetChart()');
1295
+ NETDATA.dygraph.resetChart = function(state, dygraph, context) {
1296
+ if(NETDATA.options.debug.dygraph) state.log('dygraph.resetChart()');
1297
1209
- state = NETDATA.chartState(element);
1298
state.resetChart();
1299
if(NETDATA.globalPanAndZoom.clearMaster());
1300
}
@@ -1220,20 +1308,24 @@
1308
}
1309
1310
NETDATA.dygraphSetSelection = function(state, t) {
1223
- var r = state.calculateRowForTime(t);
1224
- if(r != -1) {
1225
- state.dygraph_instance.setSelection(r);
1226
- state.pauseChart();
1227
- }
1228
- else {
1229
- state.dygraph_instance.clearSelection();
1230
- state.unpauseChart();
1311
+ if(typeof state.dygraph_instance != 'undefined') {
1312
+ var r = state.calculateRowForTime(t);
1313
+ if(r != -1) {
1314
+ state.dygraph_instance.setSelection(r);
1315
+ return true;
1316
+ }
1317
+ else {
1318
+ state.dygraph_instance.clearSelection();
1319
+ return false;
1320
+ }
1321
}
1322
}
1323
1234
- NETDATA.dygraphclearSelection = function(state, t) {
1235
- state.dygraph_instance.clearSelection();
1236
- state.unpauseChart();
1324
+ NETDATA.dygraphClearSelection = function(state, t) {
1325
+ if(typeof state.dygraph_instance != 'undefined') {
1326
+ state.dygraph_instance.clearSelection();
1327
+ }
1328
+ return true;
1329
}
1330
1331
NETDATA.dygraphInitialize = function(callback) {
@@ -1400,7 +1492,7 @@
1492
},
1493
drawCallback: function(dygraph, is_initial) {
1494
if(data.state.mode.name != 'auto') {
1403
- if(NETDATA.options.debug.dygraph) console.log('dygraphDrawCallback()');
1495
+ if(NETDATA.options.debug.dygraph) data.state.log('dygraphDrawCallback()');
1496
1497
var x_range = dygraph.xAxisRange();
1498
var after = Math.round(x_range[0]);
@@ -1410,65 +1502,100 @@
1502
}
1503
},
1504
zoomCallback: function(minDate, maxDate, yRanges) {
1413
- if(NETDATA.options.debug.dygraph) console.log('dygraphZoomCallback()');
1505
+ if(NETDATA.options.debug.dygraph) data.state.log('dygraphZoomCallback()');
1506
+ NETDATA.dygraph.syncStop(data.state);
1507
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1508
NETDATA.dygraph.zoomOrPan(element, this, minDate, maxDate);
1509
},
1510
highlightCallback: function(event, x, points, row, seriesName) {
1417
- if(NETDATA.options.debug.dygraph) console.log('dygraphHighlightCallback()');
1511
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('dygraphHighlightCallback()');
1512
+ data.state.pauseChart();
1513
NETDATA.dygraph.syncStart(data.state, event, x, points, row, seriesName);
1514
},
1515
unhighlightCallback: function(event) {
1421
- if(NETDATA.options.debug.dygraph) console.log('dygraphUnhighlightCallback()');
1516
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('dygraphUnhighlightCallback()');
1517
+ data.state.unpauseChart();
1518
NETDATA.dygraph.syncStop(data.state);
1519
},
1520
interactionModel : {
1521
mousedown: function(event, dygraph, context) {
1426
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseDown()');
1522
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousedown()');
1523
+ NETDATA.dygraph.syncStop(data.state);
1524
+
1525
+ if(NETDATA.options.debug.dygraph) data.state.log('dygraphMouseDown()');
1526
1527
// Right-click should not initiate a zoom.
1429
- if (event.button && event.button == 2) return;
1528
+ if(event.button && event.button == 2) return;
1529
1530
context.initializeMouseDown(event, dygraph, context);
1531
1433
- if (event.altKey || event.shiftKey) {
1434
- data.state.setMode('zoom');
1435
- Dygraph.startZoom(event, dygraph, context);
1532
+ if(event.button && event.button == 1) {
1533
+ if (event.altKey || event.shiftKey) {
1534
+ data.state.setMode('pan');
1535
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1536
+ Dygraph.startPan(event, dygraph, context);
1537
+ }
1538
+ else {
1539
+ data.state.setMode('zoom');
1540
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1541
+ Dygraph.startZoom(event, dygraph, context);
1542
+ }
1543
}
1544
else {
1438
- data.state.setMode('pan');
1439
- Dygraph.startPan(event, dygraph, context);
1545
+ if (event.altKey || event.shiftKey) {
1546
+ data.state.setMode('zoom');
1547
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1548
+ Dygraph.startZoom(event, dygraph, context);
1549
+ }
1550
+ else {
1551
+ data.state.setMode('pan');
1552
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1553
+ Dygraph.startPan(event, dygraph, context);
1554
+ }
1555
}
1556
},
1557
mousemove: function(event, dygraph, context) {
1443
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseMove()');
1558
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousemove()');
1559
1445
- if (context.isPanning) {
1560
+ if(context.isPanning) {
1561
+ NETDATA.dygraph.syncStop(data.state);
1562
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1563
data.state.setMode('pan');
1564
Dygraph.movePan(event, dygraph, context);
1565
}
1449
- else if (context.isZooming) {
1566
+ else if(context.isZooming) {
1567
+ NETDATA.dygraph.syncStop(data.state);
1568
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1569
data.state.setMode('zoom');
1570
Dygraph.moveZoom(event, dygraph, context);
1571
}
1572
},
1573
mouseup: function(event, dygraph, context) {
1455
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseUp()');
1574
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mouseup()');
1575
1457
- if (context.isPanning)
1576
+ if (context.isPanning) {
1577
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1578
Dygraph.endPan(event, dygraph, context);
1459
- else if (context.isZooming)
1579
+ }
1580
+ else if (context.isZooming) {
1581
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1582
Dygraph.endZoom(event, dygraph, context);
1583
+ }
1584
},
1585
click: function(event, dygraph, context) {
1463
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseClick()');
1586
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.click()');
1587
Dygraph.cancelEvent(event);
1588
},
1589
dblclick: function(event, dygraph, context) {
1467
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseDoubleClick()');
1468
- NETDATA.dygraph.resetChart(element, dygraph);
1590
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.dblclick()');
1591
+ NETDATA.dygraph.syncStop(data.state);
1592
+ NETDATA.dygraph.resetChart(data.state, dygraph, context);
1593
},
1594
mousewheel: function(event, dygraph, context) {
1471
- if(NETDATA.options.debug.dygraph) console.log('dygraphMouseWheel()');
1595
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousewheel()');
1596
+
1597
+ NETDATA.dygraph.syncStop(data.state);
1598
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1599
1600
if(event.altKey || event.shiftKey) {
1601
// http://dygraphs.com/gallery/interaction-api.js
@@ -1485,22 +1612,28 @@
1612
var before = before_old - dt;
1613
var after = after_old + dt;
1614
1488
- if(NETDATA.options.debug.dygraph) console.log('percent: ' + percentage + ' from ' + after_old + ' - ' + before_old + ' to ' + after + ' - ' + before + ', range from ' + (before_old - after_old).toString() + ' to ' + (before - after).toString());
1615
+ if(NETDATA.options.debug.dygraph) data.state.log('percent: ' + percentage + ' from ' + after_old + ' - ' + before_old + ' to ' + after + ' - ' + before + ', range from ' + (before_old - after_old).toString() + ' to ' + (before - after).toString());
1616
1617
data.state.setMode('zoom');
1618
NETDATA.dygraph.zoomOrPan(element, dygraph, after, before);
1619
}
1620
},
1621
touchstart: function(event, dygraph, context) {
1622
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchstart()');
1623
+ NETDATA.dygraph.syncStop(data.state);
1624
+ NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1625
Dygraph.Interaction.startTouch(event, dygraph, context);
1626
context.touchDirections = { x: true, y: false };
1627
data.state.setMode('zoom');
1628
},
1629
touchmove: function(event, dygraph, context) {
1630
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchmove()');
1631
//Dygraph.cancelEvent(event);
1632
+ NETDATA.dygraph.syncStop(data.state);
1633
Dygraph.Interaction.moveTouch(event, dygraph, context);
1634
},
1635
touchend: function(event, dygraph, context) {
1636
+ if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchend()');
1637
Dygraph.Interaction.endTouch(event, dygraph, context);
1638
}
1639
}