@cryptotaxi247 / netdata-1 / commits / c13350c4c

use intersectionObserver when available

Costa Tsaousis (ktsaou) committed Jan 14, 2018 at 00:56 UTC c13350c4c5dfa3f095d6133e3fc2c8d3e9c3bab9
1 file changed +177 -72
web/dashboard.js
+177 -72
@@ -287,7 +287,7 @@ var NETDATA = window.NETDATA || {};
287
288 pause: false, // when enabled we don't auto-refresh the charts
289
290 - targets: null, // an array of all the state objects that are
290 + targets: [], // an array of all the state objects that are
291 // currently active (independently of their
292 // viewport visibility)
293
@@ -374,7 +374,7 @@ var NETDATA = window.NETDATA || {};
374
375 pan_and_zoom_data_padding: true, // fetch more data for the master chart when panning or zooming
376
377 - update_only_visible: true, // enable or disable visibility management
377 + update_only_visible: true, // enable or disable visibility management / used for printing
378
379 parallel_refresher: (isSlowDevice() === false), // enable parallel refresh of charts
380
@@ -759,35 +759,27 @@ var NETDATA = window.NETDATA || {};
759
760 NETDATA.onscroll_updater_timeout_id = undefined;
761 NETDATA.onscroll_updater = function() {
762 - if(NETDATA.options.targets === null) return;
763 -
764 - //var start = Date.now();
765 -
766 - // console.log('onscroll_updater() begin');
767 -
762 NETDATA.globalSelectionSync.stop();
763
764 + if(NETDATA.options.abort_ajax_on_scroll === true)
765 + NETDATA.abort_all_refreshes();
766 +
767 // when the user scrolls he sees that we have
768 // hidden all the not-visible charts
769 // using this little function we try to switch
770 // the charts back to visible quickly
771
775 - if(NETDATA.options.abort_ajax_on_scroll === true)
776 - NETDATA.abort_all_refreshes();
777 -
778 - if(NETDATA.options.current.parallel_refresher === false) {
779 - var targets = NETDATA.options.targets;
780 - var len = targets.length;
772 + if(NETDATA.intersectionObserver.enabled() === false) {
773 + if (NETDATA.options.current.parallel_refresher === false) {
774 + var targets = NETDATA.options.targets;
775 + var len = targets.length;
776
782 - while (len--)
783 - if(targets[len].running === false)
784 - targets[len].isVisible();
777 + while (len--)
778 + if (targets[len].running === false)
779 + targets[len].isVisible();
780 + }
781 }
782
787 - //var end = Date.now();
788 - //var dt = end - start;
789 - // console.log('count = ' + targets.length + ', average = ' + Math.round(dt / targets.length).toString() + ', dt = ' + dt);
790 -
783 NETDATA.onscroll_end_delay();
784 };
785
@@ -2207,10 +2199,11 @@ var NETDATA = window.NETDATA || {};
2199 this.last_t = 0;
2200
2201 // find all slaves
2202 + var targets = NETDATA.intersectionObserver.targets();
2203 this.slaves = [];
2211 - var len = NETDATA.options.targets.length;
2204 + var len = targets.length;
2205 while(len--) {
2213 - var st = NETDATA.options.targets[len];
2206 + var st = targets[len];
2207 if (this.state !== st && st.globalSelectionSyncIsEligible() === true)
2208 this.slaves.push(st);
2209 }
@@ -2285,6 +2278,109 @@ var NETDATA = window.NETDATA || {};
2278 }
2279 };
2280
2281 + NETDATA.intersectionObserver = {
2282 + observer: null,
2283 + visible_targets: [],
2284 +
2285 + options: {
2286 + root: null,
2287 + rootMargin: "0px",
2288 + threshold: null
2289 + },
2290 +
2291 + enabled: function() {
2292 + return this.observer !== null;
2293 + },
2294 +
2295 + globalReset: function() {
2296 + if(this.observer !== null) {
2297 + this.visible_targets = [];
2298 + this.observer.disconnect();
2299 + this.init();
2300 + }
2301 + },
2302 +
2303 + targets: function() {
2304 + if(this.enabled() === true && this.visible_targets.length > 0)
2305 + return this.visible_targets;
2306 + else
2307 + return NETDATA.options.targets;
2308 + },
2309 +
2310 + switchChartVisibility: function() {
2311 + var old = this.__visibilityRatioOld;
2312 +
2313 + if(old !== this.__visibilityRatio) {
2314 + if (old === 0 && this.__visibilityRatio > 0)
2315 + this.unhideChart();
2316 + else if (old > 0 && this.__visibilityRatio === 0)
2317 + this.hideChart();
2318 +
2319 + this.__visibilityRatioOld = this.__visibilityRatio;
2320 + }
2321 + },
2322 +
2323 + handler: function(entries, observer) {
2324 + entries.forEach(function(entry) {
2325 + var state = NETDATA.chartState(entry.target);
2326 +
2327 + if(entry.intersectionRatio > 0) {
2328 + var idx = NETDATA.intersectionObserver.visible_targets.indexOf(state);
2329 + if(idx == -1)
2330 + NETDATA.intersectionObserver.visible_targets.push(state);
2331 + else if(state.__visibilityRatio === 0)
2332 + state.log("was not visible until now, but was already in visible_targets");
2333 + }
2334 + else {
2335 + var idx = NETDATA.intersectionObserver.visible_targets.indexOf(state);
2336 + if(idx > -1)
2337 + NETDATA.intersectionObserver.visible_targets.splice(idx, 1);
2338 + else if(state.__visibilityRatio > 0)
2339 + state.log("was visible, but not found in visible_targets");
2340 + }
2341 +
2342 + state.__visibilityRatio = entry.intersectionRatio;
2343 +
2344 + if(NETDATA.options.current.async_on_scroll === false) {
2345 + if(window.requestIdleCallback)
2346 + window.requestIdleCallback(function() {
2347 + NETDATA.intersectionObserver.switchChartVisibility.call(state);
2348 + }, {timeout: 100});
2349 + else
2350 + NETDATA.intersectionObserver.switchChartVisibility.call(state);
2351 + }
2352 + });
2353 + },
2354 +
2355 + observe: function(state) {
2356 + if(this.enabled() === true) {
2357 + state.__visibilityRatioOld = 0;
2358 + state.__visibilityRatio = 0;
2359 + this.observer.observe(state.element);
2360 +
2361 + state.isVisible = function() {
2362 + if(NETDATA.options.current.update_only_visible === false)
2363 + return true;
2364 +
2365 + NETDATA.intersectionObserver.switchChartVisibility.call(this);
2366 +
2367 + return this.__visibilityRatio > 0;
2368 + }
2369 + }
2370 + },
2371 +
2372 + init: function() {
2373 + try {
2374 + this.observer = new IntersectionObserver(this.handler, this.options);
2375 + }
2376 + catch(e) {
2377 + console.log("IntersectionObserver is not supported on this browser");
2378 + this.observer = null;
2379 + }
2380 + }
2381 + };
2382 + NETDATA.intersectionObserver.init();
2383 +
2384 // ----------------------------------------------------------------------------------------------------------------
2385 // Our state object, where all per-chart values are stored
2386
@@ -2715,86 +2811,86 @@ var NETDATA = window.NETDATA || {};
2811 };
2812
2813 // hide the chart, when it is not visible - called from isVisible()
2718 - var hideChart = function() {
2814 + this.hideChart = function() {
2815 // hide it, if it is not already hidden
2816 if(isHidden() === true) return;
2817
2722 - if(that.chart_created === true) {
2818 + if(this.chart_created === true) {
2819 if(NETDATA.options.current.show_help === true) {
2724 - if(that.element_legend_childs.toolbox !== null) {
2725 - if(that.debug === true)
2726 - that.log('hideChart(): hidding legend popovers');
2727 -
2728 - $(that.element_legend_childs.toolbox_left).popover('hide');
2729 - $(that.element_legend_childs.toolbox_reset).popover('hide');
2730 - $(that.element_legend_childs.toolbox_right).popover('hide');
2731 - $(that.element_legend_childs.toolbox_zoomin).popover('hide');
2732 - $(that.element_legend_childs.toolbox_zoomout).popover('hide');
2820 + if(this.element_legend_childs.toolbox !== null) {
2821 + if(this.debug === true)
2822 + this.log('hideChart(): hidding legend popovers');
2823 +
2824 + $(this.element_legend_childs.toolbox_left).popover('hide');
2825 + $(this.element_legend_childs.toolbox_reset).popover('hide');
2826 + $(this.element_legend_childs.toolbox_right).popover('hide');
2827 + $(this.element_legend_childs.toolbox_zoomin).popover('hide');
2828 + $(this.element_legend_childs.toolbox_zoomout).popover('hide');
2829 }
2830
2735 - if(that.element_legend_childs.resize_handler !== null)
2736 - $(that.element_legend_childs.resize_handler).popover('hide');
2831 + if(this.element_legend_childs.resize_handler !== null)
2832 + $(this.element_legend_childs.resize_handler).popover('hide');
2833
2738 - if(that.element_legend_childs.content !== null)
2739 - $(that.element_legend_childs.content).popover('hide');
2834 + if(this.element_legend_childs.content !== null)
2835 + $(this.element_legend_childs.content).popover('hide');
2836 }
2837
2838 if(NETDATA.options.current.destroy_on_hide === true) {
2743 - if(that.debug === true)
2744 - that.log('hideChart(): initializing chart');
2839 + if(this.debug === true)
2840 + this.log('hideChart(): initializing chart');
2841
2842 // we should destroy it
2843 init('force');
2844 }
2845 else {
2750 - if(that.debug === true)
2751 - that.log('hideChart(): hiding chart');
2846 + if(this.debug === true)
2847 + this.log('hideChart(): hiding chart');
2848
2849 showRendering();
2754 - that.element_chart.style.display = 'none';
2755 - that.element.style.willChange = 'auto';
2756 - if(that.element_legend !== null) that.element_legend.style.display = 'none';
2757 - if(that.element_legend_childs.toolbox !== null) that.element_legend_childs.toolbox.style.display = 'none';
2758 - if(that.element_legend_childs.resize_handler !== null) that.element_legend_childs.resize_handler.style.display = 'none';
2850 + this.element_chart.style.display = 'none';
2851 + this.element.style.willChange = 'auto';
2852 + if(this.element_legend !== null) this.element_legend.style.display = 'none';
2853 + if(this.element_legend_childs.toolbox !== null) this.element_legend_childs.toolbox.style.display = 'none';
2854 + if(this.element_legend_childs.resize_handler !== null) this.element_legend_childs.resize_handler.style.display = 'none';
2855
2760 - that.tm.last_hidden = Date.now();
2856 + this.tm.last_hidden = Date.now();
2857
2858 // de-allocate data
2859 // This works, but I not sure there are no corner cases somewhere
2860 // so it is commented - if the user has memory issues he can
2861 // set Destroy on Hide for all charts
2766 - // that.data = null;
2862 + // this.data = null;
2863 }
2864 }
2865
2770 - that.tmp.___chartIsHidden___ = true;
2866 + this.tmp.___chartIsHidden___ = true;
2867 };
2868
2869 // unhide the chart, when it is visible - called from isVisible()
2774 - var unhideChart = function() {
2870 + this.unhideChart = function() {
2871 if(isHidden() === false) return;
2872
2777 - that.tmp.___chartIsHidden___ = undefined;
2778 - that.updates_since_last_unhide = 0;
2873 + this.tmp.___chartIsHidden___ = undefined;
2874 + this.updates_since_last_unhide = 0;
2875
2780 - if(that.chart_created === false) {
2781 - if(that.debug === true)
2782 - that.log('unhideChart(): initializing chart');
2876 + if(this.chart_created === false) {
2877 + if(this.debug === true)
2878 + this.log('unhideChart(): initializing chart');
2879
2880 // we need to re-initialize it, to show our background
2881 // logo in bootstrap tabs, until the chart loads
2882 init('force');
2883 }
2884 else {
2789 - if(that.debug === true)
2790 - that.log('unhideChart(): unhiding chart');
2791 -
2792 - that.element.style.willChange = 'transform';
2793 - that.tm.last_unhidden = Date.now();
2794 - that.element_chart.style.display = '';
2795 - if(that.element_legend !== null) that.element_legend.style.display = '';
2796 - if(that.element_legend_childs.toolbox !== null) that.element_legend_childs.toolbox.style.display = '';
2797 - if(that.element_legend_childs.resize_handler !== null) that.element_legend_childs.resize_handler.style.display = '';
2885 + if(this.debug === true)
2886 + this.log('unhideChart(): unhiding chart');
2887 +
2888 + this.element.style.willChange = 'transform';
2889 + this.tm.last_unhidden = Date.now();
2890 + this.element_chart.style.display = '';
2891 + if(this.element_legend !== null) this.element_legend.style.display = '';
2892 + if(this.element_legend_childs.toolbox !== null) this.element_legend_childs.toolbox.style.display = '';
2893 + if(this.element_legend_childs.resize_handler !== null) this.element_legend_childs.resize_handler.style.display = '';
2894 resizeChart();
2895 hideMessage();
2896 }
@@ -2804,6 +2900,9 @@ var NETDATA = window.NETDATA || {};
2900 if(that.debug === true)
2901 that.log('canBeRendered() called');
2902
2903 + if(NETDATA.options.current.update_only_visible === false)
2904 + return true;
2905 +
2906 var ret = (
2907 (
2908 NETDATA.options.page_is_visible === true ||
@@ -4719,8 +4818,8 @@ var NETDATA = window.NETDATA || {};
4818 || typeof this.tmp.___isVisible___ === 'undefined'
4819 || this.tm.last_visible_check <= NETDATA.options.last_page_scroll) {
4820 this.tmp.___isVisible___ = __isVisible();
4722 - if (this.tmp.___isVisible___ === true) unhideChart();
4723 - else hideChart();
4821 + if (this.tmp.___isVisible___ === true) this.unhideChart();
4822 + else this.hideChart();
4823 }
4824
4825 if(this.debug === true)
@@ -5164,6 +5263,8 @@ var NETDATA = window.NETDATA || {};
5263 // this is purely sequential charts refresher
5264 // it is meant to be autonomous
5265 NETDATA.chartRefresherNoParallel = function(index, callback) {
5266 + var targets = NETDATA.intersectionObserver.targets();
5267 +
5268 if(NETDATA.options.debug.main_loop === true)
5269 console.log('NETDATA.chartRefresherNoParallel(' + index + ')');
5270
@@ -5173,7 +5274,7 @@ var NETDATA = window.NETDATA || {};
5274 NETDATA.parseDom(callback);
5275 return;
5276 }
5176 - if(index >= NETDATA.options.targets.length) {
5277 + if(index >= targets.length) {
5278 if(NETDATA.options.debug.main_loop === true)
5279 console.log('waiting to restart main loop...');
5280
@@ -5181,7 +5282,7 @@ var NETDATA = window.NETDATA || {};
5282 callback();
5283 }
5284 else {
5184 - var state = NETDATA.options.targets[index];
5285 + var state = targets[index];
5286
5287 if(NETDATA.options.auto_refresher_fast_weight < NETDATA.options.current.fast_render_timeframe) {
5288 if(NETDATA.options.debug.main_loop === true)
@@ -5314,7 +5415,7 @@ var NETDATA = window.NETDATA || {};
5415
5416 if(NETDATA.globalSelectionSync.active() === false) {
5417 var parallel = [];
5317 - var targets = NETDATA.options.targets;
5418 + var targets = NETDATA.intersectionObserver.targets();
5419 var len = targets.length;
5420 var state;
5421 while(len--) {
@@ -5374,12 +5475,15 @@ var NETDATA = window.NETDATA || {};
5475 if(NETDATA.options.debug.main_loop === true)
5476 console.log('DOM updated - there are ' + targets.length + ' charts on page.');
5477
5478 + NETDATA.intersectionObserver.globalReset();
5479 NETDATA.options.targets = [];
5480 var len = targets.length;
5481 while(len--) {
5482 // the initialization will take care of sizing
5483 // and the "loading..." message
5382 - NETDATA.options.targets.push(NETDATA.chartState(targets[len]));
5484 + var state = NETDATA.chartState(targets[len]);
5485 + NETDATA.options.targets.push(state);
5486 + NETDATA.intersectionObserver.observe(state);
5487 }
5488
5489 if(NETDATA.globalChartUnderlay.isActive() === true)
@@ -5454,13 +5558,14 @@ var NETDATA = window.NETDATA || {};
5558 };
5559
5560 NETDATA.globalReset = function() {
5561 + NETDATA.intersectionObserver.globalReset();
5562 NETDATA.globalSelectionSync.globalReset();
5563 NETDATA.globalPanAndZoom.globalReset();
5564 NETDATA.chartRegistry.globalReset();
5565 NETDATA.commonMin.globalReset();
5566 NETDATA.commonMax.globalReset();
5567 NETDATA.unitsConversion.globalReset();
5463 - NETDATA.options.targets = null;
5568 + NETDATA.options.targets = [];
5569 NETDATA.parseDom();
5570 NETDATA.unpause();
5571 };