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-d5260c3.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';
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
// 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
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,
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
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 = {
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) {
}
};
+ 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) {
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);
}
}
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'));
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
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,
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);
}
}
},
// is always between min and max
var pcent = (value - min) * 100 / (max - min);
- // these should never happen
- if(pcent < 0) pcent = 0;
- if(pcent > 100) pcent = 100;
+ // bug fix for gauge.js 1.3.1
+ // if the value is the absolute min or max, the chart is broken
+ if(pcent < 0.001) pcent = 0.001;
+ if(pcent > 99.999) pcent = 99.999;
state.gauge_instance.set(pcent);
// console.log('gauge set ' + pcent + ', value ' + value + ', min ' + min + ', max ' + max);
var options = {
lines: 12, // The number of lines to draw
- angle: 0.15, // The length of each line
- lineWidth: 0.44, // 0.44 The line thickness
+ angle: 0.15, // The span of the gauge arc
+ lineWidth: 0.50, // The line thickness
+ radiusScale: 0.85, // Relative radius
pointer: {
length: 0.8, // 0.9 The radius of the inner circle
strokeWidth: 0.035, // The rotation offset
color: pointerColor // Fill color
},
+ limitMax: true, // If false, the max value of the gauge will be updated if value surpass max
+ limitMin: true, // If true, the min value of the gauge will be fixed unless you set it manually
colorStart: startColor, // Colors
colorStop: stopColor, // just experiment with them
strokeColor: strokeColor, // to see which ones work best for you
- limitMax: true,
generateGradient: (generateGradient === true),
- gradientType: 0
+ gradientType: 0,
+ highDpiSupport: true // High resolution support
};
if (generateGradient.constructor === Array) {
if(NETDATA.alarms.current !== null) {
// get the current value_string
var t = NETDATA.alarms.current.alarms[entry.chart + '.' + entry.name];
- if(typeof t !== 'undefined' && entry.status === t.status)
+ if(typeof t !== 'undefined' && entry.status === t.status && typeof t.value_string !== 'undefined')
value_string = t.value_string;
}