@cryptotaxi247 / netdata-1 / commits / d5aef354a

added support for resizable and not resizable charts; added support for re-creating charts based on libraries that cause memory leaks on the browsers; more code cleanups;

Costa Tsaousis (ktsaou) committed Dec 7, 2015 at 03:00 UTC d5aef354ab36561f67d2279e2f584f202610b5a6
2 files changed +486 -387
web/dashboard.css
+10 -12
@@ -25,37 +25,35 @@ html {
25
26 }
27
28 -/*
29 -.netdata-legend {
30 - width: 50px;
31 - height: 100%;
28 +.netdata-chart-legend {
29 background-color:Gray;
30 overflow: auto;
31 overflow-y: scroll;
32 + display: inline-block;
33 }
36 -*/
37 -
38 -.netdata-chart-container {
34
35 +.netdata-chart {
36 + display: inline-block;
37 + overflow: hidden;
38 }
39
42 -.netdata-peity-container {
40 +.netdata-peity-chart {
41
42 }
43
46 -.netdata-sparkline-container {
44 +.netdata-sparkline-chart {
45
46 }
47
50 -.netdata-dygraph-container {
48 +.netdata-dygraph-chart {
49
50 }
51
54 -.netdata-morris-container {
52 +.netdata-morris-chart {
53
54 }
55
58 -.netdata-google-container {
56 +.netdata-google-chart {
57
58 }
59
web/dashboard.js
+476 -375
@@ -130,6 +130,8 @@
130 // rendering the chart that is panned or zoomed).
131 // Used with .current.global_pan_sync_time
132
133 + last_resized: 0, // the timestamp of the last resize request
134 +
135 // the current profile
136 // we may have many...
137 current: {
@@ -159,9 +161,15 @@
161 // autorefreshing of charts is paused for this amount
162 // of time
163
162 - sync_delay: 1500 // ms - when you pan or zoom a chart, wait this amount
164 + sync_selection_delay: 1500, // ms - when you pan or zoom a chart, wait this amount
165 // of time before setting up synchronized selections
166 // on hover.
167 +
168 + sync_selection: true, // enable or disable selection sync
169 +
170 + sync_pan_and_zoom: true, // enable or disable pan and zoom sync
171 +
172 + update_only_visible: true // enable or disable visibility management
173 },
174
175 debug: {
@@ -170,7 +178,7 @@
178 focus: 0,
179 visibility: 0,
180 chart_data_url: 0,
173 - chart_errors: 0,
181 + chart_errors: 1,
182 chart_timing: 0,
183 chart_calls: 0,
184 libraries: 0,
@@ -180,6 +188,9 @@
188
189 if(NETDATA.options.debug.main_loop) console.log('welcome to NETDATA');
190
191 + window.onresize = function(event) {
192 + NETDATA.options.last_resized = new Date().getTime();
193 + };
194
195 // ----------------------------------------------------------------------------------------------------------------
196 // Error Handling
@@ -274,6 +285,8 @@
285
286 // set a new master
287 setMaster: function(state, after, before) {
288 + if(!NETDATA.options.current.sync_pan_and_zoom) return;
289 +
290 if(this.master && this.master != state)
291 this.master.resetChart();
292
@@ -320,6 +333,9 @@
333 if(!this.master || !this.seq)
334 return false;
335
336 + if(state.needsResize())
337 + return true;
338 +
339 if(state.follows_global == this.seq)
340 return false;
341
@@ -341,10 +357,6 @@
357 width: self.data('width') || NETDATA.chartDefaults.width,
358 height: self.data('height') || NETDATA.chartDefaults.height,
359
344 - // these are calculated every time the chart is refreshed
345 - calculated_width: 0,
346 - calculated_height: 0,
347 -
360 // string - the netdata server URL, without any path
361 host: self.data('host') || NETDATA.chartDefaults.host,
362
@@ -356,7 +368,7 @@
368 before: self.data('before') || NETDATA.chartDefaults.before,
369
370 // the pixels per point requested by the user
359 - pixels_per_point: 1,
371 + pixels_per_point: self.data('pixels-per-point') || 1,
372 points: self.data('points') || null,
373
374 // the dimensions requested by the user
@@ -366,7 +378,11 @@
378 library_name: self.data('chart-library') || NETDATA.chartDefaults.library,
379 library: null, // object - the chart library used
380
369 - element: element, // the element this chart appears in
381 + element: element, // the element already created by the user
382 + element_chart: null, // the element with the chart
383 + element_chart_id: null,
384 + element_legend: null, // the element with the legend of the chart (if created by us)
385 + element_legend_id: null,
386
387 chart_url: null, // string - the url to download chart info
388 chart: null, // object - the chart as downloaded from the server
@@ -378,12 +394,16 @@
394 paused: false, // boolean - is the chart paused for any reason?
395 selected: false, // boolean - is the chart shown a selection?
396 debug: false, // boolena - console.log() debug info about this chart
397 +
398 updates_counter: 0, // numeric - the number of refreshes made so far
399 + updates_since_last_creation: 0,
400
401 follows_global: 0, // the sequence number of the global synchronization
402 // between chart.
403 // Used with NETDATA.globalPanAndZoom.seq
404
405 + last_resized: 0, // the last time the chart was resized
406 +
407 mode: null, // auto, pan, zoom
408 // this is a pointer to one of the sub-classes below
409
@@ -477,8 +497,9 @@
497 return this.selected;
498 },
499
500 + // find if a timestamp (ms) is shown in the current chart
501 timeIsVisible: function(t) {
481 - if(t >= this.mode.after_ms && t <= this.mode.before_ms)
502 + if(t >= this.current.after_ms && t <= this.current.before_ms)
503 return true;
504 return false;
505 },
@@ -486,8 +507,8 @@
507 calculateRowForTime: function(t) {
508 if(!this.timeIsVisible(t)) return -1;
509
489 - var r = Math.floor((t - this.mode.after_ms) / this.mode.view_update_every);
490 - // console.log(this.mode.data);
510 + var r = Math.floor((t - this.current.after_ms) / this.current.view_update_every);
511 + // console.log(this.current.data);
512
513 return r;
514 },
@@ -510,12 +531,12 @@
531 if(NETDATA.globalPanAndZoom.isMaster(this))
532 NETDATA.globalPanAndZoom.clearMaster();
533
513 - if(state.mode.name != 'auto')
534 + if(state.current.name != 'auto')
535 this.setMode('auto');
536
516 - this.mode.force_before_ms = null;
517 - this.mode.force_after_ms = null;
518 - this.mode.last_updated_ms = 0;
537 + this.current.force_before_ms = null;
538 + this.current.force_after_ms = null;
539 + this.current.last_updated_ms = 0;
540 this.follows_global = 0;
541 this.paused = false;
542 this.selected = false;
@@ -526,44 +547,45 @@
547 // or the chart will flip-flop when it is the master
548 // of a selection sync and another chart becomes
549 // the new master
529 - // state.updateChart();
550 + if(!NETDATA.options.current.sync_pan_and_zoom)
551 + state.updateChart();
552 },
553
554 setMode: function(m) {
533 - if(this.mode) {
534 - if(this.mode.name == m) return;
535 -
536 - this[m].url = this.mode.url;
537 - this[m].last_updated_ms = this.mode.last_updated_ms;
538 - this[m].view_update_every = this.mode.view_update_every;
539 - this[m].after_ms = this.mode.after_ms;
540 - this[m].before_ms = this.mode.before_ms;
541 - this[m].points = this.mode.points;
542 - this[m].data = this.mode.data;
543 - this[m].requested_before_ms = this.mode.requested_before_ms;
544 - this[m].requested_after_ms = this.mode.requested_after_ms;
545 - this[m].first_entry_ms = this.mode.first_entry_ms;
546 - this[m].last_entry_ms = this.mode.last_entry_ms;
555 + if(this.current) {
556 + if(this.current.name == m) return;
557 +
558 + this[m].url = this.current.url;
559 + this[m].last_updated_ms = this.current.last_updated_ms;
560 + this[m].view_update_every = this.current.view_update_every;
561 + this[m].after_ms = this.current.after_ms;
562 + this[m].before_ms = this.current.before_ms;
563 + this[m].points = this.current.points;
564 + this[m].data = this.current.data;
565 + this[m].requested_before_ms = this.current.requested_before_ms;
566 + this[m].requested_after_ms = this.current.requested_after_ms;
567 + this[m].first_entry_ms = this.current.first_entry_ms;
568 + this[m].last_entry_ms = this.current.last_entry_ms;
569 }
570
571 if(m == 'auto')
550 - this.mode = this.auto;
572 + this.current = this.auto;
573 else if(m == 'pan')
552 - this.mode = this.pan;
574 + this.current = this.pan;
575 else if(m == 'zoom')
554 - this.mode = this.zoom;
576 + this.current = this.zoom;
577 else
556 - this.mode = this.auto;
578 + this.current = this.auto;
579
558 - this.mode.force_before_ms = null;
559 - this.mode.force_after_ms = null;
580 + this.current.force_before_ms = null;
581 + this.current.force_after_ms = null;
582
561 - if(this.debug) this.log('mode set to ' + this.mode.name);
583 + if(this.debug) this.log('mode set to ' + this.current.name);
584 },
585
586 _minPanOrZoomStep: function() {
565 - return (((this.mode.before_ms - this.mode.after_ms) / this.mode.points) * ((this.mode.points * 5 / 100) + 1) );
566 - // return this.mode.view_update_every * 10;
587 + return (((this.current.before_ms - this.current.after_ms) / this.current.points) * ((this.current.points * 5 / 100) + 1) );
588 + // return this.current.view_update_every * 10;
589 },
590
591 _shouldBeMoved: function(old_after, old_before, new_after, new_before) {
@@ -576,8 +598,8 @@
598 var step = Math.max(dt_after, dt_before, dt);
599
600 var min_step = this._minPanOrZoomStep();
579 - if(new_range < old_range && new_range / this.calculated_width < 100) {
580 - 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.calculated_width / 1000).toString() + ': TOO SMALL RANGE');
601 + if(new_range < old_range && new_range / this.chartWidth() < 100) {
602 + 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');
603 return false;
604 }
605
@@ -594,21 +616,21 @@
616 updateChartPanOrZoom: function(after, before, callback) {
617 var move = false;
618
597 - if(this.mode.name == 'auto') {
619 + if(this.current.name == 'auto') {
620 if(this.debug) this.log('updateChartPanOrZoom(): caller did not set proper mode');
621 this.setMode('pan');
622 }
623
602 - if(!this.mode.force_after_ms || !this.mode.force_before_ms) {
624 + if(!this.current.force_after_ms || !this.current.force_before_ms) {
625 if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): INIT');
626 move = true;
627 }
606 - else if(this._shouldBeMoved(this.mode.force_after_ms, this.mode.force_before_ms, after, before) && this._shouldBeMoved(this.mode.after_ms, this.mode.before_ms, after, before)) {
607 - if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): FORCE CHANGE from ' + (this.mode.force_after_ms / 1000).toString() + ' - ' + (this.mode.force_before_ms / 1000).toString());
628 + 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)) {
629 + 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());
630 move = true;
631 }
610 - else if(this._shouldBeMoved(this.mode.requested_after_ms, this.mode.requested_before_ms, after, before) && this._shouldBeMoved(this.mode.after_ms, this.mode.before_ms, after, before)) {
611 - if(this.debug) this.log('updateChartPanOrZoom(' + (after / 1000).toString() + ' - ' + (before / 1000).toString() + '): REQUESTED CHANGE from ' + (this.mode.requested_after_ms / 1000).toString() + ' - ' + (this.mode.requested_before_ms / 1000).toString());
632 + 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)) {
633 + 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());
634 move = true;
635 }
636
@@ -617,8 +639,8 @@
639 NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.global_pan_sync_time;
640 NETDATA.globalPanAndZoom.setMaster(this, after, before);
641
620 - this.mode.force_after_ms = after;
621 - this.mode.force_before_ms = before;
642 + this.current.force_after_ms = after;
643 + this.current.force_before_ms = before;
644 this.updateChart(callback);
645 return true;
646 }
@@ -628,6 +650,216 @@
650 return false;
651 },
652
653 + createChartDOM: function() {
654 + this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
655 + var html = '<div class="netdata-chart netdata-'
656 + + this.library_name + '-chart" id="'
657 + + this.element_chart_id
658 + + '"style="width: 100%; height: 100%;"></div>';
659 +// + '"style="width: ' + this.chartWidth().toString() + 'px; height: ' + this.chartHeight().toString() + 'px;"></div>';
660 +
661 + if(this.hasLegend()) {
662 + this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
663 + html += '<div class="netdata-chart-legend netdata-'
664 + + this.library_name + '-legend" id="'
665 + + this.element_legend_id
666 + + '" style="width: ' + this.legendWidth().toString() + 'px; height: ' + this.legendHeight() + 'px;"></div>';
667 + }
668 +
669 + element.innerHTML = html;
670 + this.element_chart = document.getElementById(this.element_chart_id);
671 + $(this.element_chart).data('netdata-state-object', this);
672 +
673 + if(this.hasLegend()) {
674 + this.element_legend = document.getElementById(this.element_legend_id);
675 + $(this.element_legend).data('netdata-state-object', this);
676 + }
677 + },
678 +
679 + hasLegend: function() {
680 + // return (this.library && this.library.legend == 'right-side');
681 + return false;
682 + },
683 +
684 + legendWidth: function() {
685 + return (this.hasLegend())?55:0;
686 + },
687 +
688 + legendHeight: function() {
689 + return $(this.element).height();
690 + },
691 +
692 + chartWidth: function() {
693 + return $(this.element).width() - this.legendWidth();
694 + },
695 +
696 + chartHeight: function() {
697 + return $(this.element).height();
698 + },
699 +
700 + chartPixelsPerPoint: function() {
701 + // force an options provided detail
702 + var px = this.pixels_per_point;
703 +
704 + if(this.library && px < this.library.pixels_per_point)
705 + px = this.library.pixels_per_point;
706 +
707 + if(px < NETDATA.options.current.pixels_per_point)
708 + px = NETDATA.options.current.pixels_per_point;
709 +
710 + return px;
711 + },
712 +
713 + needsResize: function() {
714 + return (this.last_resized < NETDATA.options.last_resized);
715 + },
716 +
717 + resizeChart: function() {
718 + if(this.needsResize()) {
719 + if(this.library && !this.library.autoresize) {
720 + if(this.debug) this.log('forcing re-generation due to window resize.');
721 + this.created_ms = 0;
722 + this.last_resized = new Date().getTime();
723 + }
724 + }
725 + },
726 +
727 + chartURL: function() {
728 + var before;
729 + var after;
730 + if(NETDATA.globalPanAndZoom.isActive()) {
731 + after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
732 + before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
733 + this.follows_global = NETDATA.globalPanAndZoom.seq;
734 + }
735 + else {
736 + before = this.current.force_before_ms != null ? Math.round(this.current.force_before_ms / 1000) : this.before;
737 + after = this.current.force_after_ms != null ? Math.round(this.current.force_after_ms / 1000) : this.after;
738 + this.follows_global = 0;
739 + }
740 +
741 + this.current.requested_after_ms = after * 1000;
742 + this.current.requested_before_ms = before * 1000;
743 +
744 + this.current.points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint());
745 +
746 + // build the data URL
747 + this.current.url = this.chart.data_url;
748 + this.current.url += "&format=" + this.library.format;
749 + this.current.url += "&points=" + this.current.points.toString();
750 + this.current.url += "&group=" + this.method;
751 + this.current.url += "&options=" + this.library.options;
752 + if(this.library.jsonWrapper) this.current.url += '|jsonwrap';
753 +
754 + if(after)
755 + this.current.url += "&after=" + after.toString();
756 +
757 + if(before)
758 + this.current.url += "&before=" + before.toString();
759 +
760 + if(this.dimensions)
761 + this.current.url += "&dimensions=" + this.dimensions;
762 +
763 + 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);
764 + },
765 +
766 + updateChartWithData: function(data) {
767 + if(this.debug) this.log('got data from netdata server');
768 + this.current.data = data;
769 +
770 + var started = new Date().getTime();
771 +
772 + // if the result is JSON, find the latest update-every
773 + if(typeof data == 'object' && this.library.jsonWrapper) {
774 + if(!this.follows_global && typeof data.view_update_every != 'undefined')
775 + this.current.view_update_every = data.view_update_every * 1000;
776 +
777 + if(typeof data.after != 'undefined')
778 + this.current.after_ms = data.after * 1000;
779 +
780 + if(typeof data.before != 'undefined')
781 + this.current.before_ms = data.before * 1000;
782 +
783 + if(typeof data.first_entry_t != 'undefined')
784 + this.current.first_entry_ms = data.first_entry_t * 1000;
785 +
786 + if(typeof data.last_entry_t != 'undefined')
787 + this.current.last_entry_ms = data.last_entry_t * 1000;
788 +
789 + if(typeof data.points != 'undefined')
790 + this.current.points = data.points;
791 +
792 + data.state = this;
793 + }
794 +
795 + this.updates_counter++;
796 +
797 + if(this.debug) {
798 + this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
799 +
800 + if(this.current.force_after_ms)
801 + this.log('STATUS: forced : ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
802 + else
803 + this.log('STATUS: forced: unset');
804 +
805 + this.log('STATUS: requested: ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
806 + this.log('STATUS: rendered : ' + (this.current.after_ms / 1000).toString() + ' - ' + (this.current.before_ms / 1000).toString());
807 + this.log('STATUS: points : ' + (this.current.points).toString() + ', min step: ' + (this._minPanOrZoomStep() / 1000).toString());
808 + }
809 +
810 + // this may force the chart to be re-created
811 + this.resizeChart();
812 + if(this.updates_since_last_creation >= this.library.max_updates_to_recreate) {
813 + if(this.debug) this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
814 + this.created_ms = 0;
815 + }
816 +
817 + if(this.created_ms && typeof this.library.update == 'function') {
818 + if(this.debug) this.log('updating chart...');
819 +
820 + this.updates_since_last_creation++;
821 + if(NETDATA.options.debug.chart_errors) {
822 + this.library.update(this, data);
823 + }
824 + else {
825 + try {
826 + this.library.update(this, data);
827 + }
828 + catch(err) {
829 + this.error('chart "' + this.id + '" failed to be updated as ' + this.library_name);
830 + }
831 + }
832 + }
833 + else {
834 + if(this.debug) this.log('creating chart...');
835 +
836 + this.createChartDOM();
837 + this.updates_since_last_creation = 0;
838 +
839 + if(NETDATA.options.debug.chart_errors) {
840 + this.library.create(this, data);
841 + this.created_ms = new Date().getTime();
842 + }
843 + else {
844 + try {
845 + this.library.create(this, data);
846 + this.created_ms = new Date().getTime();
847 + }
848 + catch(err) {
849 + this.error('chart "' + this.id + '" failed to be created as ' + this.library_name);
850 + }
851 + }
852 + }
853 +
854 + // update the performance counters
855 + this.current.last_updated_ms = new Date().getTime();
856 + this.refresh_dt_ms = this.current.last_updated_ms - started;
857 + NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
858 +
859 + if(this.refresh_dt_element)
860 + this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
861 + },
862 +
863 updateChart: function(callback) {
864 if(!this.library || !this.library.enabled) {
865 this.error('charting library "' + this.library_name + '" is not available');
@@ -641,7 +873,7 @@
873 return;
874 }
875
644 - if(!self.visible(true)) {
876 + if(!this.isVisible()) {
877 if(NETDATA.options.debug.visibility || this.debug) this.log('is not visible');
878 if(typeof callback != 'undefined') callback();
879 return;
@@ -660,159 +892,33 @@
892
893 this.clearSelection();
894 this.chartURL();
663 - if(this.debug) this.log('updating from ' + this.mode.url);
895 + if(this.debug) this.log('updating from ' + this.current.url);
896
897 var this_state_object = this;
898 $.ajax( {
667 - url: this_state_object.mode.url,
899 + url: this.current.url,
900 crossDomain: true
901 })
902 .then(function(data) {
671 - if(this_state_object.debug) this_state_object.log('got data from netdata server');
672 - this_state_object.mode.data = data;
673 -
674 - var started = new Date().getTime();
675 -
676 - // if the result is JSON, find the latest update-every
677 - if(typeof data == 'object' && this_state_object.library.jsonWrapper) {
678 - if(!this_state_object.follows_global && typeof data.view_update_every != 'undefined')
679 - this_state_object.mode.view_update_every = data.view_update_every * 1000;
680 -
681 - if(typeof data.after != 'undefined')
682 - this_state_object.mode.after_ms = data.after * 1000;
683 -
684 - if(typeof data.before != 'undefined')
685 - this_state_object.mode.before_ms = data.before * 1000;
686 -
687 - if(typeof data.first_entry_t != 'undefined')
688 - this_state_object.mode.first_entry_ms = data.first_entry_t * 1000;
689 -
690 - if(typeof data.last_entry_t != 'undefined')
691 - this_state_object.mode.last_entry_ms = data.last_entry_t * 1000;
692 -
693 - if(typeof data.points != 'undefined')
694 - this_state_object.mode.points = data.points;
695 -
696 - data.state = this_state_object;
697 - }
698 -
699 - this_state_object.updates_counter++;
700 -
701 - if(this_state_object.debug) {
702 - this_state_object.log('UPDATE No ' + this_state_object.updates_counter + ' COMPLETED');
703 -
704 - if(this_state_object.mode.force_after_ms)
705 - this_state_object.log('STATUS: forced : ' + (this_state_object.mode.force_after_ms / 1000).toString() + ' - ' + (this_state_object.mode.force_before_ms / 1000).toString());
706 - else
707 - this_state_object.log('STATUS: forced: unset');
708 -
709 - this_state_object.log('STATUS: requested: ' + (this_state_object.mode.requested_after_ms / 1000).toString() + ' - ' + (this_state_object.mode.requested_before_ms / 1000).toString());
710 - this_state_object.log('STATUS: rendered : ' + (this_state_object.mode.after_ms / 1000).toString() + ' - ' + (this_state_object.mode.before_ms / 1000).toString());
711 - this_state_object.log('STATUS: points : ' + (this_state_object.mode.points).toString() + ', min step: ' + (this_state_object._minPanOrZoomStep() / 1000).toString());
712 - }
713 -
714 - if(this_state_object.created_ms) {
715 - if(this_state_object.debug) this_state_object.log('updating chart...');
716 -
717 - if(NETDATA.options.debug.chart_errors) {
718 - this_state_object.library.update(this_state_object.element, data);
719 - }
720 - else {
721 - try {
722 - this_state_object.library.update(this_state_object.element, data);
723 - }
724 - catch(err) {
725 - this_state_object.error('chart "' + state.id + '" failed to be updated as ' + state.library_name);
726 - }
727 - }
728 - }
729 - else {
730 - if(this_state_object.debug) this_state_object.log('creating chart...');
731 -
732 - if(NETDATA.options.debug.chart_errors) {
733 - this_state_object.library.create(this_state_object.element, data);
734 - this_state_object.created_ms = new Date().getTime();
735 - }
736 - else {
737 - try {
738 - this_state_object.library.create(this_state_object.element, data);
739 - this_state_object.created_ms = new Date().getTime();
740 - }
741 - catch(err) {
742 - this_state_object.error('chart "' + state.id + '" failed to be created as ' + state.library_name);
743 - }
744 - }
745 - }
746 -
747 - // update the performance counters
748 - this_state_object.mode.last_updated_ms = new Date().getTime();
749 - this_state_object.refresh_dt_ms = this_state_object.mode.last_updated_ms - started;
750 - NETDATA.options.auto_refresher_fast_weight += this_state_object.refresh_dt_ms;
751 -
752 - if(this_state_object.refresh_dt_element)
753 - this_state_object.refresh_dt_element.innerHTML = this_state_object.refresh_dt_ms.toString();
903 + this_state_object.updateChartWithData(data);
904 })
905 .fail(function() {
756 - this_state_object.error('cannot download chart from ' + this_state_object.mode.url);
906 + this_state_object.error('cannot download chart from ' + this_state_object.current.url);
907 })
908 .always(function() {
909 if(typeof callback == 'function') callback();
910 });
911 },
912
763 - chartURL: function() {
764 - this.calculated_width = self.width();
765 - this.calculated_height = self.height();
766 -
767 - var before;
768 - var after;
769 - if(NETDATA.globalPanAndZoom.isActive()) {
770 - after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
771 - before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
772 - this.follows_global = NETDATA.globalPanAndZoom.seq;
773 - }
774 - else {
775 - before = this.mode.force_before_ms != null ? Math.round(this.mode.force_before_ms / 1000) : this.before;
776 - after = this.mode.force_after_ms != null ? Math.round(this.mode.force_after_ms / 1000) : this.after;
777 - this.follows_global = 0;
778 - }
779 -
780 - this.mode.requested_after_ms = after * 1000;
781 - this.mode.requested_before_ms = before * 1000;
782 -
783 - // force an options provided detail
784 - var pixels_per_point = this.pixels_per_point;
785 - if(pixels_per_point < NETDATA.options.current.pixels_per_point)
786 - pixels_per_point = NETDATA.options.current.pixels_per_point
787 -
788 - this.mode.points = this.points || Math.round(this.calculated_width / pixels_per_point);
789 -
790 - // build the data URL
791 - this.mode.url = this.chart.data_url;
792 - this.mode.url += "&format=" + this.library.format;
793 - this.mode.url += "&points=" + this.mode.points.toString();
794 - this.mode.url += "&group=" + this.method;
795 - this.mode.url += "&options=" + this.library.options;
796 - if(this.library.jsonWrapper) this.mode.url += '|jsonwrap';
797 -
798 - if(after)
799 - this.mode.url += "&after=" + after.toString();
800 -
801 - if(before)
802 - this.mode.url += "&before=" + before.toString();
803 -
804 - if(this.dimensions)
805 - this.mode.url += "&dimensions=" + this.dimensions;
806 -
807 - if(NETDATA.options.debug.chart_data_url) this.log('chartURL(): ' + this.mode.url + ' WxH:' + this.calculated_width + 'x' + this.calculated_height + ' points: ' + this.mode.points + ' library: ' + this.library_name);
808 - },
809 -
913 isVisible: function() {
811 - return self.visible(true);
914 + if(NETDATA.options.current.update_only_visible)
915 + return $(this.element).visible(true);
916 + else
917 + return true;
918 },
919
920 isAutoRefreshed: function() {
815 - return this.mode.autorefresh;
921 + return this.current.autorefresh;
922 },
923
924 canBeAutoRefreshed: function() {
@@ -852,7 +958,7 @@
958 return false;
959 }
960
855 - if(now - this.mode.last_updated_ms > this.mode.view_update_every) {
961 + if(now - this.current.last_updated_ms > this.current.view_update_every) {
962 if(this.debug) this.log('canBeAutoRefreshed(): It is time to update me.');
963 return true;
964 }
@@ -863,34 +969,42 @@
969 },
970
971 autoRefresh: function(callback) {
866 - if(this.canBeAutoRefreshed())
972 + if(this.canBeAutoRefreshed()) {
973 this.updateChart(callback);
868 - else if(typeof callback != 'undefined')
869 - callback();
974 + }
975 + else {
976 + if(typeof callback != 'undefined')
977 + callback();
978 + }
979 + },
980 +
981 + _defaultsFromDownloadedChart: function(chart) {
982 + this.chart = chart;
983 + this.chart_url = chart.url;
984 + this.current.view_update_every = chart.update_every * 1000;
985 + this.current.points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
986 },
987
988 // fetch the chart description from the netdata server
989 getChart: function(callback) {
990 this.chart = NETDATA.chartRegistry.get(this.host, this.id);
991 if(this.chart) {
992 + this._defaultsFromDownloadedChart(this.chart);
993 if(typeof callback == 'function') callback();
994 }
995 else {
996 this.chart_url = this.host + "/api/v1/chart?chart=" + this.id;
997 if(this.debug) this.log('downloading ' + this.chart_url);
881 - this_state_object = this;
998 + var this_state_object = this;
999
1000 $.ajax( {
1001 url: this.chart_url,
1002 crossDomain: true
1003 })
1004 .done(function(chart) {
888 - chart.data_url = (this_state_object.host + chart.data_url);
889 - this_state_object.chart = chart;
890 - this_state_object.mode.view_update_every = chart.update_every * 1000;
891 - this_state_object.mode.points = Math.round(self.width() / (chart.update_every / 1000));
892 -
1005 chart.url = this_state_object.chart_url;
1006 + chart.data_url = (this_state_object.host + chart.data_url);
1007 + this_state_object._defaultsFromDownloadedChart(chart);
1008 NETDATA.chartRegistry.add(this_state_object.host, this_state_object.id, chart);
1009 })
1010 .fail(function() {
@@ -911,17 +1025,17 @@
1025 if(this.debug) this.log('sizing element');
1026
1027 if(this.width)
914 - self.css('width', this.width);
1028 + $(this.element).css('width', this.width);
1029
1030 if(this.height)
917 - self.css('height', this.height);
1031 + $(this.element).css('height', this.height);
1032
1033 // these should be left to css
920 - //self.css('display', 'inline-block')
921 - //self.css('overflow', 'hidden');
1034 + //$(this.element).css('display', 'inline-block')
1035 + //$(this.element).css('overflow', 'hidden');
1036
1037 if(NETDATA.chartDefaults.min_width)
924 - self.css('min-width', NETDATA.chartDefaults.min_width);
1038 + $(this.element).css('min-width', NETDATA.chartDefaults.min_width);
1039 },
1040
1041 // show a message in the chart
@@ -968,10 +1082,8 @@
1082 NETDATA.error(403, this.library_name);
1083 this.error('chart library "' + this.library_name + '" is not enabled');
1084 }
971 - else {
1085 + else
1086 this.library = NETDATA.chartLibraries[this.library_name];
973 - this.pixels_per_point = self.data('pixels-per-point') || this.library.pixels_per_point;
974 - }
1087
1088 // if we need to report the rendering speed
1089 // find the element that needs to be updated
@@ -989,11 +1101,10 @@
1101
1102 // get or create a chart state, given a DOM element
1103 NETDATA.chartState = function(element) {
992 - self = $(element);
993 - var state = self.data('state') || null;
1104 + var state = $(element).data('netdata-state-object') || null;
1105 if(!state) {
1106 state = NETDATA.chartInitialState(element);
996 - self.data('state', state);
1107 + $(element).data('netdata-state-object', state);
1108 }
1109 return state;
1110 }
@@ -1081,7 +1192,6 @@
1192
1193 return;
1194 }
1084 -
1195 var target = NETDATA.options.targets.get(index);
1196 if(target == null) {
1197 if(NETDATA.options.debug.main_loop) console.log('waiting to restart main loop...');
@@ -1183,21 +1293,17 @@
1293 }
1294 };
1295
1186 - NETDATA.peityChartUpdate = function(element, data) {
1187 - var peity = $(data.state.peity_element);
1188 - peity.html(data.result);
1189 - // peity.change() does not accept options
1296 + NETDATA.peityChartUpdate = function(state, data) {
1297 + $(state.element_chart).html(data.result);
1298 + // $(state.element_chart).change() does not accept options
1299 // to pass width and height
1191 - //peity.change();
1192 - peity.peity('line', { width: data.state.calculated_width, height: data.state.calculated_height });
1300 + //$(state.element_chart).change();
1301 + $(state.element_chart).peity('line', { width: state.chartWidth(), height: state.chartHeight() });
1302 }
1303
1195 - NETDATA.peityChartCreate = function(element, data) {
1196 - element.innerHTML = '<div class="netdata-chart-container netdata-peity-container" id="peity-' + data.state.uuid + '">' + data.result + '</div>';
1197 - data.state.peity_element = document.getElementById('peity-' + data.state.uuid);
1198 - var peity = $(data.state.peity_element);
1199 -
1200 - peity.peity('line', { width: data.state.calculated_width, height: data.state.calculated_height });
1304 + NETDATA.peityChartCreate = function(state, data) {
1305 + $(state.element_chart).html(data.result);
1306 + $(state.element_chart).peity('line', { width: state.chartWidth(), height: state.chartHeight() });
1307 }
1308
1309 // ----------------------------------------------------------------------------------------------------------------
@@ -1224,19 +1330,18 @@
1330 }
1331 };
1332
1227 - NETDATA.sparklineChartUpdate = function(element, data) {
1228 - data.state.sparkline_options.width = data.state.calculated_width;
1229 - data.state.sparkline_options.height = data.state.calculated_height;
1333 + NETDATA.sparklineChartUpdate = function(state, data) {
1334 + state.sparkline_options.width = state.chartWidth();
1335 + state.sparkline_options.height = state.chartHeight();
1336
1231 - spark = $(data.state.sparkline_element);
1232 - spark.sparkline(data.result, data.state.sparkline_options);
1337 + $(state.element_chart).sparkline(data.result, state.sparkline_options);
1338 }
1339
1235 - NETDATA.sparklineChartCreate = function(element, data) {
1236 - var self = $(element);
1340 + NETDATA.sparklineChartCreate = function(state, data) {
1341 + var self = $(state.element);
1342 var type = self.data('sparkline-type') || 'line';
1343 var lineColor = self.data('sparkline-linecolor') || NETDATA.colors[0];
1239 - var fillColor = self.data('sparkline-fillcolor') || (data.state.chart.chart_type == 'line')?'#FFF':NETDATA.ColorLuminance(lineColor, NETDATA.chartDefaults.fill_luminance);
1344 + var fillColor = self.data('sparkline-fillcolor') || (state.chart.chart_type == 'line')?'#FFF':NETDATA.ColorLuminance(lineColor, NETDATA.chartDefaults.fill_luminance);
1345 var chartRangeMin = self.data('sparkline-chartrangemin') || undefined;
1346 var chartRangeMax = self.data('sparkline-chartrangemax') || undefined;
1347 var composite = self.data('sparkline-composite') || undefined;
@@ -1270,7 +1375,7 @@
1375 var tooltipClassname = self.data('sparkline-tooltipclassname') || undefined;
1376 var tooltipFormat = self.data('sparkline-tooltipformat') || undefined;
1377 var tooltipPrefix = self.data('sparkline-tooltipprefix') || undefined;
1273 - var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + data.state.chart.units;
1378 + var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + state.chart.units;
1379 var tooltipSkipNull = self.data('sparkline-tooltipskipnull') || true;
1380 var tooltipValueLookups = self.data('sparkline-tooltipvaluelookups') || undefined;
1381 var tooltipFormatFieldlist = self.data('sparkline-tooltipformatfieldlist') || undefined;
@@ -1281,7 +1386,7 @@
1386 var numberDigitGroupCount = self.data('sparkline-numberdigitgroupcount') || undefined;
1387 var animatedZooms = self.data('sparkline-animatedzooms') || false;
1388
1284 - data.state.sparkline_options = {
1389 + state.sparkline_options = {
1390 type: type,
1391 lineColor: lineColor,
1392 fillColor: fillColor,
@@ -1315,7 +1420,7 @@
1420 highlightColor: highlightColor,
1421 tooltipContainer: tooltipContainer,
1422 tooltipClassname: tooltipClassname,
1318 - tooltipChartTitle: data.state.chart.title,
1423 + tooltipChartTitle: state.chart.title,
1424 tooltipFormat: tooltipFormat,
1425 tooltipPrefix: tooltipPrefix,
1426 tooltipSuffix: tooltipSuffix,
@@ -1328,15 +1433,11 @@
1433 numberDecimalMark: numberDecimalMark,
1434 numberDigitGroupCount: numberDigitGroupCount,
1435 animatedZooms: animatedZooms,
1331 - width: data.state.calculated_width,
1332 - height: data.state.calculated_height
1436 + width: state.chartWidth(),
1437 + height: state.chartHeight()
1438 };
1439
1335 - element.innerHTML = '<div class="netdata-chart-container netdata-sparkline-container" id="sparkline-' + data.state.uuid + '" style="display: inline-block; position: relative;"></div>';
1336 - data.state.sparkline_element = document.getElementById('sparkline-' + data.state.uuid);
1337 -
1338 - spark = $(data.state.sparkline_element);
1339 - spark.sparkline(data.result, data.state.sparkline_options);
1440 + $(state.element_chart).sparkline(data.result, state.sparkline_options);
1441 };
1442
1443 // ----------------------------------------------------------------------------------------------------------------
@@ -1350,6 +1451,7 @@
1451 };
1452
1453 NETDATA.dygraph.syncStart = function(state, event, x, points, row, seriesName) {
1454 + if(!NETDATA.options.current.sync_selection) return;
1455 if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStart()');
1456
1457 //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
@@ -1358,12 +1460,12 @@
1460 //}
1461 // state.debug = true;
1462
1361 - var t = state.mode.after_ms + row * state.mode.view_update_every;
1463 + var t = state.current.after_ms + row * state.current.view_update_every;
1464 // console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t == x)?'SAME':'DIFFERENT'));
1465
1466 now = new Date().getTime();
1467 if(now < NETDATA.dygraph.dont_sync_before) {
1366 - if(state.debug) st.log('sync: cannot sync yet.');
1468 + if(state.debug) state.log('sync: cannot sync yet.');
1469 return;
1470 }
1471
@@ -1374,7 +1476,7 @@
1476 var dygraph = state.dygraph_instance;
1477
1478 if(!NETDATA.dygraph.sync) {
1377 - if(state.debug) st.log('sync: setting up...');
1479 + if(state.debug) state.log('sync: setting up...');
1480 $.each(NETDATA.options.targets, function(i, target) {
1481 var st = NETDATA.chartState(target);
1482 if(st == state) {
@@ -1402,6 +1504,8 @@
1504 }
1505
1506 NETDATA.dygraph.syncStop = function(state) {
1507 + if(!NETDATA.options.current.sync_selection) return;
1508 +
1509 if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraph.syncStop()');
1510
1511 //if(NETDATA.dygraph.state && NETDATA.dygraph.state != state) {
@@ -1437,10 +1541,9 @@
1541 if(NETDATA.globalPanAndZoom.clearMaster());
1542 }
1543
1440 - NETDATA.dygraph.zoomOrPan = function(element, dygraph, after, before) {
1441 - if(NETDATA.options.debug.dygraph) console.log('>>>> dygraph.zoomOrPan(element, dygraph, after:' + after + ', before: ' + before + ')');
1544 + NETDATA.dygraph.chartPanOrZoom = function(state, dygraph, after, before) {
1545 + if(NETDATA.options.debug.dygraph) console.log('>>>> dygraph.zoomOrPan(state, dygraph, after:' + after + ', before: ' + before + ')');
1546
1443 - state = NETDATA.chartState(element);
1547 state.updateChartPanOrZoom(after, before);
1548 return;
1549 }
@@ -1487,47 +1590,45 @@
1590 }
1591 };
1592
1490 - NETDATA.dygraphChartUpdate = function(element, data) {
1491 - if(NETDATA.options.debug.dygraph || data.state.debug) console.log('dygraphChartUpdate()');
1492 -
1493 - var dygraph = data.state.dygraph_instance;
1593 + NETDATA.dygraphChartUpdate = function(state, data) {
1594 + var dygraph = state.dygraph_instance;
1595
1495 - if(data.state.mode.name == 'pan') {
1496 - if(NETDATA.options.debug.dygraph || data.state.debug) console.log('dygraphChartUpdate() loose update');
1596 + if(state.current.name == 'pan') {
1597 + if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartUpdate() loose update');
1598 dygraph.updateOptions({
1599 file: data.result.data,
1600 labels: data.result.labels,
1500 - labelsDivWidth: data.state.calculated_width - 70
1601 + labelsDivWidth: state.chartWidth() - 70
1602 });
1603 }
1604 else {
1504 - if(NETDATA.options.debug.dygraph || data.state.debug) console.log('dygraphChartUpdate() strict update');
1605 + if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartUpdate() strict update');
1606 dygraph.updateOptions({
1607 file: data.result.data,
1608 labels: data.result.labels,
1508 - labelsDivWidth: data.state.calculated_width - 70,
1609 + labelsDivWidth: state.chartWidth() - 70,
1610 dateWindow: null,
1611 valueRange: null
1612 });
1613 }
1614 };
1615
1515 - NETDATA.dygraphChartCreate = function(element, data) {
1516 - if(NETDATA.options.debug.dygraph || data.state.debug) console.log('dygraphChartCreate()');
1616 + NETDATA.dygraphChartCreate = function(state, data) {
1617 + if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartCreate()');
1618
1518 - var self = $(element);
1519 - var title = self.data('dygraph-title') || data.state.chart.title;
1619 + var self = $(state.element);
1620 + var title = self.data('dygraph-title') || state.chart.title;
1621 var titleHeight = self.data('dygraph-titleheight') || 19;
1622 var labelsDiv = self.data('dygraph-labelsdiv') || undefined;
1623 var connectSeparatedPoints = self.data('dygraph-connectseparatedpoints') || false;
1624 var yLabelWidth = self.data('dygraph-ylabelwidth') || 12;
1524 - var stackedGraph = self.data('dygraph-stackedgraph') || (data.state.chart.chart_type == 'stacked')?true:false;
1625 + var stackedGraph = self.data('dygraph-stackedgraph') || (state.chart.chart_type == 'stacked')?true:false;
1626 var stackedGraphNaNFill = self.data('dygraph-stackedgraphnanfill') || 'none';
1627 var hideOverlayOnMouseOut = self.data('dygraph-hideoverlayonmouseout') || true;
1527 - var fillGraph = self.data('dygraph-fillgraph') || (data.state.chart.chart_type == 'area')?true:false;
1628 + var fillGraph = self.data('dygraph-fillgraph') || (state.chart.chart_type == 'area')?true:false;
1629 var drawPoints = self.data('dygraph-drawpoints') || false;
1630 var labelsDivStyles = self.data('dygraph-labelsdivstyles') || { 'fontSize':'10px' };
1530 - var labelsDivWidth = self.data('dygraph-labelsdivwidth') || self.width() - 70;
1631 + var labelsDivWidth = self.data('dygraph-labelsdivwidth') || state.chartWidth() - 70;
1632 var labelsSeparateLines = self.data('dygraph-labelsseparatelines') || false;
1633 var labelsShowZeroValues = self.data('dygraph-labelsshowzerovalues') || true;
1634 var legend = self.data('dygraph-legend') || 'onmouseover';
@@ -1546,11 +1647,11 @@
1647 var pointSize = self.data('dygraph-pointsize') || 1;
1648 var stepPlot = self.data('dygraph-stepplot') || false;
1649 var strokeBorderColor = self.data('dygraph-strokebordercolor') || 'white';
1549 - var strokeBorderWidth = self.data('dygraph-strokeborderwidth') || (data.state.chart.chart_type == 'stacked')?0.1:0.0;
1650 + var strokeBorderWidth = self.data('dygraph-strokeborderwidth') || (state.chart.chart_type == 'stacked')?0.1:0.0;
1651 var strokePattern = self.data('dygraph-strokepattern') || undefined;
1652 var highlightCircleSize = self.data('dygraph-highlightcirclesize') || 3;
1653 var highlightSeriesOpts = self.data('dygraph-highlightseriesopts') || null; // TOO SLOW: { strokeWidth: 1.5 };
1553 - var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightseriesbackgroundalpha') || null; // TOO SLOW: (data.state.chart.chart_type == 'stacked')?0.7:0.5;
1654 + var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightseriesbackgroundalpha') || null; // TOO SLOW: (state.chart.chart_type == 'stacked')?0.7:0.5;
1655 var pointClickCallback = self.data('dygraph-pointclickcallback') || undefined;
1656 var showRangeSelector = self.data('dygraph-showrangeselector') || false;
1657 var showRoller = self.data('dygraph-showroller') || false;
@@ -1562,10 +1663,10 @@
1663 var gridLinePattern = self.data('dygraph-gridlinepattern') || null;
1664 var gridLineWidth = self.data('dygraph-gridlinewidth') || 0.3;
1665
1565 - data.state.dygraph_options = {
1666 + state.dygraph_options = {
1667 title: title,
1668 titleHeight: titleHeight,
1568 - ylabel: data.state.chart.units,
1669 + ylabel: state.chart.units,
1670 yLabelWidth: yLabelWidth,
1671 connectSeparatedPoints: connectSeparatedPoints,
1672 drawPoints: drawPoints,
@@ -1629,38 +1730,38 @@
1730 }
1731 },
1732 drawCallback: function(dygraph, is_initial) {
1632 - if(data.state.mode.name != 'auto') {
1633 - if(NETDATA.options.debug.dygraph) data.state.log('dygraphDrawCallback()');
1733 + if(state.current.name != 'auto') {
1734 + if(NETDATA.options.debug.dygraph) state.log('dygraphDrawCallback()');
1735
1736 var x_range = dygraph.xAxisRange();
1737 var after = Math.round(x_range[0]);
1738 var before = Math.round(x_range[1]);
1739
1639 - NETDATA.dygraph.zoomOrPan(element, this, after, before);
1740 + NETDATA.dygraph.chartPanOrZoom(state, this, after, before);
1741 }
1742 },
1743 zoomCallback: function(minDate, maxDate, yRanges) {
1643 - if(NETDATA.options.debug.dygraph) data.state.log('dygraphZoomCallback()');
1644 - NETDATA.dygraph.syncStop(data.state);
1645 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1646 - NETDATA.dygraph.zoomOrPan(element, this, minDate, maxDate);
1744 + if(NETDATA.options.debug.dygraph) state.log('dygraphZoomCallback()');
1745 + NETDATA.dygraph.syncStop(state);
1746 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1747 + NETDATA.dygraph.chartPanOrZoom(state, this, minDate, maxDate);
1748 },
1749 highlightCallback: function(event, x, points, row, seriesName) {
1649 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('dygraphHighlightCallback()');
1650 - data.state.pauseChart();
1651 - NETDATA.dygraph.syncStart(data.state, event, x, points, row, seriesName);
1750 + if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphHighlightCallback()');
1751 + state.pauseChart();
1752 + NETDATA.dygraph.syncStart(state, event, x, points, row, seriesName);
1753 },
1754 unhighlightCallback: function(event) {
1654 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('dygraphUnhighlightCallback()');
1655 - data.state.unpauseChart();
1656 - NETDATA.dygraph.syncStop(data.state);
1755 + if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphUnhighlightCallback()');
1756 + state.unpauseChart();
1757 + NETDATA.dygraph.syncStop(state);
1758 },
1759 interactionModel : {
1760 mousedown: function(event, dygraph, context) {
1660 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousedown()');
1661 - NETDATA.dygraph.syncStop(data.state);
1761 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousedown()');
1762 + NETDATA.dygraph.syncStop(state);
1763
1663 - if(NETDATA.options.debug.dygraph) data.state.log('dygraphMouseDown()');
1764 + if(NETDATA.options.debug.dygraph) state.log('dygraphMouseDown()');
1765
1766 // Right-click should not initiate a zoom.
1767 if(event.button && event.button == 2) return;
@@ -1669,79 +1770,79 @@
1770
1771 if(event.button && event.button == 1) {
1772 if (event.altKey || event.shiftKey) {
1672 - data.state.setMode('pan');
1673 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1773 + state.setMode('pan');
1774 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1775 Dygraph.startPan(event, dygraph, context);
1776 }
1777 else {
1677 - data.state.setMode('zoom');
1678 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1778 + state.setMode('zoom');
1779 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1780 Dygraph.startZoom(event, dygraph, context);
1781 }
1782 }
1783 else {
1784 if (event.altKey || event.shiftKey) {
1684 - data.state.setMode('zoom');
1685 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1785 + state.setMode('zoom');
1786 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1787 Dygraph.startZoom(event, dygraph, context);
1788 }
1789 else {
1689 - data.state.setMode('pan');
1690 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1790 + state.setMode('pan');
1791 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1792 Dygraph.startPan(event, dygraph, context);
1793 }
1794 }
1795 },
1796 mousemove: function(event, dygraph, context) {
1696 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousemove()');
1797 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousemove()');
1798
1799 if(context.isPanning) {
1699 - NETDATA.dygraph.syncStop(data.state);
1700 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1701 - data.state.setMode('pan');
1800 + NETDATA.dygraph.syncStop(state);
1801 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1802 + state.setMode('pan');
1803 Dygraph.movePan(event, dygraph, context);
1804 }
1805 else if(context.isZooming) {
1705 - NETDATA.dygraph.syncStop(data.state);
1706 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1707 - data.state.setMode('zoom');
1806 + NETDATA.dygraph.syncStop(state);
1807 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1808 + state.setMode('zoom');
1809 Dygraph.moveZoom(event, dygraph, context);
1810 }
1811 },
1812 mouseup: function(event, dygraph, context) {
1712 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mouseup()');
1813 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mouseup()');
1814
1815 if (context.isPanning) {
1715 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1816 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1817 Dygraph.endPan(event, dygraph, context);
1818 }
1819 else if (context.isZooming) {
1719 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1820 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1821 Dygraph.endZoom(event, dygraph, context);
1822 }
1823 },
1824 click: function(event, dygraph, context) {
1724 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.click()');
1825 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.click()');
1826 Dygraph.cancelEvent(event);
1827 },
1828 dblclick: function(event, dygraph, context) {
1728 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.dblclick()');
1729 - NETDATA.dygraph.syncStop(data.state);
1730 - NETDATA.dygraph.resetChart(data.state, dygraph, context);
1829 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.dblclick()');
1830 + NETDATA.dygraph.syncStop(state);
1831 + NETDATA.dygraph.resetChart(state, dygraph, context);
1832 },
1833 mousewheel: function(event, dygraph, context) {
1733 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.mousewheel()');
1834 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.mousewheel()');
1835
1735 - NETDATA.dygraph.syncStop(data.state);
1736 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1836 + NETDATA.dygraph.syncStop(state);
1837 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1838
1839 if(event.altKey || event.shiftKey) {
1840 // http://dygraphs.com/gallery/interaction-api.js
1841 var normal = (event.detail) ? event.detail * -1 : event.wheelDelta / 40;
1842 var percentage = normal / 25;
1843
1743 - var before_old = data.state.mode.before_ms;
1744 - var after_old = data.state.mode.after_ms;
1844 + var before_old = state.current.before_ms;
1845 + var after_old = state.current.after_ms;
1846 var range_old = before_old - after_old;
1847
1848 var range = range_old * ( 1 - percentage );
@@ -1750,37 +1851,35 @@
1851 var before = before_old - dt;
1852 var after = after_old + dt;
1853
1753 - 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());
1854 + 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());
1855
1755 - data.state.setMode('zoom');
1756 - NETDATA.dygraph.zoomOrPan(element, dygraph, after, before);
1856 + state.setMode('zoom');
1857 + NETDATA.dygraph.chartPanOrZoom(state, dygraph, after, before);
1858 }
1859 },
1860 touchstart: function(event, dygraph, context) {
1760 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchstart()');
1761 - NETDATA.dygraph.syncStop(data.state);
1762 - NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_delay;
1861 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.touchstart()');
1862 + NETDATA.dygraph.syncStop(state);
1863 + NETDATA.dygraph.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1864 Dygraph.Interaction.startTouch(event, dygraph, context);
1865 context.touchDirections = { x: true, y: false };
1765 - data.state.setMode('zoom');
1866 + state.setMode('zoom');
1867 },
1868 touchmove: function(event, dygraph, context) {
1768 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchmove()');
1869 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.touchmove()');
1870 //Dygraph.cancelEvent(event);
1770 - NETDATA.dygraph.syncStop(data.state);
1871 + NETDATA.dygraph.syncStop(state);
1872 Dygraph.Interaction.moveTouch(event, dygraph, context);
1873 },
1874 touchend: function(event, dygraph, context) {
1774 - if(NETDATA.options.debug.dygraph || data.state.debug) data.state.log('interactionModel.touchend()');
1875 + if(NETDATA.options.debug.dygraph || state.debug) state.log('interactionModel.touchend()');
1876 Dygraph.Interaction.endTouch(event, dygraph, context);
1877 }
1878 }
1879 };
1880
1780 - self.html('<div class="netdata-chart-container netdata-dygraph-container" id="dygraph-' + data.state.uuid + '" style="width: 100%; height: 100%;"></div>');
1781 -
1782 - data.state.dygraph_instance = new Dygraph(document.getElementById('dygraph-' + data.state.uuid),
1783 - data.result.data, data.state.dygraph_options);
1881 + state.dygraph_instance = new Dygraph(state.element_chart,
1882 + data.result.data, state.dygraph_options);
1883 };
1884
1885 // ----------------------------------------------------------------------------------------------------------------
@@ -1825,16 +1924,14 @@
1924 }
1925 };
1926
1828 - NETDATA.morrisChartUpdate = function(element, data) {
1829 - data.state.morris_instance.setData(data.result.data);
1927 + NETDATA.morrisChartUpdate = function(state, data) {
1928 + state.morris_instance.setData(data.result.data);
1929 };
1930
1832 - NETDATA.morrisChartCreate = function(element, data) {
1931 + NETDATA.morrisChartCreate = function(state, data) {
1932
1834 - element.innerHTML = '<div class="netdata-chart-container netdata-morris-container" id="morris-' + data.state.uuid + '" style="width: ' + data.state.calculated_width + 'px; height: ' + data.state.calculated_height + 'px;"></div>';
1835 -
1836 - var options = {
1837 - element: 'morris-' + data.state.uuid,
1933 + state.morris_options = {
1934 + element: state.element_chart_id,
1935 data: data.result.data,
1936 xkey: 'time',
1937 ykeys: data.dimension_names,
@@ -1848,19 +1945,15 @@
1945 behaveLikeLine: false
1946 };
1947
1851 - var morris;
1852 - if(data.state.chart.chart_type == 'line')
1853 - morris = new Morris.Line(options);
1948 + if(state.chart.chart_type == 'line')
1949 + state.morris_instance = new Morris.Line(state.morris_options);
1950
1855 - else if(data.state.chart.chart_type == 'area') {
1856 - options.behaveLikeLine = true;
1857 - morris = new Morris.Area(options);
1951 + else if(state.chart.chart_type == 'area') {
1952 + state.morris_options.behaveLikeLine = true;
1953 + state.morris_instance = new Morris.Area(state.morris_options);
1954 }
1955 else // stacked
1860 - morris = new Morris.Area(options);
1861 -
1862 - data.state.morris_instance = morris;
1863 - data.state.morris_options = options;
1956 + state.morris_instance = new Morris.Area(state.morris_options);
1957 };
1958
1959 // ----------------------------------------------------------------------------------------------------------------
@@ -1887,21 +1980,17 @@
1980 }
1981 };
1982
1890 - NETDATA.raphaelChartUpdate = function(element, data) {
1891 - var self = $(element);
1892 -
1893 - self.raphael(data, {
1894 - width: data.state.calculated_width,
1895 - height: data.state.calculated_height
1983 + NETDATA.raphaelChartUpdate = function(state, data) {
1984 + $(state.element_chart).raphael(data.result, {
1985 + width: state.chartWidth(),
1986 + height: state.chartHeight()
1987 })
1988 };
1989
1899 - NETDATA.raphaelChartCreate = function(element, data) {
1900 - var self = $(element);
1901 -
1902 - self.raphael(data, {
1903 - width: data.state.calculated_width,
1904 - height: data.state.calculated_height
1990 + NETDATA.raphaelChartCreate = function(state, data) {
1991 + $(state.element_chart).raphael(data.result, {
1992 + width: state.chartWidth(),
1993 + height: state.chartHeight()
1994 })
1995 };
1996
@@ -1932,20 +2021,20 @@
2021 }
2022 };
2023
1935 - NETDATA.googleChartUpdate = function(element, data) {
2024 + NETDATA.googleChartUpdate = function(state, data) {
2025 var datatable = new google.visualization.DataTable(data.result);
1937 - data.state.google_instance.draw(datatable, data.state.google_options);
2026 + state.google_instance.draw(datatable, state.google_options);
2027 };
2028
1940 - NETDATA.googleChartCreate = function(element, data) {
2029 + NETDATA.googleChartCreate = function(state, data) {
2030 var datatable = new google.visualization.DataTable(data.result);
2031
1943 - var options = {
2032 + state.google_options = {
2033 // do not set width, height - the chart resizes itself
1945 - //width: data.state.calculated_width,
1946 - //height: data.state.calculated_height,
2034 + //width: state.chartWidth(),
2035 + //height: state.chartHeight(),
2036 lineWidth: 1,
1948 - title: data.state.chart.title,
2037 + title: state.chart.title,
2038 fontSize: 11,
2039 hAxis: {
2040 // title: "Time of Day",
@@ -1961,7 +2050,7 @@
2050 }
2051 },
2052 vAxis: {
1964 - title: data.state.chart.units,
2053 + title: state.chart.units,
2054 viewWindowMode: 'pretty',
2055 minValue: -0.1,
2056 maxValue: 0.1,
@@ -2000,35 +2089,29 @@
2089 isStacked: false
2090 };
2091
2003 - element.innerHTML = '<div class="netdata-chart-container netdata-google-container" id="google-' + data.state.uuid + '" style="width: 100%; height: 100%;"></div>';
2004 -
2005 - var gchart;
2006 - switch(data.state.chart.chart_type) {
2092 + switch(state.chart.chart_type) {
2093 case "area":
2008 - options.vAxis.viewWindowMode = 'maximized';
2009 - gchart = new google.visualization.AreaChart(document.getElementById('google-' + data.state.uuid));
2094 + state.google_options.vAxis.viewWindowMode = 'maximized';
2095 + state.google_instance = new google.visualization.AreaChart(state.element_chart);
2096 break;
2097
2098 case "stacked":
2013 - options.isStacked = true;
2014 - options.areaOpacity = 0.85;
2015 - options.vAxis.viewWindowMode = 'maximized';
2016 - options.vAxis.minValue = null;
2017 - options.vAxis.maxValue = null;
2018 - gchart = new google.visualization.AreaChart(document.getElementById('google-' + data.state.uuid));
2099 + state.google_options.isStacked = true;
2100 + state.google_options.areaOpacity = 0.85;
2101 + state.google_options.vAxis.viewWindowMode = 'maximized';
2102 + state.google_options.vAxis.minValue = null;
2103 + state.google_options.vAxis.maxValue = null;
2104 + state.google_instance = new google.visualization.AreaChart(state.element_chart);
2105 break;
2106
2107 default:
2108 case "line":
2023 - options.lineWidth = 2;
2024 - gchart = new google.visualization.LineChart(document.getElementById('google-' + data.state.uuid));
2109 + state.google_options.lineWidth = 2;
2110 + state.google_instance = new google.visualization.LineChart(state.element_chart);
2111 break;
2112 }
2113
2028 - gchart.draw(datatable, options);
2029 -
2030 - data.state.google_instance = gchart;
2031 - data.state.google_options = options;
2114 + state.google_instance.draw(datatable, state.google_options);
2115 };
2116
2117 // ----------------------------------------------------------------------------------------------------------------
@@ -2046,6 +2129,9 @@
2129 format: 'json',
2130 options: 'ms|flip',
2131 jsonWrapper: true,
2132 + legend: 'right-side',
2133 + autoresize: true,
2134 + max_updates_to_recreate: 5000,
2135 pixels_per_point: 2,
2136 detects_dimensions_on_update: false
2137 },
@@ -2060,6 +2146,9 @@
2146 format: 'array',
2147 options: 'flip|abs',
2148 jsonWrapper: true,
2149 + legend: 'sparkline',
2150 + autoresize: false,
2151 + max_updates_to_recreate: 5000,
2152 pixels_per_point: 2,
2153 detects_dimensions_on_update: false
2154 },
@@ -2074,6 +2163,9 @@
2163 format: 'ssvcomma',
2164 options: 'null2zero|flip|abs',
2165 jsonWrapper: true,
2166 + legend: 'sparkline',
2167 + autoresize: false,
2168 + max_updates_to_recreate: 5000,
2169 pixels_per_point: 2,
2170 detects_dimensions_on_update: false
2171 },
@@ -2088,6 +2180,9 @@
2180 format: 'json',
2181 options: 'objectrows|ms',
2182 jsonWrapper: true,
2183 + legend: 'none',
2184 + autoresize: false,
2185 + max_updates_to_recreate: 50,
2186 pixels_per_point: 15,
2187 detects_dimensions_on_update: false
2188 },
@@ -2102,6 +2197,9 @@
2197 format: 'datatable',
2198 options: '',
2199 jsonWrapper: true,
2200 + legend: 'none',
2201 + autoresize: false,
2202 + max_updates_to_recreate: 300,
2203 pixels_per_point: 4,
2204 detects_dimensions_on_update: true
2205 },
@@ -2116,6 +2214,9 @@
2214 format: 'json',
2215 options: '',
2216 jsonWrapper: true,
2217 + legend: 'none',
2218 + autoresize: false,
2219 + max_updates_to_recreate: 1000,
2220 pixels_per_point: 1,
2221 detects_dimensions_on_update: false
2222 }