global selection sync moved as a common feature to all charts libraries; converted the state object to use javascript constructors and prototypes as it should
Costa Tsaousis (ktsaou) committed
Dec 11, 2015 at 01:00 UTC
a91d910edf2e8eda14c9567b88d11efecfd725c4
1 file changed
+773
-757
web/dashboard.js
+773
-757
@@ -356,10 +356,10 @@
356
// ----------------------------------------------------------------------------------------------------------------
357
// Our state object, where all per-chart values are stored
358
359
- NETDATA.chartInitialState = function(element) {
359
+ chartState = function(element) {
360
self = $(element);
361
362
- var state = {
362
+ Object.assign(this, {
363
uuid: NETDATA.guid(), // GUID - a unique identifier for the chart
364
id: self.data('netdata'), // string - the name of chart
365
@@ -472,789 +472,898 @@
472
473
refresh_dt_ms: 0, // milliseconds - the time the last refresh took
474
refresh_dt_element_name: self.data('dt-element-name') || null, // string - the element to print refresh_dt_ms
475
- refresh_dt_element: null,
475
+ refresh_dt_element: null
476
+ });
477
+ }
478
477
- log: function(msg) {
478
- console.log(this.id + ' (' + this.library_name + ' ' + this.uuid + '): ' + msg);
479
- },
479
+ // ----------------------------------------------------------------------------------------------------------------
480
+ // global selection sync
481
481
- delaySelectionSync: function() {
482
- NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
483
- },
482
+ NETDATA.globalSelectionSync = {
483
+ state: null,
484
+ dont_sync_before: 0,
485
+ slaves: []
486
+ };
487
485
- setSelection: function(t) {
486
- if(typeof this.library.setSelection == 'function') {
487
- if(this.library.setSelection(this, t))
488
- this.selected = true;
489
- else
490
- this.selected = false;
491
- }
492
- else this.selected = true;
488
+ // prevent to global selection sync for some time
489
+ chartState.prototype.globalSelectionSyncDelay = function() {
490
+ if(!NETDATA.options.current.sync_selection) return;
491
+ NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
492
+ }
493
494
- if(this.selected && this.debug) this.log('selection set to ' + t.toString());
494
+ // can we globally apply selection sync?
495
+ chartState.prototype.globalSelectionSyncAbility = function() {
496
+ if(!NETDATA.options.current.sync_selection) return false;
497
+ if(NETDATA.globalSelectionSync.dont_sync_before > new Date().getTime()) return false;
498
+ return true;
499
+ }
500
496
- return this.selected;
497
- },
501
+ // this chart is the master of the global selection sync
502
+ chartState.prototype.globalSelectionSyncBeMaster = function() {
503
+ // am I the master?
504
+ if(NETDATA.globalSelectionSync.state == this) {
505
+ if(this.debug) this.log('sync: I am the master already.');
506
+ return;
507
+ }
508
499
- clearSelection: function() {
500
- if(this.selected) {
501
- if(typeof this.library.clearSelection == 'function') {
502
- if(this.library.clearSelection(this))
503
- this.selected = false;
504
- else
505
- this.selected = true;
506
- }
507
- else this.selected = false;
508
-
509
- if(!this.selected && this.debug) this.log('selection cleared');
510
- }
509
+ if(NETDATA.globalSelectionSync.state) {
510
+ if(this.debug) this.log('sync: I am not the sync master. Resetting global sync.');
511
+ this.globalSelectionSyncStop();
512
+ }
513
512
- return this.selected;
513
- },
514
+ // become the master
515
+ if(this.debug) this.log('sync: becoming sync master.');
516
+ this.selected = true;
517
+ NETDATA.globalSelectionSync.state = this;
518
515
- // find if a timestamp (ms) is shown in the current chart
516
- timeIsVisible: function(t) {
517
- if(t >= this.current.after_ms && t <= this.current.before_ms)
518
- return true;
519
- return false;
520
- },
519
+ // find the all slaves
520
+ var self = this;
521
+ $.each(NETDATA.options.targets, function(i, target) {
522
+ var st = NETDATA.chartState(target);
523
+ if(st == self) {
524
+ if(self.debug) st.log('sync: not adding me to sync');
525
+ }
526
+ else if(st.globalSelectionSyncIsEligible()) {
527
+ if(self.debug) st.log('sync: adding to sync as slave');
528
+ st.globalSelectionSyncBeSlave();
529
+ }
530
+ });
531
+ }
532
522
- calculateRowForTime: function(t) {
523
- if(!this.timeIsVisible(t)) return -1;
524
- return Math.floor((t - this.current.after_ms) / this.current.view_update_every);
525
- },
533
+ // can the chart participate to the global selection sync as a slave?
534
+ chartState.prototype.globalSelectionSyncIsEligible = function() {
535
+ if(this.library != null && typeof this.library.setSelection == 'function' && this.isVisible())
536
+ return true;
537
+ return false;
538
+ }
539
527
- pauseChart: function() {
528
- if(!this.paused) {
529
- if(this.debug) this.log('paused');
530
- this.paused = true;
531
- }
532
- },
540
+ // this chart is a slave of the global selection sync
541
+ chartState.prototype.globalSelectionSyncBeSlave = function() {
542
+ if(NETDATA.globalSelectionSync.state != this)
543
+ NETDATA.globalSelectionSync.slaves.push(this);
544
+ }
545
534
- unpauseChart: function() {
535
- if(this.paused) {
536
- if(this.debug) this.log('unpaused');
537
- this.paused = false;
546
+ // sync all the visible charts to the given time
547
+ // this is to be called from the chart libraries
548
+ chartState.prototype.globalSelectionSync = function(t) {
549
+ if(!this.globalSelectionSyncAbility()) {
550
+ if(this.debug) this.log('sync: cannot sync (yet?).');
551
+ return;
552
+ }
553
+
554
+ if(this.debug) this.log('sync: trying to be sync master.');
555
+ this.globalSelectionSyncBeMaster();
556
+
557
+ var self = this;
558
+ $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
559
+ if(st == self) {
560
+ // since we are the sync master, we should not call state.setSelection()
561
+ // the chart library is taking care of visualizing our selection.
562
+ if(self.debug) st.log('sync: ignoring me from set selection');
563
+ }
564
+ else {
565
+ if(self.debug) st.log('sync: showing master selection');
566
+ st.setSelection(t);
567
+ }
568
+ });
569
+ }
570
+
571
+ // stop syncing all charts to the given time
572
+ chartState.prototype.globalSelectionSyncStop = function() {
573
+ if(NETDATA.globalSelectionSync.slaves.length) {
574
+ if(this.debug) this.log('sync: cleaning up...');
575
+ var self = this;
576
+ $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
577
+ if(st == self) {
578
+ if(self.debug) st.log('sync: not adding me to sync stop');
579
}
539
- },
580
+ else {
581
+ if(self.debug) st.log('sync: removed slave from sync');
582
+ st.clearSelection();
583
+ }
584
+ });
585
541
- resetChart: function() {
542
- NETDATA.globalPanAndZoom.clearMaster();
543
- this.follows_global = 0;
586
+ NETDATA.globalSelectionSync.slaves = [];
587
+ NETDATA.globalSelectionSync.state = null;
588
+ }
589
545
- this.clearSelection();
590
+ // since we are the sync master, we should not call this.clearSelection()
591
+ // dygraphs is taking care of visualizing our selection.
592
+ this.selected = false;
593
+ }
594
547
- this.setMode('auto');
548
- this.current.force_before_ms = null;
549
- this.current.force_after_ms = null;
550
- this.current.last_autorefreshed = 0;
551
- this.paused = false;
595
+ chartState.prototype.setSelection = function(t) {
596
+ if(typeof this.library.setSelection == 'function') {
597
+ if(this.library.setSelection(this, t))
598
+ this.selected = true;
599
+ else
600
this.selected = false;
553
- this.enabled = true;
554
- this.debug = false;
555
-
556
- // do not update the chart here
557
- // or the chart will flip-flop when it is the master
558
- // of a selection sync and another chart becomes
559
- // the new master
560
- if(!NETDATA.options.current.sync_pan_and_zoom)
561
- state.updateChart();
562
- },
601
+ }
602
+ else this.selected = true;
603
564
- setMode: function(m) {
565
- if(this.current) {
566
- if(this.current.name == m) return;
567
-
568
- this[m].url = this.current.url;
569
- this[m].last_autorefreshed = this.current.last_autorefreshed;
570
- this[m].view_update_every = this.current.view_update_every;
571
- this[m].after_ms = this.current.after_ms;
572
- this[m].before_ms = this.current.before_ms;
573
- this[m].points = this.current.points;
574
- this[m].data = this.current.data;
575
- this[m].requested_before_ms = this.current.requested_before_ms;
576
- this[m].requested_after_ms = this.current.requested_after_ms;
577
- this[m].first_entry_ms = this.current.first_entry_ms;
578
- this[m].last_entry_ms = this.current.last_entry_ms;
579
- }
604
+ if(this.selected && this.debug) this.log('selection set to ' + t.toString());
605
+
606
+ return this.selected;
607
+ }
608
581
- if(m == 'auto')
582
- this.current = this.auto;
583
- else if(m == 'pan')
584
- this.current = this.pan;
585
- else if(m == 'zoom')
586
- this.current = this.zoom;
609
+ chartState.prototype.clearSelection = function() {
610
+ if(this.selected) {
611
+ if(typeof this.library.clearSelection == 'function') {
612
+ if(this.library.clearSelection(this))
613
+ this.selected = false;
614
else
588
- this.current = this.auto;
615
+ this.selected = true;
616
+ }
617
+ else this.selected = false;
618
+
619
+ if(!this.selected && this.debug) this.log('selection cleared');
620
+ }
621
590
- this.current.force_before_ms = null;
591
- this.current.force_after_ms = null;
622
+ return this.selected;
623
+ }
624
593
- if(this.debug) this.log('mode set to ' + this.current.name);
594
- },
625
+ // find if a timestamp (ms) is shown in the current chart
626
+ chartState.prototype.timeIsVisible = function(t) {
627
+ if(t >= this.current.after_ms && t <= this.current.before_ms)
628
+ return true;
629
+ return false;
630
+ },
631
596
- _minPanOrZoomStep: function() {
597
- return (((this.current.before_ms - this.current.after_ms) / this.current.points) * ((this.current.points * 5 / 100) + 1) );
598
- // return this.current.view_update_every * 10;
599
- },
632
+ chartState.prototype.calculateRowForTime = function(t) {
633
+ if(!this.timeIsVisible(t)) return -1;
634
+ return Math.floor((t - this.current.after_ms) / this.current.view_update_every);
635
+ }
636
601
- _shouldBeMoved: function(old_after, old_before, new_after, new_before) {
602
- var dt_after = Math.abs(old_after - new_after);
603
- var dt_before = Math.abs(old_before - new_before);
604
- var old_range = old_before - old_after;
637
+ // ----------------------------------------------------------------------------------------------------------------
638
606
- var new_range = new_before - new_after;
607
- var dt = Math.abs(old_range - new_range);
608
- var step = Math.max(dt_after, dt_before, dt);
639
+ // console logging
640
+ chartState.prototype.log = function(msg) {
641
+ console.log(this.id + ' (' + this.library_name + ' ' + this.uuid + '): ' + msg);
642
+ }
643
610
- var min_step = this._minPanOrZoomStep();
611
- if(new_range < old_range && new_range / this.chartWidth() < 100) {
612
- if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum point size: 0.10, wanted point size: ' + (new_range / this.chartWidth() / 1000).toString() + ': TOO SMALL RANGE');
613
- return false;
614
- }
644
+ chartState.prototype.pauseChart = function() {
645
+ if(!this.paused) {
646
+ if(this.debug) this.log('paused');
647
+ this.paused = true;
648
+ }
649
+ }
650
616
- if(step >= min_step) {
617
- if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum step: ' + (min_step / 1000).toString() + ', this step: ' + (step / 1000).toString() + ': YES');
618
- return true;
619
- }
620
- else {
621
- if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum step: ' + (min_step / 1000).toString() + ', this step: ' + (step / 1000).toString() + ': NO');
622
- return false;
623
- }
624
- },
651
+ chartState.prototype.unpauseChart = function() {
652
+ if(this.paused) {
653
+ if(this.debug) this.log('unpaused');
654
+ this.paused = false;
655
+ }
656
+ }
657
626
- updateChartPanOrZoom: function(after, before, callback) {
627
- var move = false;
658
+ chartState.prototype.resetChart = function() {
659
+ NETDATA.globalPanAndZoom.clearMaster();
660
+ this.follows_global = 0;
661
+
662
+ this.clearSelection();
663
+
664
+ this.setMode('auto');
665
+ this.current.force_before_ms = null;
666
+ this.current.force_after_ms = null;
667
+ this.current.last_autorefreshed = 0;
668
+ this.paused = false;
669
+ this.selected = false;
670
+ this.enabled = true;
671
+ this.debug = false;
672
+
673
+ // do not update the chart here
674
+ // or the chart will flip-flop when it is the master
675
+ // of a selection sync and another chart becomes
676
+ // the new master
677
+ if(!NETDATA.options.current.sync_pan_and_zoom)
678
+ state.updateChart();
679
+ }
680
629
- if(this.current.name == 'auto') {
630
- if(this.debug) this.log('updateChartPanOrZoom(): caller did not set proper mode');
631
- this.setMode('pan');
632
- }
681
+ chartState.prototype.setMode = function(m) {
682
+ if(this.current) {
683
+ if(this.current.name == m) return;
684
+
685
+ this[m].url = this.current.url;
686
+ this[m].last_autorefreshed = this.current.last_autorefreshed;
687
+ this[m].view_update_every = this.current.view_update_every;
688
+ this[m].after_ms = this.current.after_ms;
689
+ this[m].before_ms = this.current.before_ms;
690
+ this[m].points = this.current.points;
691
+ this[m].data = this.current.data;
692
+ this[m].requested_before_ms = this.current.requested_before_ms;
693
+ this[m].requested_after_ms = this.current.requested_after_ms;
694
+ this[m].first_entry_ms = this.current.first_entry_ms;
695
+ this[m].last_entry_ms = this.current.last_entry_ms;
696
+ }
697
634
- if(!this.current.force_after_ms || !this.current.force_before_ms) {
635
- if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): INIT');
636
- move = true;
637
- }
638
- else if(this._shouldBeMoved(this.current.force_after_ms, this.current.force_before_ms, after, before) && this._shouldBeMoved(this.current.after_ms, this.current.before_ms, after, before)) {
639
- if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): FORCE CHANGE from ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
640
- move = true;
641
- }
642
- else if(this._shouldBeMoved(this.current.requested_after_ms, this.current.requested_before_ms, after, before) && this._shouldBeMoved(this.current.after_ms, this.current.before_ms, after, before)) {
643
- if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): REQUESTED CHANGE from ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
644
- move = true;
645
- }
698
+ if(m == 'auto')
699
+ this.current = this.auto;
700
+ else if(m == 'pan')
701
+ this.current = this.pan;
702
+ else if(m == 'zoom')
703
+ this.current = this.zoom;
704
+ else
705
+ this.current = this.auto;
706
647
- if(move) {
648
- var now = new Date().getTime();
649
- NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.global_pan_sync_time;
650
- NETDATA.globalPanAndZoom.setMaster(this, after, before);
707
+ this.current.force_before_ms = null;
708
+ this.current.force_after_ms = null;
709
652
- this.current.force_after_ms = after;
653
- this.current.force_before_ms = before;
654
- this.updateChart(callback);
655
- return true;
656
- }
710
+ if(this.debug) this.log('mode set to ' + this.current.name);
711
+ }
712
658
- if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): IGNORE');
659
- if(typeof callback != 'undefined') callback();
660
- return false;
661
- },
713
+ chartState.prototype._minPanOrZoomStep = function() {
714
+ return (((this.current.before_ms - this.current.after_ms) / this.current.points) * ((this.current.points * 5 / 100) + 1) );
715
+ // return this.current.view_update_every * 10;
716
+ }
717
663
- updateLegendDOM: function() {
664
- if(!this.hasLegend()) return;
718
+ chartState.prototype._shouldBeMoved = function(old_after, old_before, new_after, new_before) {
719
+ var dt_after = Math.abs(old_after - new_after);
720
+ var dt_before = Math.abs(old_before - new_before);
721
+ var old_range = old_before - old_after;
722
666
- var needed = false;
723
+ var new_range = new_before - new_after;
724
+ var dt = Math.abs(old_range - new_range);
725
+ var step = Math.max(dt_after, dt_before, dt);
726
668
- // check that the legend DOM is up to date for the downloaded dimensions
669
- if(typeof this.element_legend_childs.series != 'object')
670
- needed = true;
671
- else if(!this.current.data)
672
- needed = true;
673
- else {
674
- for(var i = 0; i < this.current.data.dimension_names.length; i++) {
675
- if(typeof this.element_legend_childs.series[this.current.data.dimension_names[i]] == 'undefined') {
676
- needed = true;
677
- break;
678
- }
679
- else if(!this.follows_global) {
680
- // FIXME update to latest value
681
- ;
682
- }
683
- }
684
- }
727
+ var min_step = this._minPanOrZoomStep();
728
+ if(new_range < old_range && new_range / this.chartWidth() < 100) {
729
+ if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum point size: 0.10, wanted point size: ' + (new_range / this.chartWidth() / 1000).toString() + ': TOO SMALL RANGE');
730
+ return false;
731
+ }
732
686
- if(!needed) return;
733
+ if(step >= min_step) {
734
+ if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum step: ' + (min_step / 1000).toString() + ', this step: ' + (step / 1000).toString() + ': YES');
735
+ return true;
736
+ }
737
+ else {
738
+ if(this.debug) this.log('_shouldBeMoved(' + (new_after / 1000).toString() + ' - ' + (new_before / 1000).toString() + '): minimum step: ' + (min_step / 1000).toString() + ', this step: ' + (step / 1000).toString() + ': NO');
739
+ return false;
740
+ }
741
+ }
742
688
- if(this.debug) this.log('updating Legend DOM');
743
+ chartState.prototype.updateChartPanOrZoom = function(after, before, callback) {
744
+ var move = false;
745
690
- this.element_legend_childs = {
691
- title_date: document.createElement('span'),
692
- title_time: document.createElement('span'),
693
- title_units: document.createElement('span'),
694
- series: {}
695
- };
746
+ if(this.current.name == 'auto') {
747
+ if(this.debug) this.log('updateChartPanOrZoom(): caller did not set proper mode');
748
+ this.setMode('pan');
749
+ }
750
697
- this.element_legend_childs.title_date.className += "netdata-legend-title-date";
698
- this.element_legend.appendChild(this.element_legend_childs.title_date);
751
+ if(!this.current.force_after_ms || !this.current.force_before_ms) {
752
+ if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): INIT');
753
+ move = true;
754
+ }
755
+ else if(this._shouldBeMoved(this.current.force_after_ms, this.current.force_before_ms, after, before) && this._shouldBeMoved(this.current.after_ms, this.current.before_ms, after, before)) {
756
+ if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): FORCE CHANGE from ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
757
+ move = true;
758
+ }
759
+ else if(this._shouldBeMoved(this.current.requested_after_ms, this.current.requested_before_ms, after, before) && this._shouldBeMoved(this.current.after_ms, this.current.before_ms, after, before)) {
760
+ if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): REQUESTED CHANGE from ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
761
+ move = true;
762
+ }
763
700
- this.element_legend.appendChild(document.createElement('br'));
764
+ if(move) {
765
+ var now = new Date().getTime();
766
+ NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.global_pan_sync_time;
767
+ NETDATA.globalPanAndZoom.setMaster(this, after, before);
768
702
- this.element_legend_childs.title_time.className += "netdata-legend-title-time";
703
- this.element_legend.appendChild(this.element_legend_childs.title_time);
769
+ this.current.force_after_ms = after;
770
+ this.current.force_before_ms = before;
771
+ this.updateChart(callback);
772
+ return true;
773
+ }
774
705
- this.element_legend.appendChild(document.createElement('br'));
775
+ if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): IGNORE');
776
+ if(typeof callback != 'undefined') callback();
777
+ return false;
778
+ }
779
707
- this.element_legend_childs.title_units.className += "netdata-legend-title-units";
708
- this.element_legend.appendChild(this.element_legend_childs.title_units);
780
+ chartState.prototype.updateLegendDOM = function() {
781
+ if(!this.hasLegend()) return;
782
710
- this.element_legend.appendChild(document.createElement('br'));
783
+ var needed = false;
784
712
- var el = document.createElement('div');
713
- el.className += "netdata-legend-series";
714
- this.element_legend.appendChild(el);
785
+ // check that the legend DOM is up to date for the downloaded dimensions
786
+ if(typeof this.element_legend_childs.series != 'object')
787
+ needed = true;
788
+ else if(!this.current.data)
789
+ needed = true;
790
+ else {
791
+ for(var i = 0; i < this.current.data.dimension_names.length; i++) {
792
+ if(typeof this.element_legend_childs.series[this.current.data.dimension_names[i]] == 'undefined') {
793
+ needed = true;
794
+ break;
795
+ }
796
+ else if(!this.follows_global) {
797
+ // FIXME update to latest value
798
+ ;
799
+ }
800
+ }
801
+ }
802
716
- var genLabel = function(state, parent, name, count) {
717
- var c = count % NETDATA.colors.length;
803
+ if(!needed) return;
804
719
- state.element_legend_childs.series[name] = {
720
- name: document.createElement('span'),
721
- value: document.createElement('span')
722
- };
805
+ if(this.debug) this.log('updating Legend DOM');
806
724
- var label = state.element_legend_childs.series[name];
807
+ this.element_legend_childs = {
808
+ title_date: document.createElement('span'),
809
+ title_time: document.createElement('span'),
810
+ title_units: document.createElement('span'),
811
+ series: {}
812
+ };
813
726
- label.name.className += 'netdata-legend-name';
727
- label.value.className += 'netdata-legend-value';
728
- label.value.title = name;
814
+ this.element_legend_childs.title_date.className += "netdata-legend-title-date";
815
+ this.element_legend.appendChild(this.element_legend_childs.title_date);
816
730
- var table = document.createElement('table');
731
- table.innerHTML = '<tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr>';
732
- table.className += 'netdata-legend-name-table-' + state.chart.chart_type;
817
+ this.element_legend.appendChild(document.createElement('br'));
818
734
- var rgb = NETDATA.colorHex2Rgb(NETDATA.colors[c]);
735
- table.style.backgroundColor = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current.color_fill_opacity[state.chart.chart_type] + ')';
819
+ this.element_legend_childs.title_time.className += "netdata-legend-title-time";
820
+ this.element_legend.appendChild(this.element_legend_childs.title_time);
821
737
- var text = document.createTextNode(' ' + name);
822
+ this.element_legend.appendChild(document.createElement('br'));
823
739
- label.name.appendChild(table);
740
- label.name.appendChild(text);
824
+ this.element_legend_childs.title_units.className += "netdata-legend-title-units";
825
+ this.element_legend.appendChild(this.element_legend_childs.title_units);
826
742
- label.name.style.color = NETDATA.colors[c];
743
- label.value.style.color = NETDATA.colors[c];
827
+ this.element_legend.appendChild(document.createElement('br'));
828
745
- if(count > 0)
746
- parent.appendChild(document.createElement('br'));
829
+ var el = document.createElement('div');
830
+ el.className += "netdata-legend-series";
831
+ this.element_legend.appendChild(el);
832
748
- parent.appendChild(label.name);
749
- parent.appendChild(label.value);
750
- };
833
+ var genLabel = function(state, parent, name, count) {
834
+ var c = count % NETDATA.colors.length;
835
752
- if(this.current.data) {
753
- var me = this;
754
- $.each(me.current.data.dimension_names, function(i, d) {
755
- genLabel(me, el, d, i);
756
- });
757
- }
758
- else {
759
- var me = this;
760
- $.each(me.chart.dimensions, function(i, d) {
761
- genLabel(me, el, d.name, i);
762
- });
763
- }
836
+ state.element_legend_childs.series[name] = {
837
+ name: document.createElement('span'),
838
+ value: document.createElement('span')
839
+ };
840
765
- // create a hidden div to be used for hidding
766
- // the original legend of the chart library
767
- el = document.createElement('div');
768
- this.element_legend.appendChild(el);
769
- el.style.display = 'none';
841
+ var label = state.element_legend_childs.series[name];
842
771
- this.element_legend_childs.hidden = document.createElement('div');
772
- el.appendChild(this.element_legend_childs.hidden);
773
- },
843
+ label.name.className += 'netdata-legend-name';
844
+ label.value.className += 'netdata-legend-value';
845
+ label.value.title = name;
846
775
- createChartDOM: function() {
776
- var html = "";
847
+ var table = document.createElement('table');
848
+ table.innerHTML = '<tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr>';
849
+ table.className += 'netdata-legend-name-table-' + state.chart.chart_type;
850
778
- if(this.hasLegend()) {
779
- this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
780
- this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
851
+ var rgb = NETDATA.colorHex2Rgb(NETDATA.colors[c]);
852
+ table.style.backgroundColor = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current.color_fill_opacity[state.chart.chart_type] + ')';
853
782
- html += '<div class="netdata-chart-with-legend-right netdata-'
783
- + this.library_name + '-chart-with-legend-right" id="'
784
- + this.element_chart_id
785
- + '"></div>';
854
+ var text = document.createTextNode(' ' + name);
855
787
- html += '<div class="netdata-chart-legend netdata-'
788
- + this.library_name + '-legend" id="'
789
- + this.element_legend_id
790
- + '"></div>';
791
- }
792
- else {
793
- this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
794
- html += '<div class="netdata-chart netdata-'
795
- + this.library_name + '-chart" id="'
796
- + this.element_chart_id
797
- + '"></div>';
798
- }
856
+ label.name.appendChild(table);
857
+ label.name.appendChild(text);
858
800
- element.innerHTML = html;
801
- this.element_chart = document.getElementById(this.element_chart_id);
802
- $(this.element_chart).data('netdata-state-object', this);
859
+ label.name.style.color = NETDATA.colors[c];
860
+ label.value.style.color = NETDATA.colors[c];
861
804
- if(this.hasLegend()) {
805
- this.element_legend = document.getElementById(this.element_legend_id);
806
- $(this.element_legend).data('netdata-state-object', this);
807
- this.updateLegendDOM();
808
- }
809
- },
862
+ if(count > 0)
863
+ parent.appendChild(document.createElement('br'));
864
811
- hasLegend: function() {
812
- if(this.element_legend) return true;
865
+ parent.appendChild(label.name);
866
+ parent.appendChild(label.value);
867
+ };
868
814
- if(this.library && this.library.legend(this) == 'right-side') {
815
- var legend = $(this.element).data('legend') || 'yes';
816
- if(legend == 'no') return false;
817
- return true;
818
- }
869
+ if(this.current.data) {
870
+ var me = this;
871
+ $.each(me.current.data.dimension_names, function(i, d) {
872
+ genLabel(me, el, d, i);
873
+ });
874
+ }
875
+ else {
876
+ var me = this;
877
+ $.each(me.chart.dimensions, function(i, d) {
878
+ genLabel(me, el, d.name, i);
879
+ });
880
+ }
881
820
- return false;
821
- },
882
+ // create a hidden div to be used for hidding
883
+ // the original legend of the chart library
884
+ el = document.createElement('div');
885
+ this.element_legend.appendChild(el);
886
+ el.style.display = 'none';
887
823
- legendWidth: function() {
824
- return (this.hasLegend())?110:0;
825
- },
888
+ this.element_legend_childs.hidden = document.createElement('div');
889
+ el.appendChild(this.element_legend_childs.hidden);
890
+ }
891
827
- legendHeight: function() {
828
- return $(this.element).height();
829
- },
892
+ chartState.prototype.createChartDOM = function() {
893
+ var html = "";
894
831
- chartWidth: function() {
832
- return $(this.element).width() - this.legendWidth();
833
- },
895
+ if(this.hasLegend()) {
896
+ this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
897
+ this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
898
835
- chartHeight: function() {
836
- return $(this.element).height();
837
- },
899
+ html += '<div class="netdata-chart-with-legend-right netdata-'
900
+ + this.library_name + '-chart-with-legend-right" id="'
901
+ + this.element_chart_id
902
+ + '"></div>';
903
839
- chartPixelsPerPoint: function() {
840
- // force an options provided detail
841
- var px = this.pixels_per_point;
904
+ html += '<div class="netdata-chart-legend netdata-'
905
+ + this.library_name + '-legend" id="'
906
+ + this.element_legend_id
907
+ + '"></div>';
908
+ }
909
+ else {
910
+ this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
911
+ html += '<div class="netdata-chart netdata-'
912
+ + this.library_name + '-chart" id="'
913
+ + this.element_chart_id
914
+ + '"></div>';
915
+ }
916
843
- if(this.library && px < this.library.pixels_per_point(this))
844
- px = this.library.pixels_per_point(this);
917
+ this.element.innerHTML = html;
918
+ this.element_chart = document.getElementById(this.element_chart_id);
919
+ $(this.element_chart).data('netdata-state-object', this);
920
846
- if(px < NETDATA.options.current.pixels_per_point)
847
- px = NETDATA.options.current.pixels_per_point;
921
+ if(this.hasLegend()) {
922
+ this.element_legend = document.getElementById(this.element_legend_id);
923
+ $(this.element_legend).data('netdata-state-object', this);
924
+ this.updateLegendDOM();
925
+ }
926
+ }
927
849
- return px;
850
- },
928
+ chartState.prototype.hasLegend = function() {
929
+ if(this.element_legend) return true;
930
852
- needsResize: function() {
853
- return (this.library && !this.library.autoresize() && this.last_resized < NETDATA.options.last_resized);
854
- },
931
+ if(this.library && this.library.legend(this) == 'right-side') {
932
+ var legend = $(this.element).data('legend') || 'yes';
933
+ if(legend == 'no') return false;
934
+ return true;
935
+ }
936
856
- resizeChart: function() {
857
- if(this.needsResize()) {
858
- if(this.debug) this.log('forcing re-generation due to window resize.');
859
- this.created_ms = 0;
860
- this.last_resized = new Date().getTime();
861
- }
862
- },
937
+ return false;
938
+ }
939
864
- chartURL: function() {
865
- var before;
866
- var after;
867
- if(NETDATA.globalPanAndZoom.isActive()) {
868
- after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
869
- before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
870
- this.follows_global = NETDATA.globalPanAndZoom.seq;
871
- }
872
- else {
873
- before = this.current.force_before_ms != null ? Math.round(this.current.force_before_ms / 1000) : this.before;
874
- after = this.current.force_after_ms != null ? Math.round(this.current.force_after_ms / 1000) : this.after;
875
- this.follows_global = 0;
876
- }
940
+ chartState.prototype.legendWidth = function() {
941
+ return (this.hasLegend())?110:0;
942
+ }
943
878
- this.current.requested_after_ms = after * 1000;
879
- this.current.requested_before_ms = before * 1000;
944
+ chartState.prototype.legendHeight = function() {
945
+ return $(this.element).height();
946
+ }
947
881
- this.current.points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint());
948
+ chartState.prototype.chartWidth = function() {
949
+ return $(this.element).width() - this.legendWidth();
950
+ }
951
883
- // build the data URL
884
- this.current.url = this.chart.data_url;
885
- this.current.url += "&format=" + this.library.format();
886
- this.current.url += "&points=" + this.current.points.toString();
887
- this.current.url += "&group=" + this.method;
888
- this.current.url += "&options=" + this.library.options();
889
- this.current.url += '|jsonwrap';
952
+ chartState.prototype.chartHeight = function() {
953
+ return $(this.element).height();
954
+ }
955
891
- if(after)
892
- this.current.url += "&after=" + after.toString();
956
+ chartState.prototype.chartPixelsPerPoint = function() {
957
+ // force an options provided detail
958
+ var px = this.pixels_per_point;
959
894
- if(before)
895
- this.current.url += "&before=" + before.toString();
960
+ if(this.library && px < this.library.pixels_per_point(this))
961
+ px = this.library.pixels_per_point(this);
962
897
- if(this.dimensions)
898
- this.current.url += "&dimensions=" + this.dimensions;
963
+ if(px < NETDATA.options.current.pixels_per_point)
964
+ px = NETDATA.options.current.pixels_per_point;
965
900
- if(NETDATA.options.debug.chart_data_url || this.debug) this.log('chartURL(): ' + this.current.url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.current.points + ' library: ' + this.library_name);
901
- },
966
+ return px;
967
+ }
968
903
- updateChartWithData: function(data) {
904
- if(this.debug) this.log('got data from netdata server');
905
- this.current.data = data;
969
+ chartState.prototype.needsResize = function() {
970
+ return (this.library && !this.library.autoresize() && this.last_resized < NETDATA.options.last_resized);
971
+ }
972
907
- var started = new Date().getTime();
973
+ chartState.prototype.resizeChart = function() {
974
+ if(this.needsResize()) {
975
+ if(this.debug) this.log('forcing re-generation due to window resize.');
976
+ this.created_ms = 0;
977
+ this.last_resized = new Date().getTime();
978
+ }
979
+ }
980
909
- // if the result is JSON, find the latest update-every
910
- if(typeof data == 'object') {
911
- if(typeof data.view_update_every != 'undefined')
912
- this.current.view_update_every = data.view_update_every * 1000;
981
+ chartState.prototype.chartURL = function() {
982
+ var before;
983
+ var after;
984
+ if(NETDATA.globalPanAndZoom.isActive()) {
985
+ after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
986
+ before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
987
+ this.follows_global = NETDATA.globalPanAndZoom.seq;
988
+ }
989
+ else {
990
+ before = this.current.force_before_ms != null ? Math.round(this.current.force_before_ms / 1000) : this.before;
991
+ after = this.current.force_after_ms != null ? Math.round(this.current.force_after_ms / 1000) : this.after;
992
+ this.follows_global = 0;
993
+ }
994
914
- if(typeof data.after != 'undefined')
915
- this.current.after_ms = data.after * 1000;
995
+ this.current.requested_after_ms = after * 1000;
996
+ this.current.requested_before_ms = before * 1000;
997
917
- if(typeof data.before != 'undefined')
918
- this.current.before_ms = data.before * 1000;
998
+ this.current.points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint());
999
920
- if(typeof data.first_entry_t != 'undefined')
921
- this.current.first_entry_ms = data.first_entry_t * 1000;
1000
+ // build the data URL
1001
+ this.current.url = this.chart.data_url;
1002
+ this.current.url += "&format=" + this.library.format();
1003
+ this.current.url += "&points=" + this.current.points.toString();
1004
+ this.current.url += "&group=" + this.method;
1005
+ this.current.url += "&options=" + this.library.options();
1006
+ this.current.url += '|jsonwrap';
1007
923
- if(typeof data.last_entry_t != 'undefined')
924
- this.current.last_entry_ms = data.last_entry_t * 1000;
1008
+ if(after)
1009
+ this.current.url += "&after=" + after.toString();
1010
926
- if(typeof data.points != 'undefined')
927
- this.current.points = data.points;
1011
+ if(before)
1012
+ this.current.url += "&before=" + before.toString();
1013
929
- data.state = this;
930
- }
1014
+ if(this.dimensions)
1015
+ this.current.url += "&dimensions=" + this.dimensions;
1016
932
- this.updates_counter++;
1017
+ if(NETDATA.options.debug.chart_data_url || this.debug) this.log('chartURL(): ' + this.current.url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.current.points + ' library: ' + this.library_name);
1018
+ }
1019
934
- if(this.debug) {
935
- this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
1020
+ chartState.prototype.updateChartWithData = function(data) {
1021
+ if(this.debug) this.log('got data from netdata server');
1022
+ this.current.data = data;
1023
937
- if(this.current.force_after_ms)
938
- this.log('STATUS: forced : ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
939
- else
940
- this.log('STATUS: forced: unset');
1024
+ var started = new Date().getTime();
1025
942
- this.log('STATUS: requested: ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
943
- this.log('STATUS: rendered : ' + (this.current.after_ms / 1000).toString() + ' - ' + (this.current.before_ms / 1000).toString());
944
- this.log('STATUS: points : ' + (this.current.points).toString() + ', min step: ' + (this._minPanOrZoomStep() / 1000).toString());
945
- }
1026
+ // if the result is JSON, find the latest update-every
1027
+ if(typeof data == 'object') {
1028
+ if(typeof data.view_update_every != 'undefined')
1029
+ this.current.view_update_every = data.view_update_every * 1000;
1030
947
- // this may force the chart to be re-created
948
- this.resizeChart();
1031
+ if(typeof data.after != 'undefined')
1032
+ this.current.after_ms = data.after * 1000;
1033
950
- if(this.updates_since_last_creation >= this.library.max_updates_to_recreate()) {
951
- if(this.debug) this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
952
- this.created_ms = 0;
953
- }
1034
+ if(typeof data.before != 'undefined')
1035
+ this.current.before_ms = data.before * 1000;
1036
955
- if(this.created_ms && typeof this.library.update == 'function') {
956
- if(this.debug) this.log('updating chart...');
1037
+ if(typeof data.first_entry_t != 'undefined')
1038
+ this.current.first_entry_ms = data.first_entry_t * 1000;
1039
958
- // check and update the legend
959
- this.updateLegendDOM();
1040
+ if(typeof data.last_entry_t != 'undefined')
1041
+ this.current.last_entry_ms = data.last_entry_t * 1000;
1042
961
- this.updates_since_last_creation++;
962
- if(NETDATA.options.debug.chart_errors) {
963
- this.library.update(this, data);
964
- }
965
- else {
966
- try {
967
- this.library.update(this, data);
968
- }
969
- catch(err) {
970
- this.error('chart "' + this.id + '" failed to be updated as ' + this.library_name);
971
- }
972
- }
973
- }
974
- else {
975
- if(this.debug) this.log('creating chart...');
1043
+ if(typeof data.points != 'undefined')
1044
+ this.current.points = data.points;
1045
977
- this.createChartDOM();
978
- this.updates_since_last_creation = 0;
1046
+ data.state = this;
1047
+ }
1048
980
- if(NETDATA.options.debug.chart_errors) {
981
- this.library.create(this, data);
982
- this.created_ms = new Date().getTime();
983
- }
984
- else {
985
- try {
986
- this.library.create(this, data);
987
- this.created_ms = new Date().getTime();
988
- }
989
- catch(err) {
990
- this.error('chart "' + this.id + '" failed to be created as ' + this.library_name);
991
- }
992
- }
993
- }
1049
+ this.updates_counter++;
1050
995
- // update the performance counters
996
- var now = new Date().getTime();
997
-
998
- // don't update last_autorefreshed if this chart is
999
- // forced to be updated with global PanAndZoom
1000
- if(NETDATA.globalPanAndZoom.isActive())
1001
- this.current.last_autorefreshed = 0;
1002
- else
1003
- this.current.last_autorefreshed = now;
1051
+ if(this.debug) {
1052
+ this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
1053
1005
- this.refresh_dt_ms = now - started;
1006
- NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
1054
+ if(this.current.force_after_ms)
1055
+ this.log('STATUS: forced : ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
1056
+ else
1057
+ this.log('STATUS: forced: unset');
1058
1008
- if(this.refresh_dt_element)
1009
- this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
1010
- },
1059
+ this.log('STATUS: requested: ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
1060
+ this.log('STATUS: rendered : ' + (this.current.after_ms / 1000).toString() + ' - ' + (this.current.before_ms / 1000).toString());
1061
+ this.log('STATUS: points : ' + (this.current.points).toString() + ', min step: ' + (this._minPanOrZoomStep() / 1000).toString());
1062
+ }
1063
1012
- updateChart: function(callback) {
1013
- if(!this.library || !this.library.enabled) {
1014
- this.error('charting library "' + this.library_name + '" is not available');
1015
- if(typeof callback != 'undefined') callback();
1016
- return;
1017
- }
1064
+ // this may force the chart to be re-created
1065
+ this.resizeChart();
1066
1019
- if(!this.enabled) {
1020
- if(this.debug) this.error('chart "' + this.id + '" is not enabled');
1021
- if(typeof callback != 'undefined') callback();
1022
- return;
1023
- }
1067
+ if(this.updates_since_last_creation >= this.library.max_updates_to_recreate()) {
1068
+ if(this.debug) this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
1069
+ this.created_ms = 0;
1070
+ }
1071
+
1072
+ if(this.created_ms && typeof this.library.update == 'function') {
1073
+ if(this.debug) this.log('updating chart...');
1074
+
1075
+ // check and update the legend
1076
+ this.updateLegendDOM();
1077
1025
- if(!this.isVisible()) {
1026
- if(NETDATA.options.debug.visibility || this.debug) this.log('is not visible');
1027
- if(typeof callback != 'undefined') callback();
1028
- return;
1078
+ this.updates_since_last_creation++;
1079
+ if(NETDATA.options.debug.chart_errors) {
1080
+ this.library.update(this, data);
1081
+ }
1082
+ else {
1083
+ try {
1084
+ this.library.update(this, data);
1085
}
1030
- if(!this.chart) {
1031
- var this_state_object = this;
1032
- this.getChart(function() { this_state_object.updateChart(callback); });
1033
- return;
1086
+ catch(err) {
1087
+ this.error('chart "' + this.id + '" failed to be updated as ' + this.library_name);
1088
}
1089
+ }
1090
+ }
1091
+ else {
1092
+ if(this.debug) this.log('creating chart...');
1093
+
1094
+ this.createChartDOM();
1095
+ this.updates_since_last_creation = 0;
1096
1036
- if(!this.library.initialized) {
1037
- var this_state_object = this;
1038
- this.library.initialize(function() { this_state_object.updateChart(callback); });
1039
- return;
1097
+ if(NETDATA.options.debug.chart_errors) {
1098
+ this.library.create(this, data);
1099
+ this.created_ms = new Date().getTime();
1100
+ }
1101
+ else {
1102
+ try {
1103
+ this.library.create(this, data);
1104
+ this.created_ms = new Date().getTime();
1105
+ }
1106
+ catch(err) {
1107
+ this.error('chart "' + this.id + '" failed to be created as ' + this.library_name);
1108
}
1109
+ }
1110
+ }
1111
1042
- this.clearSelection();
1043
- this.chartURL();
1044
- if(this.debug) this.log('updating from ' + this.current.url);
1112
+ // update the performance counters
1113
+ var now = new Date().getTime();
1114
+
1115
+ // don't update last_autorefreshed if this chart is
1116
+ // forced to be updated with global PanAndZoom
1117
+ if(NETDATA.globalPanAndZoom.isActive())
1118
+ this.current.last_autorefreshed = 0;
1119
+ else
1120
+ this.current.last_autorefreshed = now;
1121
1046
- var this_state_object = this;
1047
- $.ajax( {
1048
- url: this.current.url,
1049
- crossDomain: true,
1050
- cache: false
1051
- })
1052
- .then(function(data) {
1053
- this_state_object.updateChartWithData(data);
1054
- })
1055
- .fail(function() {
1056
- this_state_object.error('cannot download chart from ' + this_state_object.current.url);
1057
- })
1058
- .always(function() {
1059
- if(typeof callback == 'function') callback();
1060
- });
1061
- },
1122
+ this.refresh_dt_ms = now - started;
1123
+ NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
1124
1063
- isVisible: function() {
1064
- if(NETDATA.options.current.update_only_visible)
1065
- return $(this.element).visible(true);
1066
- else
1067
- return true;
1068
- },
1125
+ if(this.refresh_dt_element)
1126
+ this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
1127
+ }
1128
1070
- isAutoRefreshed: function() {
1071
- return this.current.autorefresh;
1072
- },
1129
+ chartState.prototype.updateChart = function(callback) {
1130
+ if(!this.library || !this.library.enabled) {
1131
+ this.error('charting library "' + this.library_name + '" is not available');
1132
+ if(typeof callback != 'undefined') callback();
1133
+ return;
1134
+ }
1135
1074
- canBeAutoRefreshed: function() {
1075
- if(this.isAutoRefreshed()) {
1076
- var now = new Date().getTime();
1136
+ if(!this.enabled) {
1137
+ if(this.debug) this.error('chart "' + this.id + '" is not enabled');
1138
+ if(typeof callback != 'undefined') callback();
1139
+ return;
1140
+ }
1141
1078
- if(this.updates_counter && !NETDATA.options.page_is_visible) {
1079
- if(NETDATA.options.debug.focus || this.debug) this.log('canBeAutoRefreshed(): page does not have focus');
1080
- return false;
1081
- }
1142
+ if(!this.isVisible()) {
1143
+ if(NETDATA.options.debug.visibility || this.debug) this.log('is not visible');
1144
+ if(typeof callback != 'undefined') callback();
1145
+ return;
1146
+ }
1147
+ if(!this.chart) {
1148
+ var this_state_object = this;
1149
+ this.getChart(function() { this_state_object.updateChart(callback); });
1150
+ return;
1151
+ }
1152
1083
- if(!this.isVisible()) {
1084
- if(this.debug) this.log('canBeAutoRefreshed(): I am not visible.');
1085
- return false;
1086
- }
1153
+ if(!this.library.initialized) {
1154
+ var this_state_object = this;
1155
+ this.library.initialize(function() { this_state_object.updateChart(callback); });
1156
+ return;
1157
+ }
1158
1088
- // options valid only for autoRefresh()
1089
- if(NETDATA.options.auto_refresher_stop_until == 0 || NETDATA.options.auto_refresher_stop_until < now) {
1090
- if(NETDATA.globalPanAndZoom.isActive()) {
1091
- if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) {
1092
- if(this.debug) this.log('canBeAutoRefreshed(): global panning: I need an update.');
1093
- return true;
1094
- }
1095
- else {
1096
- if(this.debug) this.log('canBeAutoRefreshed(): global panning: I am already up to date.');
1097
- return false;
1098
- }
1099
- }
1159
+ this.clearSelection();
1160
+ this.chartURL();
1161
+ if(this.debug) this.log('updating from ' + this.current.url);
1162
1101
- if(this.selected) {
1102
- if(this.debug) this.log('canBeAutoRefreshed(): I have a selection in place.');
1103
- return false;
1104
- }
1163
+ var this_state_object = this;
1164
+ $.ajax( {
1165
+ url: this.current.url,
1166
+ crossDomain: true,
1167
+ cache: false
1168
+ })
1169
+ .then(function(data) {
1170
+ this_state_object.updateChartWithData(data);
1171
+ })
1172
+ .fail(function() {
1173
+ this_state_object.error('cannot download chart from ' + this_state_object.current.url);
1174
+ })
1175
+ .always(function() {
1176
+ if(typeof callback == 'function') callback();
1177
+ });
1178
+ }
1179
1106
- if(this.paused) {
1107
- if(this.debug) this.log('canBeAutoRefreshed(): I am paused.');
1108
- return false;
1109
- }
1180
+ chartState.prototype.isVisible = function() {
1181
+ if(NETDATA.options.current.update_only_visible)
1182
+ return $(this.element).visible(true);
1183
+ else
1184
+ return true;
1185
+ }
1186
1111
- if(now - this.current.last_autorefreshed > this.current.view_update_every) {
1112
- if(this.debug) this.log('canBeAutoRefreshed(): It is time to update me.');
1113
- return true;
1114
- }
1115
- }
1116
- }
1187
+ chartState.prototype.isAutoRefreshed = function() {
1188
+ return this.current.autorefresh;
1189
+ }
1190
+
1191
+ chartState.prototype.canBeAutoRefreshed = function() {
1192
+ if(this.isAutoRefreshed()) {
1193
+ var now = new Date().getTime();
1194
1195
+ if(this.updates_counter && !NETDATA.options.page_is_visible) {
1196
+ if(NETDATA.options.debug.focus || this.debug) this.log('canBeAutoRefreshed(): page does not have focus');
1197
return false;
1119
- },
1198
+ }
1199
1121
- autoRefresh: function(callback) {
1122
- if(this.canBeAutoRefreshed()) {
1123
- this.updateChart(callback);
1124
- }
1125
- else {
1126
- if(typeof callback != 'undefined')
1127
- callback();
1200
+ if(!this.isVisible()) {
1201
+ if(this.debug) this.log('canBeAutoRefreshed(): I am not visible.');
1202
+ return false;
1203
+ }
1204
+
1205
+ // options valid only for autoRefresh()
1206
+ if(NETDATA.options.auto_refresher_stop_until == 0 || NETDATA.options.auto_refresher_stop_until < now) {
1207
+ if(NETDATA.globalPanAndZoom.isActive()) {
1208
+ if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) {
1209
+ if(this.debug) this.log('canBeAutoRefreshed(): global panning: I need an update.');
1210
+ return true;
1211
+ }
1212
+ else {
1213
+ if(this.debug) this.log('canBeAutoRefreshed(): global panning: I am already up to date.');
1214
+ return false;
1215
+ }
1216
}
1129
- },
1217
1131
- _defaultsFromDownloadedChart: function(chart) {
1132
- this.chart = chart;
1133
- this.chart_url = chart.url;
1134
- this.current.view_update_every = chart.update_every * 1000;
1135
- this.current.points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
1136
- },
1218
+ if(this.selected) {
1219
+ if(this.debug) this.log('canBeAutoRefreshed(): I have a selection in place.');
1220
+ return false;
1221
+ }
1222
1138
- // fetch the chart description from the netdata server
1139
- getChart: function(callback) {
1140
- this.chart = NETDATA.chartRegistry.get(this.host, this.id);
1141
- if(this.chart) {
1142
- this._defaultsFromDownloadedChart(this.chart);
1143
- if(typeof callback == 'function') callback();
1223
+ if(this.paused) {
1224
+ if(this.debug) this.log('canBeAutoRefreshed(): I am paused.');
1225
+ return false;
1226
}
1145
- else {
1146
- this.chart_url = this.host + "/api/v1/chart?chart=" + this.id;
1147
- if(this.debug) this.log('downloading ' + this.chart_url);
1148
- var this_state_object = this;
1149
-
1150
- $.ajax( {
1151
- url: this.chart_url,
1152
- crossDomain: true,
1153
- cache: false
1154
- })
1155
- .done(function(chart) {
1156
- chart.url = this_state_object.chart_url;
1157
- chart.data_url = (this_state_object.host + chart.data_url);
1158
- this_state_object._defaultsFromDownloadedChart(chart);
1159
- NETDATA.chartRegistry.add(this_state_object.host, this_state_object.id, chart);
1160
- })
1161
- .fail(function() {
1162
- NETDATA.error(404, this_state_object.chart_url);
1163
- this_state_object.error('chart "' + this_state_object.id + '" not found on url "' + this_state_object.chart_url + '"');
1164
- })
1165
- .always(function() {
1166
- if(typeof callback == 'function') callback();
1167
- });
1227
+
1228
+ if(now - this.current.last_autorefreshed > this.current.view_update_every) {
1229
+ if(this.debug) this.log('canBeAutoRefreshed(): It is time to update me.');
1230
+ return true;
1231
}
1169
- },
1232
+ }
1233
+ }
1234
+
1235
+ return false;
1236
+ }
1237
+
1238
+ chartState.prototype.autoRefresh = function(callback) {
1239
+ if(this.canBeAutoRefreshed()) {
1240
+ this.updateChart(callback);
1241
+ }
1242
+ else {
1243
+ if(typeof callback != 'undefined')
1244
+ callback();
1245
+ }
1246
+ }
1247
1171
- // resize the chart to its real dimensions
1172
- // as given by the caller
1173
- sizeChart: function() {
1174
- element.className += "netdata-container";
1248
+ chartState.prototype._defaultsFromDownloadedChart = function(chart) {
1249
+ this.chart = chart;
1250
+ this.chart_url = chart.url;
1251
+ this.current.view_update_every = chart.update_every * 1000;
1252
+ this.current.points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
1253
+ }
1254
1176
- if(this.debug) this.log('sizing element');
1255
+ // fetch the chart description from the netdata server
1256
+ chartState.prototype.getChart = function(callback) {
1257
+ this.chart = NETDATA.chartRegistry.get(this.host, this.id);
1258
+ if(this.chart) {
1259
+ this._defaultsFromDownloadedChart(this.chart);
1260
+ if(typeof callback == 'function') callback();
1261
+ }
1262
+ else {
1263
+ this.chart_url = this.host + "/api/v1/chart?chart=" + this.id;
1264
+ if(this.debug) this.log('downloading ' + this.chart_url);
1265
+ var this_state_object = this;
1266
+
1267
+ $.ajax( {
1268
+ url: this.chart_url,
1269
+ crossDomain: true,
1270
+ cache: false
1271
+ })
1272
+ .done(function(chart) {
1273
+ chart.url = this_state_object.chart_url;
1274
+ chart.data_url = (this_state_object.host + chart.data_url);
1275
+ this_state_object._defaultsFromDownloadedChart(chart);
1276
+ NETDATA.chartRegistry.add(this_state_object.host, this_state_object.id, chart);
1277
+ })
1278
+ .fail(function() {
1279
+ NETDATA.error(404, this_state_object.chart_url);
1280
+ this_state_object.error('chart "' + this_state_object.id + '" not found on url "' + this_state_object.chart_url + '"');
1281
+ })
1282
+ .always(function() {
1283
+ if(typeof callback == 'function') callback();
1284
+ });
1285
+ }
1286
+ }
1287
1178
- if(this.width)
1179
- $(this.element).css('width', this.width);
1288
+ // resize the chart to its real dimensions
1289
+ // as given by the caller
1290
+ chartState.prototype.sizeChart = function() {
1291
+ this.element.className += "netdata-container";
1292
1181
- if(this.height)
1182
- $(this.element).css('height', this.height);
1293
+ if(this.debug) this.log('sizing element');
1294
1184
- // these should be left to css
1185
- //$(this.element).css('display', 'inline-block')
1186
- //$(this.element).css('overflow', 'hidden');
1295
+ if(this.width)
1296
+ $(this.element).css('width', this.width);
1297
1188
- if(NETDATA.chartDefaults.min_width)
1189
- $(this.element).css('min-width', NETDATA.chartDefaults.min_width);
1190
- },
1298
+ if(this.height)
1299
+ $(this.element).css('height', this.height);
1300
1192
- // show a message in the chart
1193
- message: function(type, msg) {
1194
- this.element.innerHTML = '<div class="netdata-message netdata-' + type + '-message" style="font-size: x-small; overflow: hidden; width: 100%; height: 100%;"><small>'
1195
- + msg
1196
- + '</small></div>';
1301
+ if(NETDATA.chartDefaults.min_width)
1302
+ $(this.element).css('min-width', NETDATA.chartDefaults.min_width);
1303
+ }
1304
1198
- // reset the creation datetime
1199
- // since we overwrote the whole element
1200
- this.created_ms = 0
1201
- if(this.debug) this.log(msg);
1202
- },
1305
+ // show a message in the chart
1306
+ chartState.prototype.message = function(type, msg) {
1307
+ this.element.innerHTML = '<div class="netdata-message netdata-' + type + '-message" style="font-size: x-small; overflow: hidden; width: 100%; height: 100%;"><small>'
1308
+ + msg
1309
+ + '</small></div>';
1310
1204
- // show an error on the chart and stop it forever
1205
- error: function(msg) {
1206
- this.message('error', this.id + ': ' + msg);
1207
- this.enabled = false;
1208
- },
1311
+ // reset the creation datetime
1312
+ // since we overwrote the whole element
1313
+ this.created_ms = 0
1314
+ if(this.debug) this.log(msg);
1315
+ }
1316
1210
- // show a message indicating the chart is loading
1211
- info: function(msg) {
1212
- this.message('info', this.id + ': ' + msg);
1213
- },
1317
+ // show an error on the chart and stop it forever
1318
+ chartState.prototype.error = function(msg) {
1319
+ this.message('error', this.id + ': ' + msg);
1320
+ this.enabled = false;
1321
+ }
1322
1215
- init: function() {
1216
- if(this.debug) this.log('created');
1217
- this.sizeChart();
1218
- this.info("loading...");
1219
-
1220
- // make sure the host does not end with /
1221
- // all netdata API requests use absolute paths
1222
- while(this.host.slice(-1) == '/')
1223
- this.host = this.host.substring(0, this.host.length - 1);
1224
-
1225
- // check the requested library is available
1226
- // we don't initialize it here - it will be initialized when
1227
- // this chart will be first used
1228
- if(typeof NETDATA.chartLibraries[this.library_name] == 'undefined') {
1229
- NETDATA.error(402, this.library_name);
1230
- this.error('chart library "' + this.library_name + '" is not found');
1231
- }
1232
- else if(!NETDATA.chartLibraries[this.library_name].enabled) {
1233
- NETDATA.error(403, this.library_name);
1234
- this.error('chart library "' + this.library_name + '" is not enabled');
1235
- }
1236
- else
1237
- this.library = NETDATA.chartLibraries[this.library_name];
1323
+ // show a message indicating the chart is loading
1324
+ chartState.prototype.info = function(msg) {
1325
+ this.message('info', this.id + ': ' + msg);
1326
+ }
1327
1239
- // if we need to report the rendering speed
1240
- // find the element that needs to be updated
1241
- if(this.refresh_dt_element_name)
1242
- this.refresh_dt_element = document.getElementById(this.refresh_dt_element_name) || null;
1328
+ chartState.prototype.init = function() {
1329
+ if(this.debug) this.log('created');
1330
+ this.sizeChart();
1331
+ this.info("loading...");
1332
+
1333
+ // make sure the host does not end with /
1334
+ // all netdata API requests use absolute paths
1335
+ while(this.host.slice(-1) == '/')
1336
+ this.host = this.host.substring(0, this.host.length - 1);
1337
+
1338
+ // check the requested library is available
1339
+ // we don't initialize it here - it will be initialized when
1340
+ // this chart will be first used
1341
+ if(typeof NETDATA.chartLibraries[this.library_name] == 'undefined') {
1342
+ NETDATA.error(402, this.library_name);
1343
+ this.error('chart library "' + this.library_name + '" is not found');
1344
+ }
1345
+ else if(!NETDATA.chartLibraries[this.library_name].enabled) {
1346
+ NETDATA.error(403, this.library_name);
1347
+ this.error('chart library "' + this.library_name + '" is not enabled');
1348
+ }
1349
+ else
1350
+ this.library = NETDATA.chartLibraries[this.library_name];
1351
1244
- // the default mode for all charts
1245
- this.setMode('auto');
1246
- }
1247
- };
1352
+ // if we need to report the rendering speed
1353
+ // find the element that needs to be updated
1354
+ if(this.refresh_dt_element_name)
1355
+ this.refresh_dt_element = document.getElementById(this.refresh_dt_element_name) || null;
1356
1249
- state.init();
1250
- return state;
1357
+ // the default mode for all charts
1358
+ this.setMode('auto');
1359
}
1360
1361
// get or create a chart state, given a DOM element
1362
NETDATA.chartState = function(element) {
1363
var state = $(element).data('netdata-state-object') || null;
1364
if(!state) {
1257
- state = NETDATA.chartInitialState(element);
1365
+ state = new chartState(element);
1366
+ state.init();
1367
$(element).data('netdata-state-object', state);
1368
}
1369
return state;
@@ -1624,110 +1733,8 @@
1733
1734
NETDATA.dygraph = {
1735
smooth: false,
1627
- state: null,
1628
- sync: false,
1629
- dont_sync_before: 0,
1630
- slaves: []
1736
};
1737
1633
- NETDATA.dygraph.syncStart = function(state, event, x, points, row, seriesName) {
1634
- if(!NETDATA.options.current.sync_selection) return;
1635
- if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStart()');
1636
-
1637
- //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
1638
- // state.log('sync: I am not the sync master.');
1639
- // return;
1640
- //}
1641
- // state.debug = true;
1642
-
1643
- var t = state.current.after_ms + row * state.current.view_update_every;
1644
- // console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t == x)?'SAME':'DIFFERENT') + ', rows in db: ' + state.current.data.points + ' visible(x) = ' + state.timeIsVisible(x) + ' visible(t) = ' + state.timeIsVisible(t) + ' r(x) = ' + state.calculateRowForTime(x) + ' r(t) = ' + state.calculateRowForTime(t) + ' range: ' + state.current.after_ms + ' - ' + state.current.before_ms + ' real: ' + state.current.data.after + ' - ' + state.current.data.before + ' every: ' + state.current.view_update_every);
1645
-
1646
- now = new Date().getTime();
1647
- if(now < NETDATA.dygraph.dont_sync_before) {
1648
- if(state.debug) state.log('sync: cannot sync yet.');
1649
- return;
1650
- }
1651
-
1652
- // since we are the sync master, we should not call state.setSelection()
1653
- // dygraphs is taking care of visualizing our selection.
1654
- state.selected = true;
1655
-
1656
- var dygraph = state.dygraph_instance;
1657
-
1658
- if(!NETDATA.dygraph.sync) {
1659
- if(state.debug) state.log('sync: setting up...');
1660
- $.each(NETDATA.options.targets, function(i, target) {
1661
- var st = NETDATA.chartState(target);
1662
- if(st == state) {
1663
- if(state.debug) st.log('sync: not adding me to sync');
1664
- }
1665
- else {
1666
- if(typeof st.dygraph_instance == 'object' && st.library_name == state.library_name && st.isVisible()) {
1667
- NETDATA.dygraph.slaves.push(st);
1668
- if(state.debug) st.log('sync: added slave to sync');
1669
- }
1670
- }
1671
- });
1672
- NETDATA.dygraph.sync = true;
1673
- }
1674
-
1675
- $.each(NETDATA.dygraph.slaves, function(i, st) {
1676
- if(st == state) {
1677
- if(state.debug) st.log('sync: ignoring me from set selection');
1678
- }
1679
- else {
1680
- if(state.debug) st.log('sync: showing master selection');
1681
- st.setSelection(t);
1682
- }
1683
- });
1684
- }
1685
-
1686
- NETDATA.dygraph.syncStop = function(state) {
1687
- if(!NETDATA.options.current.sync_selection) return;
1688
-
1689
- if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStop()');
1690
-
1691
- //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
1692
- // state.log('sync: I am not the sync master.');
1693
- // return;
1694
- //}
1695
-
1696
- if(NETDATA.dygraph.sync) {
1697
- if(state.debug) st.log('sync: cleaning up...');
1698
- $.each(NETDATA.dygraph.slaves, function(i, st) {
1699
- if(st == state) {
1700
- if(state.debug) st.log('sync: not adding me to sync stop');
1701
- }
1702
- else {
1703
- if(state.debug) st.log('sync: removed slave from sync');
1704
- st.clearSelection();
1705
- }
1706
- });
1707
-
1708
- NETDATA.dygraph.slaves = [];
1709
- NETDATA.dygraph.sync = false;
1710
- }
1711
-
1712
- // since we are the sync master, we should not call state.clearSelection()
1713
- // dygraphs is taking care of visualizing our selection.
1714
- state.selected = false;
1715
- }
1716
-
1717
- NETDATA.dygraph.resetChart = function(state, dygraph, context) {
1718
- if(NETDATA.options.debug.dygraph) state.log('dygraph.resetChart()');
1719
-
1720
- state.resetChart();
1721
- }
1722
-
1723
- NETDATA.dygraph.chartPanOrZoom = function(state, dygraph, after, before) {
1724
- if(NETDATA.options.debug.dygraph) console.log('>>>> dygraph.zoomOrPan(state, dygraph, after:' + after + ', before: ' + before + ')');
1725
-
1726
- //console.log(state.dygraph_instance);
1727
- state.updateChartPanOrZoom(after, before);
1728
- return;
1729
- }
1730
-
1738
NETDATA.dygraphSetSelection = function(state, t) {
1739
if(typeof state.dygraph_instance != 'undefined') {
1740
var r = state.calculateRowForTime(t);
@@ -1957,19 +1964,28 @@
1964
var after = Math.round(x_range[0]);
1965
var before = Math.round(x_range[1]);
1966
1960
- NETDATA.dygraph.chartPanOrZoom(state, this, after, before);
1967
+ state.updateChartPanOrZoom(after, before);
1968
}
1969
},
1970
zoomCallback: function(minDate, maxDate, yRanges) {
1971
if(NETDATA.options.debug.dygraph) state.log('dygraphZoomCallback()');
1965
- NETDATA.dygraph.syncStop(state);
1966
- state.delaySelectionSync();
1967
- NETDATA.dygraph.chartPanOrZoom(state, this, minDate, maxDate);
1972
+ state.globalSelectionSyncStop();
1973
+ state.globalSelectionSyncDelay();
1974
+ state.updateChartPanOrZoom(minDate, maxDate);
1975
},
1976
highlightCallback: function(event, x, points, row, seriesName) {
1977
if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphHighlightCallback()');
1978
state.pauseChart();
1972
- NETDATA.dygraph.syncStart(state, event, x, points, row, seriesName);
1979
+
1980
+ // there is a bug in dygraph when the chart is zoomed enough
1981
+ // the time it thinks is selected is wrong
1982
+ // here we calculate the time t based on the row number selected
1983
+ // which is ok
1984
+ var t = state.current.after_ms + row * state.current.view_update_every;
1985
+ // console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t == x)?'SAME':'DIFFERENT') + ', rows in db: ' + state.current.data.points + ' visible(x) = ' + state.timeIsVisible(x) + ' visible(t) = ' + state.timeIsVisible(t) + ' r(x) = ' + state.calculateRowForTime(x) + ' r(t) = ' + state.calculateRowForTime(t) + ' range: ' + state.current.after_ms + ' - ' + state.current.before_ms + ' real: ' + state.current.data.after + ' - ' + state.current.data.before + ' every: ' + state.current.view_update_every);
1986
+
1987
+ state.globalSelectionSync(t);
1988
+
1989
// fix legend zIndex using the internal structures of dygraph legend module
1990
// this works, but it is a hack!
1991
// state.dygraph_instance.plugins_[0].plugin.legend_div_.style.zIndex = 10000;
@@ -1977,12 +1993,12 @@
1993
unhighlightCallback: function(event) {
1994
if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphUnhighlightCallback()');
1995
state.unpauseChart();
1980
- NETDATA.dygraph.syncStop(state);
1996
+ state.globalSelectionSyncStop();
1997
},
1998
interactionModel : {
1999
mousedown: function(event, dygraph, context) {
2000
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousedown()');
1985
- NETDATA.dygraph.syncStop(state);
2001
+ state.globalSelectionSyncStop();
2002
2003
if(NETDATA.options.debug.dygraph) state.log('dygraphMouseDown()');
2004
@@ -1994,24 +2010,24 @@
2010
if(event.button && event.button == 1) {
2011
if (event.altKey || event.shiftKey) {
2012
state.setMode('pan');
1997
- state.delaySelectionSync();
2013
+ state.globalSelectionSyncDelay();
2014
Dygraph.startPan(event, dygraph, context);
2015
}
2016
else {
2017
state.setMode('zoom');
2002
- state.delaySelectionSync();
2018
+ state.globalSelectionSyncDelay();
2019
Dygraph.startZoom(event, dygraph, context);
2020
}
2021
}
2022
else {
2023
if (event.altKey || event.shiftKey) {
2024
state.setMode('zoom');
2009
- state.delaySelectionSync();
2025
+ state.globalSelectionSyncDelay();
2026
Dygraph.startZoom(event, dygraph, context);
2027
}
2028
else {
2029
state.setMode('pan');
2014
- state.delaySelectionSync();
2030
+ state.globalSelectionSyncDelay();
2031
Dygraph.startPan(event, dygraph, context);
2032
}
2033
}
@@ -2020,14 +2036,14 @@
2036
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousemove()');
2037
2038
if(context.isPanning) {
2023
- NETDATA.dygraph.syncStop(state);
2024
- state.delaySelectionSync();
2039
+ state.globalSelectionSyncStop();
2040
+ state.globalSelectionSyncDelay();
2041
state.setMode('pan');
2042
Dygraph.movePan(event, dygraph, context);
2043
}
2044
else if(context.isZooming) {
2029
- NETDATA.dygraph.syncStop(state);
2030
- state.delaySelectionSync();
2045
+ state.globalSelectionSyncStop();
2046
+ state.globalSelectionSyncDelay();
2047
state.setMode('zoom');
2048
Dygraph.moveZoom(event, dygraph, context);
2049
}
@@ -2036,11 +2052,11 @@
2052
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mouseup()');
2053
2054
if (context.isPanning) {
2039
- state.delaySelectionSync();
2055
+ state.globalSelectionSyncDelay();
2056
Dygraph.endPan(event, dygraph, context);
2057
}
2058
else if (context.isZooming) {
2043
- state.delaySelectionSync();
2059
+ state.globalSelectionSyncDelay();
2060
Dygraph.endZoom(event, dygraph, context);
2061
}
2062
},
@@ -2050,14 +2066,14 @@
2066
},
2067
dblclick: function(event, dygraph, context) {
2068
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.dblclick()');
2053
- NETDATA.dygraph.syncStop(state);
2054
- NETDATA.dygraph.resetChart(state, dygraph, context);
2069
+ state.globalSelectionSyncStop();
2070
+ state.resetChart();
2071
},
2072
mousewheel: function(event, dygraph, context) {
2073
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousewheel()');
2074
2059
- NETDATA.dygraph.syncStop(state);
2060
- state.delaySelectionSync();
2075
+ state.globalSelectionSyncStop();
2076
+ state.globalSelectionSyncDelay();
2077
2078
if(event.altKey || event.shiftKey) {
2079
// http://dygraphs.com/gallery/interaction-api.js
@@ -2077,13 +2093,13 @@
2093
if(NETDATA.options.debug.dygraph) state.log('percent: ' + percentage + ' from ' + after_old + ' - ' + before_old + ' to ' + after + ' - ' + before + ', range from ' + (before_old - after_old).toString() + ' to ' + (before - after).toString());
2094
2095
state.setMode('zoom');
2080
- NETDATA.dygraph.chartPanOrZoom(state, dygraph, after, before);
2096
+ state.updateChartPanOrZoom(after, before);
2097
}
2098
},
2099
touchstart: function(event, dygraph, context) {
2100
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.touchstart()');
2085
- NETDATA.dygraph.syncStop(state);
2086
- state.delaySelectionSync();
2101
+ state.globalSelectionSyncStop();
2102
+ state.globalSelectionSyncDelay();
2103
Dygraph.Interaction.startTouch(event, dygraph, context);
2104
context.touchDirections = { x: true, y: false };
2105
state.setMode('zoom');
@@ -2091,7 +2107,7 @@
2107
touchmove: function(event, dygraph, context) {
2108
if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.touchmove()');
2109
//Dygraph.cancelEvent(event);
2094
- NETDATA.dygraph.syncStop(state);
2110
+ state.globalSelectionSyncStop();
2111
Dygraph.Interaction.moveTouch(event, dygraph, context);
2112
},
2113
touchend: function(event, dygraph, context) {