X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=web%2Fdashboard.js;h=b34accdecb0948a45a1769631e1f2d5a02681b8a;hb=8679670bdbe3c5928ec2e266d9c72e1a758fdf37;hp=88ac14fa876105de2f2b55146c0108b39d9af774;hpb=2a3c9bfc374ab1cf023792780b770f4dc3efb344;p=netdata.git diff --git a/web/dashboard.js b/web/dashboard.js index 88ac14fa..b34accde 100644 --- a/web/dashboard.js +++ b/web/dashboard.js @@ -130,7 +130,7 @@ var NETDATA = window.NETDATA || {}; NETDATA.peity_js = NETDATA.serverDefault + 'lib/jquery.peity-3.2.0.min.js'; NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline-2.1.2.min.js'; NETDATA.easypiechart_js = NETDATA.serverDefault + 'lib/jquery.easypiechart-97b5824.min.js'; - NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-1.3.1.min.js'; + NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-1.3.2.min.js'; NETDATA.dygraph_js = NETDATA.serverDefault + 'lib/dygraph-combined-dd74404.js'; NETDATA.dygraph_smooth_js = NETDATA.serverDefault + 'lib/dygraph-smooth-plotter-dd74404.js'; NETDATA.raphael_js = NETDATA.serverDefault + 'lib/raphael-2.2.4-min.js'; @@ -218,6 +218,29 @@ var NETDATA = window.NETDATA || {}; if(netdataRegistry === false && typeof netdataRegistryCallback === 'function') netdataRegistry = true; + + // ---------------------------------------------------------------------------------------------------------------- + // detect if this is probably a slow device + + var isSlowDeviceResult = undefined; + var isSlowDevice = function() { + if(isSlowDeviceResult !== undefined) + return isSlowDeviceResult; + + try { + var ua = navigator.userAgent.toLowerCase(); + + var iOS = /ipad|iphone|ipod/.test(ua) && !window.MSStream; + var android = /android/.test(ua) && !window.MSStream; + isSlowDeviceResult = (iOS === true || android === true); + } + catch (e) { + isSlowDeviceResult = false; + } + + return isSlowDeviceResult; + }; + // ---------------------------------------------------------------------------------------------------------------- // the defaults for all charts @@ -271,7 +294,7 @@ var NETDATA = window.NETDATA || {}; // the current profile // we may have many... current: { - pixels_per_point: 1, // the minimum pixels per point for all charts + pixels_per_point: isSlowDevice()?5:1, // the minimum pixels per point for all charts // increase this to speed javascript up // each chart library has its own limit too // the max of this and the chart library is used @@ -313,11 +336,11 @@ var NETDATA = window.NETDATA || {}; update_only_visible: true, // enable or disable visibility management - parallel_refresher: true, // enable parallel refresh of charts + parallel_refresher: (isSlowDevice() === false), // enable parallel refresh of charts concurrent_refreshes: true, // when parallel_refresher is enabled, sync also the charts - destroy_on_hide: false, // destroy charts when they are not visible + destroy_on_hide: (isSlowDevice() === true), // destroy charts when they are not visible show_help: netdataShowHelp, // when enabled the charts will show some help show_help_delay_show_ms: 500, @@ -330,7 +353,7 @@ var NETDATA = window.NETDATA || {}; double_click_speed: 500, // ms - time between clicks / taps to detect double click/tap - smooth_plot: true, // enable smooth plot, where possible + smooth_plot: (isSlowDevice() === false), // enable smooth plot, where possible charts_selection_animation_delay: 50, // delay to animate charts when syncing selection @@ -1340,9 +1363,7 @@ var NETDATA = window.NETDATA || {}; this.value_decimal_detail = -1; var d = self.data('decimal-digits'); if(typeof d === 'number') { - this.value_decimal_detail = 1; - while(d-- > 0) - this.value_decimal_detail *= 10; + this.value_decimal_detail = d; } this.auto = { @@ -2224,19 +2245,69 @@ var NETDATA = window.NETDATA || {}; return ret; }; + var __legendFormatValueChartDecimalsLastMin = undefined; + var __legendFormatValueChartDecimalsLastMax = undefined; + var __legendFormatValueChartDecimals = -1; + this.legendFormatValueDecimalsFromMinMax = function(min, max) { + if(min === __legendFormatValueChartDecimalsLastMin && max === __legendFormatValueChartDecimalsLastMax) + return; + + __legendFormatValueChartDecimalsLastMin = min; + __legendFormatValueChartDecimalsLastMax = max; + + if(this.data !== null && this.data.min === this.data.max) + __legendFormatValueChartDecimals = -1; + + else if(this.value_decimal_detail !== -1) + __legendFormatValueChartDecimals = this.value_decimal_detail; + + else { + var delta; + + if (min === max) + delta = Math.abs(min); + else + delta = Math.abs(max - min); + + if (delta > 1000) __legendFormatValueChartDecimals = 0; + else if (delta > 10) __legendFormatValueChartDecimals = 1; + else if (delta > 1) __legendFormatValueChartDecimals = 2; + else if (delta > 0.1) __legendFormatValueChartDecimals = 2; + else __legendFormatValueChartDecimals = 4; + } + }; + this.legendFormatValue = function(value) { - if(value === null || value === 'undefined') return '-'; - if(typeof value !== 'number') return value; - - if(this.value_decimal_detail !== -1) - return (Math.round(value * this.value_decimal_detail) / this.value_decimal_detail).toLocaleString(); - - var abs = Math.abs(value); - if(abs >= 1000) return (Math.round(value)).toLocaleString(); - if(abs >= 100 ) return (Math.round(value * 10) / 10).toLocaleString(); - if(abs >= 1 ) return (Math.round(value * 100) / 100).toLocaleString(); - if(abs >= 0.1 ) return (Math.round(value * 1000) / 1000).toLocaleString(); - return (Math.round(value * 10000) / 10000).toLocaleString(); + if(typeof value !== 'number') return '-'; + + var dmin, dmax; + + if(__legendFormatValueChartDecimals < 0) { + dmin = 0; + var abs = value; + if(abs > 1000) dmax = 0; + else if(abs > 10 ) dmax = 1; + else if(abs > 1) dmax = 2; + else if(abs > 0.1) dmax = 2; + else dmax = 4; + } + else { + dmin = dmax = __legendFormatValueChartDecimals; + } + + if(this.value_decimal_detail !== -1) { + dmin = dmax = this.value_decimal_detail; + } + + return value.toLocaleString(undefined, { + // style: 'decimal', + // minimumIntegerDigits: 1, + // minimumSignificantDigits: 1, + // maximumSignificantDigits: 1, + useGrouping: true, + minimumFractionDigits: dmin, + maximumFractionDigits: dmax + }); }; this.legendSetLabelValue = function(label, value) { @@ -2306,32 +2377,43 @@ var NETDATA = window.NETDATA || {}; } }; + this.legendSetDateLast = { + ms: 0, + date: undefined, + time: undefined + }; + this.legendSetDate = function(ms) { if(typeof ms !== 'number') { this.legendShowUndefined(); return; } - var d = new Date(ms); + if(this.legendSetDateLast.ms !== ms) { + var d = new Date(ms); + this.legendSetDateLast.ms = ms; + this.legendSetDateLast.date = d.toLocaleDateString(); + this.legendSetDateLast.time = d.toLocaleTimeString(); + } - if(this.element_legend_childs.title_date) - this.__legendSetDateString(d.toLocaleDateString()); + if(this.element_legend_childs.title_date !== null) + this.__legendSetDateString(this.legendSetDateLast.date); - if(this.element_legend_childs.title_time) - this.__legendSetTimeString(d.toLocaleTimeString()); + if(this.element_legend_childs.title_time !== null) + this.__legendSetTimeString(this.legendSetDateLast.time); - if(this.element_legend_childs.title_units) + if(this.element_legend_childs.title_units !== null) this.__legendSetUnitsString(this.units) }; this.legendShowUndefined = function() { - if(this.element_legend_childs.title_date) + if(this.element_legend_childs.title_date !== null) this.__legendSetDateString(' '); - if(this.element_legend_childs.title_time) + if(this.element_legend_childs.title_time !== null) this.__legendSetTimeString(this.chart.name); - if(this.element_legend_childs.title_units) + if(this.element_legend_childs.title_units !== null) this.__legendSetUnitsString(' '); if(this.data && this.element_legend_childs.series !== null) { @@ -2340,8 +2422,7 @@ var NETDATA = window.NETDATA || {}; while(i--) { var label = labels[i]; - if(typeof label === 'undefined') continue; - if(typeof this.element_legend_childs.series[label] === 'undefined') continue; + if(typeof label === 'undefined' || typeof this.element_legend_childs.series[label] === 'undefined') continue; this.legendSetLabelValue(label, null); } } @@ -2753,16 +2834,19 @@ var NETDATA = window.NETDATA || {}; this.element_legend_childs.title_date.className += " netdata-legend-title-date"; this.element_legend.appendChild(this.element_legend_childs.title_date); + this.__last_shown_legend_date = undefined; this.element_legend.appendChild(document.createElement('br')); this.element_legend_childs.title_time.className += " netdata-legend-title-time"; this.element_legend.appendChild(this.element_legend_childs.title_time); + this.__last_shown_legend_time = undefined; this.element_legend.appendChild(document.createElement('br')); this.element_legend_childs.title_units.className += " netdata-legend-title-units"; this.element_legend.appendChild(this.element_legend_childs.title_units); + this.__last_shown_legend_units = undefined; this.element_legend.appendChild(document.createElement('br')); @@ -3055,7 +3139,8 @@ var NETDATA = window.NETDATA || {}; if(this.debug === true) this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.'); - this.chart_created = false; + init(); + return; } // check and update the legend @@ -4186,101 +4271,185 @@ var NETDATA = window.NETDATA || {}; var self = $(state.element); - var chart_type = state.chart.chart_type; + var chart_type = self.data('dygraph-type') || state.chart.chart_type; if(chart_type === 'stacked' && data.dimensions === 1) chart_type = 'area'; - chart_type = self.data('dygraph-type') || chart_type; - var smooth = (chart_type === 'line' && NETDATA.chartLibraries.dygraph.isSparkline(state) === false); - smooth = self.data('dygraph-smooth') || smooth; + var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state) === true)?3:4; - if(NETDATA.dygraph.smooth === false) - smooth = false; - - var strokeWidth = (chart_type === 'stacked')?0.1:((smooth)?1.5:0.7); - var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state))?3:4; + var smooth = (NETDATA.dygraph.smooth === true) + ?(self.data('dygraph-smooth') || (chart_type === 'line' && NETDATA.chartLibraries.dygraph.isSparkline(state) === false)) + :false; state.dygraph_options = { - colors: self.data('dygraph-colors') || state.chartColors(), + colors: self.data('dygraph-colors') || state.chartColors(), // leave a few pixels empty on the right of the chart - rightGap: self.data('dygraph-rightgap') || 5, - showRangeSelector: self.data('dygraph-showrangeselector') || false, - showRoller: self.data('dygraph-showroller') || false, - - title: self.data('dygraph-title') || state.title, - titleHeight: self.data('dygraph-titleheight') || 19, - - legend: self.data('dygraph-legend') || 'always', // we need this to get selection events - labels: data.result.labels, - labelsDiv: self.data('dygraph-labelsdiv') || state.element_legend_childs.hidden, - labelsDivStyles: self.data('dygraph-labelsdivstyles') || { 'fontSize':'1px' }, - labelsDivWidth: self.data('dygraph-labelsdivwidth') || state.chartWidth() - 70, - labelsSeparateLines: self.data('dygraph-labelsseparatelines') || true, - labelsShowZeroValues: self.data('dygraph-labelsshowzerovalues') || true, - labelsKMB: false, - labelsKMG2: false, - showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight') || true, - hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout') || true, - - includeZero: self.data('dygraph-includezero') || (chart_type === 'stacked'), - xRangePad: self.data('dygraph-xrangepad') || 0, - yRangePad: self.data('dygraph-yrangepad') || 1, - - valueRange: self.data('dygraph-valuerange') || [ null, null ], - - ylabel: state.units, - yLabelWidth: self.data('dygraph-ylabelwidth') || 12, - - // the function to plot the chart - plotter: null, - - // The width of the lines connecting data points. This can be used to increase the contrast or some graphs. - strokeWidth: self.data('dygraph-strokewidth') || strokeWidth, - strokePattern: self.data('dygraph-strokepattern') || undefined, - - // The size of the dot to draw on each point in pixels (see drawPoints). A dot is always drawn when a point is "isolated", - // i.e. there is a missing point on either side of it. This also controls the size of those dots. - drawPoints: self.data('dygraph-drawpoints') || false, - - // Draw points at the edges of gaps in the data. This improves visibility of small data segments or other data irregularities. - drawGapEdgePoints: self.data('dygraph-drawgapedgepoints') || true, - - connectSeparatedPoints: self.data('dygraph-connectseparatedpoints') || false, - pointSize: self.data('dygraph-pointsize') || 1, - - // enabling this makes the chart with little square lines - stepPlot: self.data('dygraph-stepplot') || false, - - // Draw a border around graph lines to make crossing lines more easily distinguishable. Useful for graphs with many lines. - strokeBorderColor: self.data('dygraph-strokebordercolor') || NETDATA.themes.current.background, - strokeBorderWidth: self.data('dygraph-strokeborderwidth') || (chart_type === 'stacked')?0.0:0.0, - - fillGraph: self.data('dygraph-fillgraph') || (chart_type === 'area' || chart_type === 'stacked'), - fillAlpha: self.data('dygraph-fillalpha') || ((chart_type === 'stacked')?NETDATA.options.current.color_fill_opacity_stacked:NETDATA.options.current.color_fill_opacity_area), - stackedGraph: self.data('dygraph-stackedgraph') || (chart_type === 'stacked'), - stackedGraphNaNFill: self.data('dygraph-stackedgraphnanfill') || 'none', - - drawAxis: self.data('dygraph-drawaxis') || true, - axisLabelFontSize: self.data('dygraph-axislabelfontsize') || 10, - axisLineColor: self.data('dygraph-axislinecolor') || NETDATA.themes.current.axis, - axisLineWidth: self.data('dygraph-axislinewidth') || 1.0, - - drawGrid: self.data('dygraph-drawgrid') || true, - gridLinePattern: self.data('dygraph-gridlinepattern') || null, - gridLineWidth: self.data('dygraph-gridlinewidth') || 1.0, - gridLineColor: self.data('dygraph-gridlinecolor') || NETDATA.themes.current.grid, - - maxNumberWidth: self.data('dygraph-maxnumberwidth') || 8, - sigFigs: self.data('dygraph-sigfigs') || null, - digitsAfterDecimal: self.data('dygraph-digitsafterdecimal') || 2, - valueFormatter: self.data('dygraph-valueformatter') || function(x){ return x.toFixed(2); }, - - highlightCircleSize: self.data('dygraph-highlightcirclesize') || highlightCircleSize, - highlightSeriesOpts: self.data('dygraph-highlightseriesopts') || null, // TOO SLOW: { strokeWidth: 1.5 }, - highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha') || null, // TOO SLOW: (chart_type === 'stacked')?0.7:0.5, - - pointClickCallback: self.data('dygraph-pointclickcallback') || undefined, - visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names), + rightGap: self.data('dygraph-rightgap') + || 5, + + showRangeSelector: self.data('dygraph-showrangeselector') + || false, + + showRoller: self.data('dygraph-showroller') + || false, + + title: self.data('dygraph-title') + || state.title, + + titleHeight: self.data('dygraph-titleheight') + || 19, + + legend: self.data('dygraph-legend') + || 'always', // we need this to get selection events + + labels: data.result.labels, + + labelsDiv: self.data('dygraph-labelsdiv') + || state.element_legend_childs.hidden, + + labelsDivStyles: self.data('dygraph-labelsdivstyles') + || { 'fontSize':'1px' }, + + labelsDivWidth: self.data('dygraph-labelsdivwidth') + || state.chartWidth() - 70, + + labelsSeparateLines: self.data('dygraph-labelsseparatelines') + || true, + + labelsShowZeroValues: self.data('dygraph-labelsshowzerovalues') + || true, + + labelsKMB: false, + labelsKMG2: false, + + showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight') + || true, + + hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout') + || true, + + includeZero: self.data('dygraph-includezero') + || (chart_type === 'stacked'), + + xRangePad: self.data('dygraph-xrangepad') + || 0, + + yRangePad: self.data('dygraph-yrangepad') + || 1, + + valueRange: self.data('dygraph-valuerange') + || [ null, null ], + + ylabel: state.units, + + yLabelWidth: self.data('dygraph-ylabelwidth') + || 12, + + // the function to plot the chart + plotter: null, + + // The width of the lines connecting data points. + // This can be used to increase the contrast or some graphs. + strokeWidth: self.data('dygraph-strokewidth') + || ((chart_type === 'stacked')?0.1:((smooth === true)?1.5:0.7)), + + strokePattern: self.data('dygraph-strokepattern') + || undefined, + + // The size of the dot to draw on each point in pixels (see drawPoints). + // A dot is always drawn when a point is "isolated", + // i.e. there is a missing point on either side of it. + // This also controls the size of those dots. + drawPoints: self.data('dygraph-drawpoints') + || false, + + // Draw points at the edges of gaps in the data. + // This improves visibility of small data segments or other data irregularities. + drawGapEdgePoints: self.data('dygraph-drawgapedgepoints') + || true, + + connectSeparatedPoints: self.data('dygraph-connectseparatedpoints') + || false, + + pointSize: self.data('dygraph-pointsize') + || 1, + + // enabling this makes the chart with little square lines + stepPlot: self.data('dygraph-stepplot') + || false, + + // Draw a border around graph lines to make crossing lines more easily + // distinguishable. Useful for graphs with many lines. + strokeBorderColor: self.data('dygraph-strokebordercolor') + || NETDATA.themes.current.background, + + strokeBorderWidth: self.data('dygraph-strokeborderwidth') + || (chart_type === 'stacked')?0.0:0.0, + + fillGraph: self.data('dygraph-fillgraph') + || (chart_type === 'area' || chart_type === 'stacked'), + + fillAlpha: self.data('dygraph-fillalpha') + || ((chart_type === 'stacked') + ?NETDATA.options.current.color_fill_opacity_stacked + :NETDATA.options.current.color_fill_opacity_area), + + stackedGraph: self.data('dygraph-stackedgraph') + || (chart_type === 'stacked'), + + stackedGraphNaNFill: self.data('dygraph-stackedgraphnanfill') + || 'none', + + drawAxis: self.data('dygraph-drawaxis') + || true, + + axisLabelFontSize: self.data('dygraph-axislabelfontsize') + || 10, + + axisLineColor: self.data('dygraph-axislinecolor') + || NETDATA.themes.current.axis, + + axisLineWidth: self.data('dygraph-axislinewidth') + || 1.0, + + drawGrid: self.data('dygraph-drawgrid') + || true, + + gridLinePattern: self.data('dygraph-gridlinepattern') + || null, + + gridLineWidth: self.data('dygraph-gridlinewidth') + || 1.0, + + gridLineColor: self.data('dygraph-gridlinecolor') + || NETDATA.themes.current.grid, + + maxNumberWidth: self.data('dygraph-maxnumberwidth') + || 8, + + sigFigs: self.data('dygraph-sigfigs') + || null, + + digitsAfterDecimal: self.data('dygraph-digitsafterdecimal') + || 2, + + valueFormatter: self.data('dygraph-valueformatter') + || undefined, + + highlightCircleSize: self.data('dygraph-highlightcirclesize') + || highlightCircleSize, + + highlightSeriesOpts: self.data('dygraph-highlightseriesopts') + || null, // TOO SLOW: { strokeWidth: 1.5 }, + + highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha') + || null, // TOO SLOW: (chart_type === 'stacked')?0.7:0.5, + + pointClickCallback: self.data('dygraph-pointclickcallback') + || undefined, + + visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names), + axes: { x: { pixelsPerLabel: 50, @@ -4288,25 +4457,19 @@ var NETDATA = window.NETDATA || {}; axisLabelFormatter: function (d, gran) { void(gran); return NETDATA.zeropad(d.getHours()) + ":" + NETDATA.zeropad(d.getMinutes()) + ":" + NETDATA.zeropad(d.getSeconds()); - }, - valueFormatter: function (ms) { - void(ms); - //var d = new Date(ms); - //return d.toLocaleDateString() + ' ' + d.toLocaleTimeString(); - - // no need to return anything here - return ' '; - } }, y: { pixelsPerLabel: 15, - valueFormatter: function (x) { - // we format legends with the state object - // no need to do anything here - // return (Math.round(x*100) / 100).toLocaleString(); - // return state.legendFormatValue(x); - return x; + axisLabelFormatter: function (y) { + + // unfortunately, we have to call this every single time + state.legendFormatValueDecimalsFromMinMax( + this.axes_[0].extremeRange[0], + this.axes_[0].extremeRange[1] + ); + + return state.legendFormatValue(y); } } }, @@ -5626,7 +5789,7 @@ var NETDATA = window.NETDATA || {}; var len = generateGradient.length; while(len--) { var pcent = generateGradient[len]; - var color = self.data('gauge-gradient-percent-color-' + pcent.toString()) || false; + var color = self.attr('data-gauge-gradient-percent-color-' + pcent.toString()) || false; if(color !== false) { var a = []; a[0] = pcent / 100;