+// ----------------------------------------------------------------------------
// You can set the following variables before loading this script:
-//
-// var netdataNoDygraphs = true; // do not use dygraph
-// var netdataNoSparklines = true; // do not use sparkline
-// var netdataNoPeitys = true; // do not use peity
-// var netdataNoGoogleCharts = true; // do not use google
-// var netdataNoMorris = true; // do not use morris
-// var netdataNoEasyPieChart = true; // do not use easy pie chart
-// var netdataNoGauge = true; // do not use gauge.js
-// var netdataNoD3 = true; // do not use D3
-// var netdataNoC3 = true; // do not use C3
-// var netdataNoBootstrap = true; // do not load bootstrap
-// var netdataDontStart = true; // do not start the thread to process the charts
-// var netdataErrorCallback = null; // Callback function that will be invoked upon error
-// var netdataRegistry = true; // Update the registry (default disabled)
-// var netdataRegistryCallback = null; // Callback function that will be invoked with one param,
-// the URLs from the registry
-// var netdataShowHelp = false; // enable/disable help (default enabled)
-// var netdataShowAlarms = true; // enable/disable alarms checks and notifications (default disabled)
-//
-// var netdataRegistryAfterMs = 1500 // the time to consult to registry on startup
-//
-// var netdataCallback = null; // a function to call when netdata is ready
-// // netdata will be running while this is called (call NETDATA.pause to stop it)
-// var netdataPrepCallback = null; // a callback to be called before netdata does anything else
-//
-// You can also set the default netdata server, using the following.
-// When this variable is not set, we assume the page is hosted on your
-// netdata server already.
-// var netdataServer = "http://yourhost:19999"; // set your NetData server
-
-//(function(window, document, undefined) {
+/*global netdataNoDygraphs *//* boolean, disable dygraph charts
+ * (default: false) */
+/*global netdataNoSparklines *//* boolean, disable sparkline charts
+ * (default: false) */
+/*global netdataNoPeitys *//* boolean, disable peity charts
+ * (default: false) */
+/*global netdataNoGoogleCharts *//* boolean, disable google charts
+ * (default: false) */
+/*global netdataNoMorris *//* boolean, disable morris charts
+ * (default: false) */
+/*global netdataNoEasyPieChart *//* boolean, disable easypiechart charts
+ * (default: false) */
+/*global netdataNoGauge *//* boolean, disable gauge.js charts
+ * (default: false) */
+/*global netdataNoD3 *//* boolean, disable d3 charts
+ * (default: false) */
+/*global netdataNoC3 *//* boolean, disable c3 charts
+ * (default: false) */
+/*global netdataNoBootstrap *//* boolean, disable bootstrap - disables help too
+ * (default: false) */
+/*global netdataDontStart *//* boolean, do not start the thread to process the charts
+ * (default: false) */
+/*global netdataErrorCallback *//* function, callback to be called when the dashboard encounters an error
+ * (default: null) */
+/*global netdataRegistry:true *//* boolean, use the netdata registry
+ * (default: false) */
+/*global netdataNoRegistry *//* boolean, included only for compatibility with existing custom dashboard
+ * (obsolete - do not use this any more) */
+/*global netdataRegistryCallback *//* function, callback that will be invoked with one param: the URLs from the registry
+ * (default: null) */
+/*global netdataShowHelp:true *//* boolean, disable charts help
+ * (default: true) */
+/*global netdataShowAlarms:true *//* boolean, enable alarms checks and notifications
+ * (default: false) */
+/*global netdataRegistryAfterMs:true *//* ms, delay registry use at started
+ * (default: 1500) */
+/*global netdataCallback *//* function, callback to be called when netdata is ready to start
+ * (default: null)
+ * netdata will be running while this is called
+ * (call NETDATA.pause to stop it) */
+/*global netdataPrepCallback *//* function, callback to be called before netdata does anything else
+ * (default: null) */
+/*global netdataServer *//* string, the URL of the netdata server to use
+ * (default: the URL the page is hosted at) */
+
+// ----------------------------------------------------------------------------
+// global namespace
+
+var NETDATA = window.NETDATA || {};
+
+(function(window, document) {
// ------------------------------------------------------------------------
// compatibility fixes
};
}
- // global namespace
- var NETDATA = window.NETDATA || {};
-
NETDATA.name2id = function(s) {
return s
.replace(/ /g, '_')
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';
NETDATA.themes = {
white: {
- bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-3.3.7.min.css',
- dashboard_css: NETDATA.serverDefault + 'dashboard.css?v20161002-1',
+ bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-3.3.7.css',
+ dashboard_css: NETDATA.serverDefault + 'dashboard.css?v20161229-2',
background: '#FFFFFF',
foreground: '#000000',
- grid: '#DDDDDD',
- axis: '#CCCCCC',
+ grid: '#F0F0F0',
+ axis: '#F0F0F0',
colors: [ '#3366CC', '#DC3912', '#109618', '#FF9900', '#990099', '#DD4477',
'#3B3EAC', '#66AA00', '#0099C6', '#B82E2E', '#AAAA11', '#5574A6',
'#994499', '#22AA99', '#6633CC', '#E67300', '#316395', '#8B0707',
gauge_gradient: false
},
slate: {
- bootstrap_css: NETDATA.serverDefault + 'css/bootstrap.slate.min.css?v20161002-1',
- dashboard_css: NETDATA.serverDefault + 'dashboard.slate.css?v20161002-1',
+ bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-slate-flat-3.3.7.css?v20161229-1',
+ dashboard_css: NETDATA.serverDefault + 'dashboard.slate.css?v20161229-2',
background: '#272b30',
foreground: '#C8C8C8',
- grid: '#35393e',
- axis: '#35393e',
+ grid: '#283236',
+ axis: '#283236',
/* colors: [ '#55bb33', '#ff2222', '#0099C6', '#faa11b', '#adbce0', '#DDDD00',
'#4178ba', '#f58122', '#a5cc39', '#f58667', '#f5ef89', '#cf93c0',
'#a5d18a', '#b8539d', '#3954a3', '#c8a9cf', '#c7de8a', '#fad20a',
if(typeof netdataRegistry === 'undefined') {
// backward compatibility
- if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry === false)
- netdataRegistry = true;
- else
- netdataRegistry = false;
+ netdataRegistry = (typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry === false);
}
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
before: 0, // panning
after: -600, // panning
pixels_per_point: 1, // the detail of the chart
- fill_luminance: 0.8 // luminance of colors in solit areas
+ fill_luminance: 0.8 // luminance of colors in solid areas
};
// ----------------------------------------------------------------------------------------------------------------
// new elements we have to check.
auto_refresher_fast_weight: 0, // this is the current time in ms, spent
- // rendering charts continiously.
+ // rendering charts continuously.
// used with .current.fast_render_timeframe
page_is_visible: true, // when true, this page is visible
- auto_refresher_stop_until: 0, // timestamp in ms - used internaly, to stop the
+ auto_refresher_stop_until: 0, // timestamp in ms - used internally, to stop the
// auto-refresher for some time (when a chart is
// performing pan or zoom, we need to stop refreshing
// all other charts, to have the maximum speed for
// rendering the chart that is panned or zoomed).
// Used with .current.global_pan_sync_time
- last_resized: new Date().getTime(), // the timestamp of the last resize request
+ last_resized: Date.now(), // the timestamp of the last resize request
last_page_scroll: 0, // the timestamp the last time the page was scrolled
// 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
idle_between_charts: 100, // ms - how much time to wait between chart updates
- fast_render_timeframe: 200, // ms - render continously until this time of continious
+ fast_render_timeframe: 200, // ms - render continuously until this time of continuous
// rendering has been reached
// this setting is used to make it render e.g. 10
// charts at once, sleep idle_between_charts time
idle_lost_focus: 500, // ms - when the window does not have focus, check
// if focus has been regained, every this time
- global_pan_sync_time: 1000, // ms - when you pan or zoon a chart, the background
- // autorefreshing of charts is paused for this amount
+ global_pan_sync_time: 1000, // ms - when you pan or zoom a chart, the background
+ // auto-refreshing of charts is paused for this amount
// of time
sync_selection_delay: 1500, // ms - when you pan or zoom a chart, wait this amount
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
async_on_scroll: false, // sync/async onscroll handler
onscroll_worker_duration_threshold: 30, // time in ms, to consider slow the onscroll handler
- setOptionCallback: function() { ; }
+ retries_on_data_failures: 3, // how many retries to make if we can't fetch chart data from the server
+
+ setOptionCallback: function() { }
},
debug: {
focus: false,
visibility: false,
chart_data_url: false,
- chart_errors: false, // FIXME
+ chart_errors: false, // FIXME: remember to set it to false before merging
chart_timing: false,
chart_calls: false,
libraries: false,
callback: {} // only used for resetting back to defaults
};
+ NETDATA.localStorageTested = -1;
+ NETDATA.localStorageTest = function() {
+ if(NETDATA.localStorageTested !== -1)
+ return NETDATA.localStorageTested;
+
+ if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ var test = 'test';
+ try {
+ localStorage.setItem(test, test);
+ localStorage.removeItem(test);
+ NETDATA.localStorageTested = true;
+ }
+ catch (e) {
+ NETDATA.localStorageTested = false;
+ }
+ }
+ else
+ NETDATA.localStorageTested = false;
+
+ return NETDATA.localStorageTested;
+ };
+
NETDATA.localStorageGet = function(key, def, callback) {
var ret = def;
NETDATA.localStorage.callback[key.toString()] = callback;
}
- if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ if(NETDATA.localStorageTest() === true) {
try {
// console.log('localStorage: loading "' + key.toString() + '"');
ret = localStorage.getItem(key.toString());
NETDATA.localStorage.callback[key.toString()] = callback;
}
- if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
+ if(NETDATA.localStorageTest() === true) {
// console.log('localStorage: saving "' + key.toString() + '" with value "' + JSON.stringify(value) + '"');
try {
localStorage.setItem(key.toString(), JSON.stringify(value));
};
NETDATA.localStorageGetRecursive = function(obj, prefix, callback) {
- for(var i in obj) {
+ var keys = Object.keys(obj);
+ var len = keys.length;
+ while(len--) {
+ var i = keys[len];
+
if(typeof obj[i] === 'object') {
//console.log('object ' + prefix + '.' + i.toString());
NETDATA.localStorageGetRecursive(obj[i], prefix + '.' + i.toString(), callback);
NETDATA.setOption('stop_updates_when_focus_is_lost', true);
NETDATA.resetOptions = function() {
- for(var i in NETDATA.localStorage.default) {
+ var keys = Object.keys(NETDATA.localStorage.default);
+ var len = keys.length;
+ while(len--) {
+ var i = keys[len];
var a = i.split('.');
if(a[0] === 'options') {
}
}
}
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
if(NETDATA.options.debug.main_loop === true)
console.log('welcome to NETDATA');
+ NETDATA.onresizeCallback = null;
NETDATA.onresize = function() {
- NETDATA.options.last_resized = new Date().getTime();
+ NETDATA.options.last_resized = Date.now();
NETDATA.onscroll();
+
+ if(typeof NETDATA.onresizeCallback === 'function')
+ NETDATA.onresizeCallback();
};
NETDATA.onscroll_updater_count = 0;
NETDATA.onscroll_updater = function() {
NETDATA.onscroll_updater_running = true;
NETDATA.onscroll_updater_count++;
- var start = new Date().getTime();
+ var start = Date.now();
var targets = NETDATA.options.targets;
var len = targets.length;
targets[len].isVisible();
}
- var end = new Date().getTime();
+ var end = Date.now();
// console.log('scroll No ' + NETDATA.onscroll_updater_count + ' calculation took ' + (end - start).toString() + ' ms');
if(NETDATA.options.current.async_on_scroll === false) {
NETDATA.onscroll = function() {
// console.log('onscroll');
- NETDATA.options.last_page_scroll = new Date().getTime();
+ NETDATA.options.last_page_scroll = Date.now();
NETDATA.options.auto_refresher_stop_until = 0;
if(NETDATA.options.targets === null) return;
NETDATA.error = function(code, msg) {
NETDATA.errorLast.code = code;
NETDATA.errorLast.message = msg;
- NETDATA.errorLast.datetime = new Date().getTime();
+ NETDATA.errorLast.datetime = Date.now();
console.log("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
NETDATA.errorLast.datetime = 0;
};
+ // ----------------------------------------------------------------------------------------------------------------
+ // commonMin & commonMax
+
+ NETDATA.commonMin = {
+ keys: {},
+ latest: {},
+
+ get: function(state) {
+ if(typeof state.__commonMin === 'undefined') {
+ // get the commonMin setting
+ var self = $(state.element);
+ state.__commonMin = self.data('common-min') || null;
+ }
+
+ var min = state.data.min;
+ var name = state.__commonMin;
+
+ if(name === null) {
+ // we don't need commonMin
+ //state.log('no need for commonMin');
+ return min;
+ }
+
+ var t = this.keys[name];
+ if(typeof t === 'undefined') {
+ // add our commonMin
+ this.keys[name] = {};
+ t = this.keys[name];
+ }
+
+ var uuid = state.uuid;
+ if(typeof t[uuid] !== 'undefined') {
+ if(t[uuid] === min) {
+ //state.log('commonMin ' + state.__commonMin + ' not changed: ' + this.latest[name]);
+ return this.latest[name];
+ }
+ else if(min < this.latest[name]) {
+ //state.log('commonMin ' + state.__commonMin + ' increased: ' + min);
+ t[uuid] = min;
+ this.latest[name] = min;
+ return min;
+ }
+ }
+
+ // add our min
+ t[uuid] = min;
+
+ // find the common min
+ var m = min;
+ for(var i in t)
+ if(t.hasOwnProperty(i) && t[i] < m) m = t[i];
+
+ //state.log('commonMin ' + state.__commonMin + ' updated: ' + m);
+ this.latest[name] = m;
+ return m;
+ }
+ };
+
+ NETDATA.commonMax = {
+ keys: {},
+ latest: {},
+
+ get: function(state) {
+ if(typeof state.__commonMax === 'undefined') {
+ // get the commonMax setting
+ var self = $(state.element);
+ state.__commonMax = self.data('common-max') || null;
+ }
+
+ var max = state.data.max;
+ var name = state.__commonMax;
+
+ if(name === null) {
+ // we don't need commonMax
+ //state.log('no need for commonMax');
+ return max;
+ }
+
+ var t = this.keys[name];
+ if(typeof t === 'undefined') {
+ // add our commonMax
+ this.keys[name] = {};
+ t = this.keys[name];
+ }
+
+ var uuid = state.uuid;
+ if(typeof t[uuid] !== 'undefined') {
+ if(t[uuid] === max) {
+ //state.log('commonMax ' + state.__commonMax + ' not changed: ' + this.latest[name]);
+ return this.latest[name];
+ }
+ else if(max > this.latest[name]) {
+ //state.log('commonMax ' + state.__commonMax + ' increased: ' + max);
+ t[uuid] = max;
+ this.latest[name] = max;
+ return max;
+ }
+ }
+
+ // add our max
+ t[uuid] = max;
+
+ // find the common max
+ var m = max;
+ for(var i in t)
+ if(t.hasOwnProperty(i) && t[i] > m) m = t[i];
+
+ //state.log('commonMax ' + state.__commonMax + ' updated: ' + m);
+ this.latest[name] = m;
+ return m;
+ }
+ };
+
// ----------------------------------------------------------------------------------------------------------------
// Chart Registry
// Every time we download a chart definition, we save it here with .add()
// Then we try to get it back with .get(). If that fails, we download it.
+ NETDATA.fixHost = function(host) {
+ while(host.slice(-1) === '/')
+ host = host.substring(0, host.length - 1);
+
+ return host;
+ };
+
NETDATA.chartRegistry = {
charts: {},
},
downloadAll: function(host, callback) {
- while(host.slice(-1) === '/')
- host = host.substring(0, host.length - 1);
+ host = NETDATA.fixHost(host);
var self = this;
else NETDATA.error(406, host + '/api/v1/charts');
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(405, host + '/api/v1/charts');
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
}
};
// every time a chart is panned or zoomed
// we set the timestamp here
// then we use it as a sequence number
- // to find if other charts are syncronized
- // to this timerange
+ // to find if other charts are synchronized
+ // to this time-range
master: null, // the master chart (state), to which all others
// are synchronized
if(this.master !== null && this.master !== state)
this.master.resetChart(true, true);
- var now = new Date().getTime();
+ var now = Date.now();
this.master = state;
this.seq = now;
this.force_after_ms = after;
// is the given state the master of the global
// pan and zoom sync?
isMaster: function(state) {
- if(this.master === state) return true;
- return false;
+ return (this.master === state);
},
// are we currently have a global pan and zoom sync?
isActive: function() {
- if(this.master !== null && this.force_before_ms !== null && this.force_after_ms !== null && this.seq !== 0) return true;
- return false;
+ return (this.master !== null && this.force_before_ms !== null && this.force_after_ms !== null && this.seq !== 0);
},
// check if a chart, other than the master
//if(state.needsRecreation())
// return true;
- if(state.tm.pan_and_zoom_seq === this.seq)
- return false;
-
- return true;
+ return (state.tm.pan_and_zoom_seq !== this.seq);
}
};
// FIXME
// move color assignment to dimensions, here
- dimensionStatus = function(parent, label, name_div, value_div, color) {
+ var dimensionStatus = function(parent, label, name_div, value_div, color) {
this.enabled = false;
this.parent = parent;
this.label = label;
this.name_div = null;
this.value_div = null;
this.color = NETDATA.themes.current.foreground;
-
- if(parent.unselected_count === 0)
- this.selected = true;
- else
- this.selected = false;
+ this.selected = (parent.unselected_count === 0);
this.setOptions(name_div, value_div, color);
};
dimensionStatus.prototype.setOptions = function(name_div, value_div, color) {
this.color = color;
- if(this.name_div != name_div) {
+ if(this.name_div !== name_div) {
this.name_div = name_div;
this.name_div.title = this.label;
this.name_div.style.color = this.color;
this.name_div.className = 'netdata-legend-name selected';
}
- if(this.value_div != value_div) {
+ if(this.value_div !== value_div) {
this.value_div = value_div;
this.value_div.title = this.label;
this.value_div.style.color = this.color;
// ----------------------------------------------------------------------------------------------------------------
- dimensionsVisibility = function(state) {
+ var dimensionsVisibility = function(state) {
this.state = state;
this.len = 0;
this.dimensions = {};
};
dimensionsVisibility.prototype.invalidateAll = function() {
- for(var d in this.dimensions)
- this.dimensions[d].invalidate();
+ var keys = Object.keys(this.dimensions);
+ var len = keys.length;
+ while(len--)
+ this.dimensions[keys[len]].invalidate();
};
dimensionsVisibility.prototype.selectAll = function() {
- for(var d in this.dimensions)
- this.dimensions[d].select();
+ var keys = Object.keys(this.dimensions);
+ var len = keys.length;
+ while(len--)
+ this.dimensions[keys[len]].select();
};
dimensionsVisibility.prototype.countSelected = function() {
- var i = 0;
- for(var d in this.dimensions)
- if(this.dimensions[d].isSelected()) i++;
+ var selected = 0;
+ var keys = Object.keys(this.dimensions);
+ var len = keys.length;
+ while(len--)
+ if(this.dimensions[keys[len]].isSelected()) selected++;
- return i;
+ return selected;
};
dimensionsVisibility.prototype.selectNone = function() {
- for(var d in this.dimensions)
- this.dimensions[d].unselect();
+ var keys = Object.keys(this.dimensions);
+ var len = keys.length;
+ while(len--)
+ this.dimensions[keys[len]].unselect();
};
dimensionsVisibility.prototype.selected2BooleanArray = function(array) {
- var ret = new Array();
+ var ret = [];
this.selected_count = 0;
this.unselected_count = 0;
// ----------------------------------------------------------------------------------------------------------------
// Our state object, where all per-chart values are stored
- chartState = function(element) {
+ var chartState = function(element) {
var self = $(element);
this.element = element;
// the user given dimensions of the element
this.width = self.data('width') || NETDATA.chartDefaults.width;
this.height = self.data('height') || NETDATA.chartDefaults.height;
+ this.height_original = this.height;
if(this.settings_id !== null) {
this.height = NETDATA.localStorageGet('chart_heights.' + this.settings_id, this.height, function(height) {
// the chart library requested by the user
this.library_name = self.data('chart-library') || NETDATA.chartDefaults.library;
+ // how many retries we have made to load chart data from the server
+ this.retries_on_data_failures = 0;
+
// object - the chart library used
this.library = null;
title_date: null,
title_time: null,
title_units: null,
- nano: null,
- nano_options: null,
+ perfect_scroller: null, // the container to apply perfect scroller to
series: null
};
this.title = self.data('title') || null; // the title of the chart
this.units = self.data('units') || null; // the units of the chart dimensions
- this.append_options = self.data('append-options') || null; // the units of the chart dimensions
+ this.append_options = self.data('append-options') || null; // additional options to pass to netdata
+ this.override_options = self.data('override-options') || null; // override options to pass to netdata
this.running = false; // boolean - true when the chart is being refreshed now
- this.validated = false; // boolean - has the chart been validated?
this.enabled = true; // boolean - is the chart enabled for refresh?
this.paused = false; // boolean - is the chart paused for any reason?
this.selected = false; // boolean - is the chart shown a selection?
this.view_after = 0;
this.view_before = 0;
+ this.value_decimal_detail = -1;
+ var d = self.data('decimal-digits');
+ if(typeof d === 'number') {
+ this.value_decimal_detail = d;
+ }
+
this.auto = {
name: 'auto',
autorefresh: true,
// find the element that needs to be updated
var refresh_dt_element_name = self.data('dt-element-name') || null; // string - the element to print refresh_dt_ms
- if(refresh_dt_element_name !== null)
+ if(refresh_dt_element_name !== null) {
this.refresh_dt_element = document.getElementById(refresh_dt_element_name) || null;
+ }
else
this.refresh_dt_element = null;
that.element.innerHTML = '';
that.element_message = document.createElement('div');
- that.element_message.className = ' netdata-message hidden';
+ that.element_message.className = 'netdata-message icon hidden';
that.element.appendChild(that.element_message);
that.element_chart = document.createElement('div');
if(typeof(that.library.aspect_ratio) === 'undefined') {
if(typeof(that.height) === 'string')
- $(that.element).css('height', that.height);
+ that.element.style.height = that.height;
else if(typeof(that.height) === 'number')
- $(that.element).css('height', that.height + 'px');
+ that.element.style.height = that.height.toString() + 'px';
}
else {
var w = that.element.offsetWidth;
that.tm.last_resized = 0;
}
else
- $(that.element).css('height', (that.element.offsetWidth * that.library.aspect_ratio / 100).toString() + 'px');
+ that.element.style.height = (w * that.library.aspect_ratio / 100).toString() + 'px';
}
if(NETDATA.chartDefaults.min_width !== null)
$(that.element).css('min-width', NETDATA.chartDefaults.min_width);
- that.tm.last_dom_created = new Date().getTime();
+ that.tm.last_dom_created = Date.now();
showLoading();
};
that.data_before = 0; // milliseconds - the last timestamp of the data
that.data_update_every = 0; // milliseconds - the frequency to update the data
- that.tm.last_initialized = new Date().getTime();
+ that.tm.last_initialized = Date.now();
createDOM();
that.setMode('auto');
};
var maxMessageFontSize = function() {
+ var screenHeight = screen.height;
+ var el = that.element;
+
// normally we want a font size, as tall as the element
- var h = that.element_message.clientHeight;
+ var h = el.clientHeight;
// but give it some air, 20% let's say, or 5 pixels min
var lost = Math.max(h * 0.2, 5);
// but check the width too
// it should fit 10 characters in it
- var w = that.element_message.clientWidth / 10;
+ var w = el.clientWidth / 10;
if(h > w) {
paddingTop += (h - w) / 2;
h = w;
// and don't make it too huge
// 5% of the screen size is good
- if(h > screen.height / 20) {
- paddingTop += (h - (screen.height / 20)) / 2;
- h = screen.height / 20;
+ if(h > screenHeight / 20) {
+ paddingTop += (h - (screenHeight / 20)) / 2;
+ h = screenHeight / 20;
}
// set it
that.element_message.style.paddingTop = paddingTop.toString() + 'px';
};
- var showMessage = function(msg) {
- that.element_message.className = 'netdata-message';
- that.element_message.innerHTML = msg;
- that.element_message.style.fontSize = 'x-small';
- that.element_message.style.paddingTop = '0px';
- that.___messageHidden___ = undefined;
- };
-
var showMessageIcon = function(icon) {
that.element_message.innerHTML = icon;
- that.element_message.className = 'netdata-message icon';
maxMessageFontSize();
+ $(that.element_message).removeClass('hidden');
that.___messageHidden___ = undefined;
};
var hideMessage = function() {
if(typeof that.___messageHidden___ === 'undefined') {
that.___messageHidden___ = true;
- that.element_message.className = 'netdata-message hidden';
+ $(that.element_message).addClass('hidden');
}
};
};
var isHidden = function() {
- if(typeof that.___chartIsHidden___ !== 'undefined')
- return true;
-
- return false;
+ return (typeof that.___chartIsHidden___ !== 'undefined');
};
// hide the chart, when it is not visible - called from isVisible()
showRendering();
that.element_chart.style.display = 'none';
if(that.element_legend !== null) that.element_legend.style.display = 'none';
- that.tm.last_hidden = new Date().getTime();
+ that.tm.last_hidden = Date.now();
// de-allocate data
// This works, but I not sure there are no corner cases somewhere
init();
}
else {
- that.tm.last_unhidden = new Date().getTime();
+ that.tm.last_unhidden = Date.now();
that.element_chart.style.display = '';
if(that.element_legend !== null) that.element_legend.style.display = '';
resizeChart();
};
var canBeRendered = function() {
- if(isHidden() === true || that.isVisible(true) === false)
- return false;
-
- return true;
+ return (isHidden() === false && that.isVisible(true) === true);
};
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
else if(typeof that.library.resize === 'function') {
that.library.resize(that);
- if(that.element_legend_childs.nano !== null && that.element_legend_childs.nano_options !== null)
- $(that.element_legend_childs.nano).nanoScroller();
+ if(that.element_legend_childs.perfect_scroller !== null)
+ Ps.update(that.element_legend_childs.perfect_scroller);
maxMessageFontSize();
}
- that.tm.last_resized = new Date().getTime();
+ that.tm.last_resized = Date.now();
}
};
if(that.settings_id !== null)
NETDATA.localStorageSet('chart_heights.' + that.settings_id, h);
- var now = new Date().getTime();
+ var now = Date.now();
NETDATA.options.last_page_scroll = now;
NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.stop_updates_while_resizing;
this.event_resize.chart_last_w = this.element.clientWidth;
this.event_resize.chart_last_h = this.element.clientHeight;
- var now = new Date().getTime();
- if(now - this.event_resize.last <= NETDATA.options.current.double_click_speed) {
+ var now = Date.now();
+ if(now - this.event_resize.last <= NETDATA.options.current.double_click_speed && this.element_legend_childs.perfect_scroller !== null) {
// double click / double tap event
+ // console.dir(this.element_legend_childs.content);
+ // console.dir(this.element_legend_childs.perfect_scroller);
+
// the optimal height of the chart
// showing the entire legend
var optimal = this.event_resize.chart_last_h
- + this.element_legend_childs.content.scrollHeight
- - this.element_legend_childs.content.clientHeight;
+ + this.element_legend_childs.perfect_scroller.scrollHeight
+ - this.element_legend_childs.perfect_scroller.clientHeight;
// if we are not optimal, be optimal
- if(this.event_resize.chart_last_h != optimal)
+ if(this.event_resize.chart_last_h !== optimal) {
+ // this.log('resize to optimal, current = ' + this.event_resize.chart_last_h.toString() + 'px, original = ' + this.event_resize.chart_original_h.toString() + 'px, optimal = ' + optimal.toString() + 'px, internal = ' + this.height_original.toString());
resizeChartToHeight(optimal.toString() + 'px');
+ }
- // else if we do not have the original height
- // reset to the original height
- else if(this.event_resize.chart_last_h != this.event_resize.chart_original_h)
+ // else if the current height is not the original/saved height
+ // reset to the original/saved height
+ else if(this.event_resize.chart_last_h !== this.event_resize.chart_original_h) {
+ // this.log('resize to original, current = ' + this.event_resize.chart_last_h.toString() + 'px, original = ' + this.event_resize.chart_original_h.toString() + 'px, optimal = ' + optimal.toString() + 'px, internal = ' + this.height_original.toString());
resizeChartToHeight(this.event_resize.chart_original_h.toString() + 'px');
+ }
+
+ // else if the current height is not the internal default height
+ // reset to the internal default height
+ else if((this.event_resize.chart_last_h.toString() + 'px') !== this.height_original) {
+ // this.log('resize to internal default, current = ' + this.event_resize.chart_last_h.toString() + 'px, original = ' + this.event_resize.chart_original_h.toString() + 'px, optimal = ' + optimal.toString() + 'px, internal = ' + this.height_original.toString());
+ resizeChartToHeight(this.height_original.toString());
+ }
+
+ // else if the current height is not the firstchild's clientheight
+ // resize to it
+ else if(typeof this.element_legend_childs.perfect_scroller.firstChild !== 'undefined') {
+ var parent_rect = this.element.getBoundingClientRect();
+ var content_rect = this.element_legend_childs.perfect_scroller.firstElementChild.getBoundingClientRect();
+ var wanted = content_rect.top - parent_rect.top + this.element_legend_childs.perfect_scroller.firstChild.clientHeight + 18; // 15 = toolbox + 3 space
+
+ // console.log(parent_rect);
+ // console.log(content_rect);
+ // console.log(wanted);
+
+ // this.log('resize to firstChild, current = ' + this.event_resize.chart_last_h.toString() + 'px, original = ' + this.event_resize.chart_original_h.toString() + 'px, optimal = ' + optimal.toString() + 'px, internal = ' + this.height_original.toString() + 'px, firstChild = ' + wanted.toString() + 'px' );
+ if(this.event_resize.chart_last_h !== wanted)
+ resizeChartToHeight(wanted.toString() + 'px');
+ }
}
else {
this.event_resize.last = now;
this.element_legend_childs.resize_handler.onmouseup =
this.element_legend_childs.resize_handler.ontouchend =
function(e) {
+ void(e);
+
// remove all the hooks
document.onmouseup =
document.onmousemove =
var noDataToShow = function() {
showMessageIcon('<i class="fa fa-warning"></i> empty');
that.legendUpdateDOM();
- that.tm.last_autorefreshed = new Date().getTime();
+ that.tm.last_autorefreshed = Date.now();
// that.data_update_every = 30 * 1000;
//that.element_chart.style.display = 'none';
//if(that.element_legend !== null) that.element_legend.style.display = 'none';
this.current.force_before_ms = null;
this.current.force_after_ms = null;
- this.tm.last_mode_switch = new Date().getTime();
+ this.tm.last_mode_switch = Date.now();
};
// ----------------------------------------------------------------------------------------------------------------
return;
if(typeof ms === 'number')
- NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + ms;
+ NETDATA.globalSelectionSync.dont_sync_before = Date.now() + ms;
else
- NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
+ NETDATA.globalSelectionSync.dont_sync_before = Date.now() + NETDATA.options.current.sync_selection_delay;
};
// can we globally apply selection sync?
if(NETDATA.options.current.sync_selection === false)
return false;
- if(NETDATA.globalSelectionSync.dont_sync_before > new Date().getTime())
- return false;
-
- return true;
+ return (NETDATA.globalSelectionSync.dont_sync_before <= Date.now());
};
this.globalSelectionSyncIsMaster = function() {
- if(NETDATA.globalSelectionSync.state === this)
- return true;
- else
- return false;
+ return (NETDATA.globalSelectionSync.state === this);
};
// this chart is the master of the global selection sync
var targets = NETDATA.options.targets;
var len = targets.length;
while(len--) {
- st = targets[len];
+ var st = targets[len];
if(st === this) {
if(this.debug === true)
// can the chart participate to the global selection sync as a slave?
this.globalSelectionSyncIsEligible = function() {
- if(this.enabled === true
+ return (this.enabled === true
&& this.library !== null
&& typeof this.library.setSelection === 'function'
&& this.isVisible() === true
- && this.chart_created === true)
- return true;
-
- return false;
+ && this.chart_created === true);
};
// this chart becomes a slave of the global selection sync
// sync all the visible charts to the given time
// this is to be called from the chart libraries
this.globalSelectionSync = function(t) {
- if(this.globalSelectionSyncAbility() === false) {
- if(this.debug === true)
- this.log('sync: cannot sync (yet?).');
-
+ if(this.globalSelectionSyncAbility() === false)
return;
- }
if(this.globalSelectionSyncIsMaster() === false) {
if(this.debug === true)
this.globalSelectionSyncBeMaster();
- if(this.globalSelectionSyncAbility() === false) {
- if(this.debug === true)
- this.log('sync: cannot sync (yet?).');
-
+ if(this.globalSelectionSyncAbility() === false)
return;
- }
}
NETDATA.globalSelectionSync.last_t = t;
};
this.setSelection = function(t) {
- if(typeof this.library.setSelection === 'function') {
- if(this.library.setSelection(this, t) === true)
- this.selected = true;
- else
- this.selected = false;
- }
- else this.selected = true;
+ if(typeof this.library.setSelection === 'function')
+ this.selected = (this.library.setSelection(this, t) === true);
+ else
+ this.selected = true;
if(this.selected === true && this.debug === true)
this.log('selection set to ' + t.toString());
this.clearSelection = function() {
if(this.selected === true) {
- if(typeof this.library.clearSelection === 'function') {
- if(this.library.clearSelection(this) === true)
- this.selected = false;
- else
- this.selected = true;
- }
- else this.selected = false;
+ if(typeof this.library.clearSelection === 'function')
+ this.selected = (this.library.clearSelection(this) !== true);
+ else
+ this.selected = false;
if(this.selected === false && this.debug === true)
this.log('selection cleared');
// find if a timestamp (ms) is shown in the current chart
this.timeIsVisible = function(t) {
- if(t >= this.data_after && t <= this.data_before)
- return true;
- return false;
+ return (t >= this.data_after && t <= this.data_before);
};
this.calculateRowForTime = function(t) {
if(this.debug === true)
this.log(logme + 'ACCEPTING UPDATE: current/min duration: ' + (current_duration / 1000).toString() + '/' + (this.fixed_min_duration / 1000).toString() + ', wanted duration: ' + (wanted_duration / 1000).toString() + ', duration diff: ' + (Math.round(Math.abs(current_duration - wanted_duration) / 1000)).toString() + ', movement: ' + (movement / 1000).toString() + ', tolerance: ' + (tolerance / 1000).toString() + ', returning: ' + ret);
- this.current.force_update_at = new Date().getTime() + NETDATA.options.current.pan_and_zoom_delay;
+ this.current.force_update_at = Date.now() + NETDATA.options.current.pan_and_zoom_delay;
this.current.force_after_ms = after;
this.current.force_before_ms = before;
NETDATA.globalPanAndZoom.setMaster(this, after, before);
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;
-
- 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) {
if(typeof series === 'undefined') return;
if(series.value === null && series.user === null) return;
+ /*
+ // this slows down firefox and edge significantly
+ // since it requires to use innerHTML(), instead of innerText()
+
// if the value has not changed, skip DOM update
//if(series.last === value) return;
else s += '<i class="fa fa-angle-left" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
}
else s += '<i class="fa fa-angle-right" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
+
series.last = v;
}
else {
- s = r = value;
+ if(value === null)
+ s = r = '';
+ else
+ s = r = value;
+
series.last = value;
}
+ */
+
+ var s = this.legendFormatValue(value);
+
+ // caching: do not update the update to show the same value again
+ if(s === series.last_shown_value) return;
+ series.last_shown_value = s;
+
+ if(series.value !== null) series.value.innerText = s;
+ if(series.user !== null) series.user.innerText = s;
+ };
+
+ this.__legendSetDateString = function(date) {
+ if(date !== this.__last_shown_legend_date) {
+ this.element_legend_childs.title_date.innerText = date;
+ this.__last_shown_legend_date = date;
+ }
+ };
+
+ this.__legendSetTimeString = function(time) {
+ if(time !== this.__last_shown_legend_time) {
+ this.element_legend_childs.title_time.innerText = time;
+ this.__last_shown_legend_time = time;
+ }
+ };
+
+ this.__legendSetUnitsString = function(units) {
+ if(units !== this.__last_shown_legend_units) {
+ this.element_legend_childs.title_units.innerText = units;
+ this.__last_shown_legend_units = units;
+ }
+ };
- if(series.value !== null) series.value.innerHTML = s;
- if(series.user !== null) series.user.innerHTML = r;
+ this.legendSetDateLast = {
+ ms: 0,
+ date: undefined,
+ time: undefined
};
this.legendSetDate = function(ms) {
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.element_legend_childs.title_date.innerHTML = d.toLocaleDateString();
+ if(this.element_legend_childs.title_date !== null)
+ this.__legendSetDateString(this.legendSetDateLast.date);
- if(this.element_legend_childs.title_time)
- this.element_legend_childs.title_time.innerHTML = d.toLocaleTimeString();
+ if(this.element_legend_childs.title_time !== null)
+ this.__legendSetTimeString(this.legendSetDateLast.time);
- if(this.element_legend_childs.title_units)
- this.element_legend_childs.title_units.innerHTML = this.units;
+ if(this.element_legend_childs.title_units !== null)
+ this.__legendSetUnitsString(this.units)
};
this.legendShowUndefined = function() {
- if(this.element_legend_childs.title_date)
- this.element_legend_childs.title_date.innerHTML = ' ';
+ if(this.element_legend_childs.title_date !== null)
+ this.__legendSetDateString(' ');
- if(this.element_legend_childs.title_time)
- this.element_legend_childs.title_time.innerHTML = this.chart.name;
+ if(this.element_legend_childs.title_time !== null)
+ this.__legendSetTimeString(this.chart.name);
- if(this.element_legend_childs.title_units)
- this.element_legend_childs.title_units.innerHTML = ' ';
+ if(this.element_legend_childs.title_units !== null)
+ this.__legendSetUnitsString(' ');
if(this.data && this.element_legend_childs.series !== null) {
var labels = this.data.dimension_names;
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.chartColors = function() {
if(this.colors !== null) return this.colors;
- this.colors = new Array();
- this.colors_available = new Array();
+ this.colors = [];
+ this.colors_available = [];
// add the standard colors
var len = NETDATA.themes.current.colors.length;
};
this.legendUpdateDOM = function() {
- var needed = false;
+ var needed = false, dim, keys, len, i;
// check that the legend DOM is up to date for the downloaded dimensions
if(typeof this.element_legend_childs.series !== 'object' || this.element_legend_childs.series === null) {
if(this.colors === null) {
// this is the first time we update the chart
// let's assign colors to all dimensions
- if(this.library.track_colors() === true)
- for(var dim in this.chart.dimensions)
- this._chartDimensionColor(this.chart.dimensions[dim].name);
+ if(this.library.track_colors() === true) {
+ keys = Object.keys(this.chart.dimensions);
+ len = keys.length;
+ for(i = 0; i < len ;i++)
+ this._chartDimensionColor(this.chart.dimensions[keys[i]].name);
+ }
}
// we will re-generate the colors for the chart
// based on the selected dimensions
var color = state._chartDimensionColor(name);
var user_element = null;
- var user_id = self.data('show-value-of-' + dim + '-at') || null;
+ var user_id = self.data('show-value-of-' + name.toLowerCase() + '-at') || null;
+ if(user_id === null)
+ user_id = self.data('show-value-of-' + dim.toLowerCase() + '-at') || null;
if(user_id !== null) {
user_element = document.getElementById(user_id) || null;
- if(user_element === null)
+ if (user_element === null)
state.log('Cannot find element with id: ' + user_id);
}
name: document.createElement('span'),
value: document.createElement('span'),
user: user_element,
- last: null
+ last: null,
+ last_shown_value: null
};
var label = state.element_legend_childs.series[name];
+ state.chart.chart_type
+ '" style="background-color: '
+ 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ')'
- + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>'
+ + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>';
var text = document.createTextNode(' ' + name);
label.name.appendChild(text);
title_date: document.createElement('span'),
title_time: document.createElement('span'),
title_units: document.createElement('span'),
- nano: document.createElement('div'),
- nano_options: {
- paneClass: 'netdata-legend-series-pane',
- sliderClass: 'netdata-legend-series-slider',
- contentClass: 'netdata-legend-series-content',
- enabledClass: '__enabled',
- flashedClass: '__flashed',
- activeClass: '__active',
- tabIndex: -1,
- alwaysVisible: true,
- sliderMinHeight: 10
- },
+ perfect_scroller: document.createElement('div'),
series: {}
};
if(this.library.toolboxPanAndZoom !== null) {
- function get_pan_and_zoom_step(event) {
+ var get_pan_and_zoom_step = function(event) {
if (event.ctrlKey)
return NETDATA.options.current.pan_and_zoom_factor * NETDATA.options.current.pan_and_zoom_factor_multiplier_control;
else
return NETDATA.options.current.pan_and_zoom_factor;
- }
+ };
this.element_legend_childs.toolbox.className += ' netdata-legend-toolbox';
this.element.appendChild(this.element_legend_childs.toolbox);
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'));
- this.element_legend_childs.nano.className = 'netdata-legend-series';
- this.element_legend.appendChild(this.element_legend_childs.nano);
+ this.element_legend_childs.perfect_scroller.className = 'netdata-legend-series';
+ this.element_legend.appendChild(this.element_legend_childs.perfect_scroller);
content.className = 'netdata-legend-series-content';
- this.element_legend_childs.nano.appendChild(content);
+ this.element_legend_childs.perfect_scroller.appendChild(content);
if(NETDATA.options.current.show_help === true)
$(content).popover({
placement: 'bottom',
title: 'Chart Legend',
delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
- content: 'You can click or tap on the values or the labels to select dimentions. By pressing SHIFT or CONTROL, you can enable or disable multiple dimensions.<br/><small>Help, can be disabled from the settings.</small>'
+ content: 'You can click or tap on the values or the labels to select dimensions. By pressing SHIFT or CONTROL, you can enable or disable multiple dimensions.<br/><small>Help, can be disabled from the settings.</small>'
});
}
else {
title_date: null,
title_time: null,
title_units: null,
- nano: null,
- nano_options: null,
+ perfect_scroller: null,
series: {}
};
}
if(this.debug === true)
this.log('labels from data: "' + this.element_legend_childs.series.labels_key + '"');
- for(var i = 0, len = this.data.dimension_names.length; i < len ;i++) {
+ for(i = 0, len = this.data.dimension_names.length; i < len ;i++) {
genLabel(this, content, this.data.dimension_ids[i], this.data.dimension_names[i], i);
}
}
else {
- var tmp = new Array();
- for(var dim in this.chart.dimensions) {
+ var tmp = [];
+ keys = Object.keys(this.chart.dimensions);
+ for(i = 0, len = keys.length; i < len ;i++) {
+ dim = keys[i];
tmp.push(this.chart.dimensions[dim].name);
genLabel(this, content, dim, this.chart.dimensions[dim].name, i);
}
this.element_legend_childs.hidden = document.createElement('div');
el.appendChild(this.element_legend_childs.hidden);
- if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
- $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
+ if(this.element_legend_childs.perfect_scroller !== null) {
+ Ps.initialize(this.element_legend_childs.perfect_scroller, {
+ wheelSpeed: 0.2,
+ wheelPropagation: true,
+ swipePropagation: true,
+ minScrollbarLength: null,
+ maxScrollbarLength: null,
+ useBothWheelAxes: false,
+ suppressScrollX: true,
+ suppressScrollY: false,
+ scrollXMarginOffset: 0,
+ scrollYMarginOffset: 0,
+ theme: 'default'
+ });
+ Ps.update(this.element_legend_childs.perfect_scroller);
+ }
this.legendShowLatestValues();
};
this.data_url += "&format=" + this.library.format();
this.data_url += "&points=" + (this.data_points * points_multiplier).toString();
this.data_url += "&group=" + this.method;
- this.data_url += "&options=" + this.library.options(this);
+
+ if(this.override_options !== null)
+ this.data_url += "&options=" + this.override_options.toString();
+ else
+ this.data_url += "&options=" + this.library.options(this);
+
this.data_url += '|jsonwrap';
if(NETDATA.options.current.eliminate_zero_dimensions === true)
this.updates_since_last_unhide++;
this.updates_since_last_creation++;
- var started = new Date().getTime();
+ var started = Date.now();
// if the result is JSON, find the latest update-every
this.data_update_every = data.view_update_every * 1000;
if(NETDATA.options.current.pan_and_zoom_data_padding === true && this.requested_padding !== null) {
if(this.view_after < this.data_after) {
- // console.log('adusting view_after from ' + this.view_after + ' to ' + this.data_after);
+ // console.log('adjusting view_after from ' + this.view_after + ' to ' + this.data_after);
this.view_after = this.data_after;
}
if(this.view_before > this.data_before) {
- // console.log('adusting view_before from ' + this.view_before + ' to ' + this.data_before);
+ // console.log('adjusting view_before from ' + this.view_before + ' to ' + this.data_before);
this.view_before = this.data_before;
}
}
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
NETDATA.globalSelectionSync.stop();
// update the performance counters
- var now = new Date().getTime();
+ var now = Date.now();
this.tm.last_updated = now;
// don't update last_autorefreshed if this chart is
NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
if(this.refresh_dt_element !== null)
- this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
+ this.refresh_dt_element.innerText = this.refresh_dt_ms.toString();
};
this.updateChart = function(callback) {
if(this.debug === true)
this.log('I am already updating...');
- if(typeof callback === 'function') callback();
- return false;
+ if(typeof callback === 'function')
+ return callback();
+
+ return;
}
// due to late initialization of charts and libraries
if(this.debug === true)
this.log('I am not enabled');
- if(typeof callback === 'function') callback();
- return false;
+ if(typeof callback === 'function')
+ return callback();
+
+ return;
}
if(canBeRendered() === false) {
- if(typeof callback === 'function') callback();
- return false;
- }
+ if(typeof callback === 'function')
+ return callback();
- if(this.chart === null) {
- this.getChart(function() { that.updateChart(callback); });
- return false;
+ return;
}
+ if(this.chart === null)
+ return this.getChart(function() {
+ return that.updateChart(callback);
+ });
+
if(this.library.initialized === false) {
if(this.library.enabled === true) {
- this.library.initialize(function() { that.updateChart(callback); });
- return false;
+ return this.library.initialize(function () {
+ return that.updateChart(callback);
+ });
}
else {
error('chart library "' + this.library_name + '" is not available.');
- if(typeof callback === 'function') callback();
- return false;
+
+ if(typeof callback === 'function')
+ return callback();
+
+ return;
}
}
})
.done(function(data) {
that.xhr = undefined;
+ that.retries_on_data_failures = 0;
if(that.debug === true)
that.log('data received. updating chart.');
.fail(function(msg) {
that.xhr = undefined;
- if(msg.statusText !== 'abort')
- error('data download failed for url: ' + that.data_url);
+ if(msg.statusText !== 'abort') {
+ that.retries_on_data_failures++;
+ if(that.retries_on_data_failures > NETDATA.options.current.retries_on_data_failures) {
+ // that.log('failed ' + that.retries_on_data_failures.toString() + ' times - giving up');
+ that.retries_on_data_failures = 0;
+ error('data download failed for url: ' + that.data_url);
+ }
+ else {
+ that.tm.last_autorefreshed = Date.now();
+ // that.log('failed ' + that.retries_on_data_failures.toString() + ' times, but I will retry');
+ }
+ }
})
.always(function() {
that.xhr = undefined;
NETDATA.statistics.refreshes_active--;
that._updating = false;
- if(typeof callback === 'function') callback();
- });
- return true;
+ if(typeof callback === 'function')
+ return callback();
+ });
};
this.isVisible = function(nocache) {
if(nocache === false && this.tm.last_visible_check > NETDATA.options.last_page_scroll)
return this.___isVisible___;
- this.tm.last_visible_check = new Date().getTime();
+ this.tm.last_visible_check = Date.now();
var wh = window.innerHeight;
var x = this.element.getBoundingClientRect();
};
this.canBeAutoRefreshed = function() {
- var now = new Date().getTime();
+ var now = Date.now();
if(this.running === true) {
if(this.debug === true)
state.running = false;
if(typeof callback !== 'undefined')
- callback();
+ return callback();
});
}
else {
if(typeof callback !== 'undefined')
- callback();
+ return callback();
}
};
this.chart_url = chart.url;
this.data_update_every = chart.update_every * 1000;
this.data_points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
- this.tm.last_info_downloaded = new Date().getTime();
+ this.tm.last_info_downloaded = Date.now();
if(this.title === null)
this.title = chart.title;
this.chart = NETDATA.chartRegistry.get(this.host, this.id);
if(this.chart) {
this._defaultsFromDownloadedChart(this.chart);
- if(typeof callback === 'function') callback();
+
+ if(typeof callback === 'function')
+ return callback();
}
else {
this.chart_url = "/api/v1/chart?chart=" + this.id;
error('chart not found on url "' + that.chart_url + '"');
})
.always(function() {
- if(typeof callback === 'function') callback();
+ if(typeof callback === 'function')
+ return callback();
});
}
};
script.src = NETDATA.jQuery;
// script.onabort = onError;
- script.onerror = function(err, t) { NETDATA.error(101, NETDATA.jQuery); };
+ script.onerror = function() { NETDATA.error(101, NETDATA.jQuery); };
if(typeof callback === "function")
script.onload = callback;
s.parentNode.insertBefore(script, s);
}
else if(typeof callback === "function")
- callback();
+ return callback();
};
NETDATA._loadCSS = function(filename) {
};
NETDATA.pause = function(callback) {
- if(NETDATA.options.pause === true)
- callback();
- else
- NETDATA.options.pauseCallback = callback;
+ if(typeof callback === 'function') {
+ if (NETDATA.options.pause === true)
+ return callback();
+ else
+ NETDATA.options.pauseCallback = callback;
+ }
};
NETDATA.unpause = function() {
// ----------------------------------------------------------------------------------------------------------------
- // this is purely sequencial charts refresher
+ // this is purely sequential charts refresher
// it is meant to be autonomous
NETDATA.chartRefresherNoParallel = function(index) {
- if(NETDATA.options.debug.mail_loop === true)
+ if(NETDATA.options.debug.main_loop === true)
console.log('NETDATA.chartRefresherNoParallel(' + index + ')');
if(NETDATA.options.updated_dom === true) {
}
};
- // this is part of the parallel refresher
- // its cause is to refresh sequencially all the charts
- // that depend on chart library initialization
- // it will call the parallel refresher back
- // as soon as it sees a chart that its chart library
- // is initialized
- NETDATA.chartRefresher_uninitialized = function() {
- if(NETDATA.options.updated_dom === true) {
- // the dom has been updated
- // get the dom parts again
- NETDATA.parseDom(NETDATA.chartRefresher);
- return;
- }
-
- if(NETDATA.options.sequencial.length === 0)
- NETDATA.chartRefresher();
- else {
- var state = NETDATA.options.sequencial.pop();
- if(state.library.initialized === true)
- NETDATA.chartRefresher();
- else
- state.autoRefresh(NETDATA.chartRefresher_uninitialized);
- }
- };
-
NETDATA.chartRefresherWaitTime = function() {
return NETDATA.options.current.idle_parallel_loops;
};
// the default refresher
- // it will create 2 sets of charts:
- // - the ones that can be refreshed in parallel
- // - the ones that depend on something else
- // the first set will be executed in parallel
- // the second will be given to NETDATA.chartRefresher_uninitialized()
NETDATA.chartRefresher = function() {
// console.log('auto-refresher...');
return;
}
- var parallel = new Array();
+ var parallel = [];
var targets = NETDATA.options.targets;
var len = targets.length;
var state;
};
NETDATA.parseDom = function(callback) {
- NETDATA.options.last_page_scroll = new Date().getTime();
+ NETDATA.options.last_page_scroll = Date.now();
NETDATA.options.updated_dom = false;
var targets = $('div[data-netdata]'); //.filter(':visible');
if(NETDATA.options.debug.main_loop === true)
console.log('DOM updated - there are ' + targets.length + ' charts on page.');
- NETDATA.options.targets = new Array();
+ NETDATA.options.targets = [];
var len = targets.length;
while(len--) {
// the initialization will take care of sizing
NETDATA.options.targets.push(NETDATA.chartState(targets[len]));
}
- if(typeof callback === 'function') callback();
+ if(typeof callback === 'function')
+ return callback();
};
// this is the main function - where everything starts
$('a[data-toggle="tab"]').on('shown.bs.tab', NETDATA.onscroll);
// bootstrap modal switching
- $('.modal').on('hidden.bs.modal', NETDATA.onscroll);
- $('.modal').on('shown.bs.modal', NETDATA.onscroll);
+ var $modal = $('.modal');
+ $modal.on('hidden.bs.modal', NETDATA.onscroll);
+ $modal.on('shown.bs.modal', NETDATA.onscroll);
// bootstrap collapse switching
- $('.collapse').on('hidden.bs.collapse', NETDATA.onscroll);
- $('.collapse').on('shown.bs.collapse', NETDATA.onscroll);
+ var $collapse = $('.collapse');
+ $collapse.on('hidden.bs.collapse', NETDATA.onscroll);
+ $collapse.on('shown.bs.collapse', NETDATA.onscroll);
NETDATA.parseDom(NETDATA.chartRefresher);
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.peity.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.sparkline.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
var self = $(state.element);
var type = self.data('sparkline-type') || 'line';
var lineColor = self.data('sparkline-linecolor') || state.chartColors()[0];
- var fillColor = self.data('sparkline-fillcolor') || (state.chart.chart_type === 'line')?NETDATA.themes.current.background:NETDATA.colorLuminance(lineColor, NETDATA.chartDefaults.fill_luminance);
+ var fillColor = self.data('sparkline-fillcolor') || ((state.chart.chart_type === 'line')?NETDATA.themes.current.background:NETDATA.colorLuminance(lineColor, NETDATA.chartDefaults.fill_luminance));
var chartRangeMin = self.data('sparkline-chartrangemin') || undefined;
var chartRangeMax = self.data('sparkline-chartrangemax') || undefined;
var composite = self.data('sparkline-composite') || undefined;
if(minSpotColor === 'disable') minSpotColor='';
if(maxSpotColor === 'disable') maxSpotColor='';
+ // state.log('sparkline type ' + type + ', lineColor: ' + lineColor + ', fillColor: ' + fillColor);
+
state.sparkline_options = {
type: type,
lineColor: lineColor,
return true;
};
- NETDATA.dygraphClearSelection = function(state, t) {
+ NETDATA.dygraphClearSelection = function(state) {
if(typeof state.dygraph_instance !== 'undefined') {
state.dygraph_instance.clearSelection();
}
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
};
if(NETDATA.chartLibraries.dygraph.enabled === true && NETDATA.options.current.smooth_plot === true)
NETDATA.dygraphSmoothInitialize(callback);
else if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.dygraph.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
state.log('dygraphChartUpdate() forced zoom update');
options.dateWindow = (state.requested_padding !== null)?[ state.view_after, state.view_before ]:null;
- options.valueRange = state.dygraph_options.valueRange;
options.isZoomedIgnoreProgrammaticZoom = true;
state.dygraph_force_zoom = false;
}
else if(state.current.name !== 'auto') {
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphChartUpdate() loose update');
-
- options.valueRange = state.dygraph_options.valueRange;
}
else {
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphChartUpdate() strict update');
options.dateWindow = (state.requested_padding !== null)?[ state.view_after, state.view_before ]:null;
- options.valueRange = state.dygraph_options.valueRange;
options.isZoomedIgnoreProgrammaticZoom = true;
}
+ options.valueRange = state.dygraph_options.valueRange;
+
+ var oldMax = null, oldMin = null;
+ if(state.__commonMin !== null) {
+ state.data.min = state.dygraph_instance.axes_[0].extremeRange[0];
+ oldMin = options.valueRange[0] = NETDATA.commonMin.get(state);
+ }
+ if(state.__commonMax !== null) {
+ state.data.max = state.dygraph_instance.axes_[0].extremeRange[1];
+ oldMax = options.valueRange[1] = NETDATA.commonMax.get(state);
+ }
+
if(state.dygraph_smooth_eligible === true) {
if((NETDATA.options.current.smooth_plot === true && state.dygraph_options.plotter !== smoothPlotter)
|| (NETDATA.options.current.smooth_plot === false && state.dygraph_options.plotter === smoothPlotter)) {
dygraph.updateOptions(options);
- state.dygraph_last_rendered = new Date().getTime();
+ var redraw = false;
+ if(oldMin !== null && oldMin > state.dygraph_instance.axes_[0].extremeRange[0]) {
+ state.data.min = state.dygraph_instance.axes_[0].extremeRange[0];
+ options.valueRange[0] = NETDATA.commonMin.get(state);
+ redraw = true;
+ }
+ if(oldMax !== null && oldMax < state.dygraph_instance.axes_[0].extremeRange[1]) {
+ state.data.max = state.dygraph_instance.axes_[0].extremeRange[1];
+ options.valueRange[1] = NETDATA.commonMax.get(state);
+ redraw = true;
+ }
+
+ if(redraw === true) {
+ // state.log('forcing redraw to adapt to common- min/max');
+ dygraph.updateOptions(options);
+ }
+
+ state.dygraph_last_rendered = Date.now();
return true;
};
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))?true:false;
- smooth = self.data('dygraph-smooth') || smooth;
- if(NETDATA.dygraph.smooth === false)
- smooth = false;
+ var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state) === true)?3:4;
- 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', // 'onmouseover',
- 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')? true : false),
- xRangePad: self.data('dygraph-xrangepad') || 0,
- yRangePad: self.data('dygraph-yrangepad') || 1,
-
- valueRange: self.data('dygraph-valuerange') || 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')?true:false,
- 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')?true:false,
- 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') || 0.3,
-
- drawGrid: self.data('dygraph-drawgrid') || true,
- gridLinePattern: self.data('dygraph-gridlinepattern') || null,
- gridLineWidth: self.data('dygraph-gridlinewidth') || 0.4,
- 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,
ticker: Dygraph.dateTicker,
axisLabelFormatter: function (d, gran) {
+ void(gran);
return NETDATA.zeropad(d.getHours()) + ":" + NETDATA.zeropad(d.getMinutes()) + ":" + NETDATA.zeropad(d.getSeconds());
- },
- valueFormatter: function (ms) {
- var d = new Date(ms);
- return d.toLocaleDateString() + ' ' + d.toLocaleTimeString();
- // return NETDATA.zeropad(d.getHours()) + ":" + NETDATA.zeropad(d.getMinutes()) + ":" + NETDATA.zeropad(d.getSeconds());
}
},
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);
}
}
},
var i = data.series.length;
while(i--) {
var series = data.series[i];
- if(!series.isVisible) continue;
- state.legendSetLabelValue(series.label, series.y);
+ if(series.isVisible === true)
+ state.legendSetLabelValue(series.label, series.y);
+ else
+ state.legendSetLabelValue(series.label, null);
}
}
}
},
zoomCallback: function(minDate, maxDate, yRanges) {
+ void(yRanges);
+
if(NETDATA.options.debug.dygraph === true)
state.log('dygraphZoomCallback()');
state.updateChartPanOrZoom(minDate, maxDate);
},
highlightCallback: function(event, x, points, row, seriesName) {
+ void(seriesName);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphHighlightCallback()');
// the time it thinks is selected is wrong
// here we calculate the time t based on the row number selected
// which is ok
- var t = state.data_after + row * state.data_update_every;
+ // var t = state.data_after + row * state.data_update_every;
// console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t === x)?'SAME':(Math.abs(x-t)<=state.data_update_every)?'SIMILAR':'DIFFERENT') + ', rows in db: ' + state.data_points + ' visible(x) = ' + state.timeIsVisible(x) + ' visible(t) = ' + state.timeIsVisible(t) + ' r(x) = ' + state.calculateRowForTime(x) + ' r(t) = ' + state.calculateRowForTime(t) + ' range: ' + state.data_after + ' - ' + state.data_before + ' real: ' + state.data.after + ' - ' + state.data.before + ' every: ' + state.data_update_every);
state.globalSelectionSync(x);
// state.dygraph_instance.plugins_[0].plugin.legend_div_.style.zIndex = 10000;
},
unhighlightCallback: function(event) {
+ void(event);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('dygraphUnhighlightCallback()');
state.globalSelectionSyncStop();
state.globalSelectionSyncDelay();
state.setMode('pan');
+ context.is2DPan = false;
Dygraph.movePan(event, dygraph, context);
}
else if(context.isZooming) {
}
},
click: function(event, dygraph, context) {
+ void(dygraph);
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('interactionModel.click()');
event.preventDefault();
},
dblclick: function(event, dygraph, context) {
+ void(event);
+ void(dygraph);
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
state.log('interactionModel.dblclick()');
NETDATA.resetAllCharts(state);
},
- mousewheel: function(event, dygraph, context) {
+ wheel: function(event, dygraph, context) {
+ void(context);
+
if(NETDATA.options.debug.dygraph === true || state.debug === true)
- state.log('interactionModel.mousewheel()');
+ state.log('interactionModel.wheel()');
// Take the offset of a mouse event on the dygraph canvas and
// convert it to a pair of percentages from the bottom left.
var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
var yar0 = g.yAxisRange(0);
- // This is calculating the pixel of the higest value. (Top pixel)
+ // This is calculating the pixel of the highest value. (Top pixel)
var yOffset = g.toDomCoords(null, yar0[1])[1];
// x y w and h are relative to the corner of the drawing area,
state.globalSelectionSyncDelay();
// http://dygraphs.com/gallery/interaction-api.js
- var normal = (event.detail) ? event.detail * -1 : event.wheelDelta / 40;
+ var normal_def;
+ if(typeof event.wheelDelta === 'number' && !isNaN(event.wheelDelta))
+ // chrome
+ normal_def = event.wheelDelta / 40;
+ else
+ // firefox
+ normal_def = event.deltaY * -1.2;
+
+ var normal = (event.detail) ? event.detail * -1 : normal_def;
var percentage = normal / 50;
if (!(event.offsetX && event.offsetY)){
var yPct = percentages[1];
var new_x_range = zoomRange(dygraph, percentage, xPct, yPct);
-
var after = new_x_range[0];
var before = new_x_range[1];
Dygraph.defaultInteractionModel.touchstart(event, dygraph, context);
// we overwrite the touch directions at the end, to overwrite
- // the internal default of dygraphs
+ // the internal default of dygraph
context.touchDirections = { x: true, y: false };
- state.dygraph_last_touch_start = new Date().getTime();
+ state.dygraph_last_touch_start = Date.now();
state.dygraph_last_touch_move = 0;
if(typeof event.touches[0].pageX === 'number')
state.dygraph_user_action = true;
Dygraph.defaultInteractionModel.touchmove(event, dygraph, context);
- state.dygraph_last_touch_move = new Date().getTime();
+ state.dygraph_last_touch_move = Date.now();
},
touchend: function(event, dygraph, context) {
if(NETDATA.options.debug.dygraph === true || state.debug === true)
// if it didn't move, it is a selection
if(state.dygraph_last_touch_move === 0 && state.dygraph_last_touch_page_x !== 0) {
- // internal api of dygraphs
+ // internal api of dygraph
var pct = (state.dygraph_last_touch_page_x - (dygraph.plotter_.area.x + state.element.getBoundingClientRect().left)) / dygraph.plotter_.area.w;
var t = Math.round(state.data_after + (state.data_before - state.data_after) * pct);
if(NETDATA.dygraphSetSelection(state, t) === true)
}
// if it was double tap within double click time, reset the charts
- var now = new Date().getTime();
+ var now = Date.now();
if(typeof state.dygraph_last_touch_end !== 'undefined') {
if(state.dygraph_last_touch_move === 0) {
var dt = now - state.dygraph_last_touch_end;
state.dygraph_force_zoom = false;
state.dygraph_user_action = false;
- state.dygraph_last_rendered = new Date().getTime();
+ state.dygraph_last_rendered = Date.now();
+
+ if(typeof state.dygraph_instance.axes_[0].extremeRange !== 'undefined') {
+ state.__commonMin = self.data('common-min') || null;
+ state.__commonMax = self.data('common-max') || null;
+ }
+ else {
+ state.log('incompatible version of Dygraph detected');
+ state.__commonMin = null;
+ state.__commonMax = null;
+ }
+
return true;
};
else {
NETDATA.chartLibraries.morris.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
}
else {
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
}
else {
NETDATA.chartLibraries.morris.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.raphael.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
else {
NETDATA.chartLibraries.c3.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
}
else {
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
}
else {
NETDATA.chartLibraries.c3.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.d3.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
NETDATA.d3ChartUpdate = function(state, data) {
+ void(state);
+ void(data);
+
return false;
};
NETDATA.d3ChartCreate = function(state, data) {
+ void(state);
+ void(data);
+
return false;
};
NETDATA.chartLibraries.google.enabled = false;
NETDATA.error(100, NETDATA.google_js);
if(typeof callback === "function")
- callback();
+ return callback();
});
}
else {
NETDATA.chartLibraries.google.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
// ----------------------------------------------------------------------------------------------------------------
- NETDATA.percentFromValueMax = function(value, max) {
- if(value === null) value = 0;
+ NETDATA.easypiechartPercentFromValueMinMax = function(value, min, max) {
+ if(typeof value !== 'number') value = 0;
+ if(typeof min !== 'number') min = 0;
+ if(typeof max !== 'number') max = 0;
+
+ if(min > value) min = value;
if(max < value) max = value;
+ // make sure it is zero based
+ if(min > 0) min = 0;
+ if(max < 0) max = 0;
+
var pcent = 0;
- if(max !== 0) {
- pcent = Math.round(value * 100 / max);
- if(pcent === 0 && value > 0) pcent = 1;
+ if(value >= 0) {
+ if(max !== 0)
+ pcent = Math.round(value * 100 / max);
+ if(pcent === 0) pcent = 0.1;
+ }
+ else {
+ if(min !== 0)
+ pcent = Math.round(-value * 100 / min);
+ if(pcent === 0) pcent = -0.1;
}
return pcent;
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
})
}
else {
NETDATA.chartLibraries.easypiechart.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
NETDATA.easypiechartClearSelection = function(state) {
if(typeof state.easyPieChartEvent !== 'undefined') {
- if(state.easyPieChartEvent.timer !== null)
+ if(state.easyPieChartEvent.timer !== undefined) {
clearTimeout(state.easyPieChartEvent.timer);
+ }
- state.easyPieChartEvent.timer = null;
+ state.easyPieChartEvent.timer = undefined;
}
if(state.isAutoRefreshable() === true && state.data !== null) {
NETDATA.easypiechartChartUpdate(state, state.data);
}
else {
- state.easyPieChartLabel.innerHTML = state.legendFormatValue(null);
+ state.easyPieChartLabel.innerText = state.legendFormatValue(null);
state.easyPieChart_instance.update(0);
}
state.easyPieChart_instance.enableAnimation();
if(typeof state.easyPieChartEvent === 'undefined') {
state.easyPieChartEvent = {
- timer: null,
+ timer: undefined,
value: 0,
pcent: 0
};
}
var value = state.data.result[state.data.result.length - 1 - slot];
- var max = (state.easyPieChartMax === null)?state.data.max:state.easyPieChartMax;
- var pcent = NETDATA.percentFromValueMax(value, max);
+ var min = (state.easyPieChartMin === null)?NETDATA.commonMin.get(state):state.easyPieChartMin;
+ var max = (state.easyPieChartMax === null)?NETDATA.commonMax.get(state):state.easyPieChartMax;
+ var pcent = NETDATA.easypiechartPercentFromValueMinMax(value, min, max);
state.easyPieChartEvent.value = value;
state.easyPieChartEvent.pcent = pcent;
- state.easyPieChartLabel.innerHTML = state.legendFormatValue(value);
+ state.easyPieChartLabel.innerText = state.legendFormatValue(value);
- if(state.easyPieChartEvent.timer === null) {
+ if(state.easyPieChartEvent.timer === undefined) {
state.easyPieChart_instance.disableAnimation();
state.easyPieChartEvent.timer = setTimeout(function() {
- state.easyPieChartEvent.timer = null;
+ state.easyPieChartEvent.timer = undefined;
state.easyPieChart_instance.update(state.easyPieChartEvent.pcent);
}, NETDATA.options.current.charts_selection_animation_delay);
}
};
NETDATA.easypiechartChartUpdate = function(state, data) {
- var value, max, pcent;
+ var value, min, max, pcent;
if(NETDATA.globalPanAndZoom.isActive() === true || state.isAutoRefreshable() === false) {
value = null;
- max = 0;
pcent = 0;
}
else {
value = data.result[0];
- max = (state.easyPieChartMax === null)?data.max:state.easyPieChartMax;
- pcent = NETDATA.percentFromValueMax(value, max);
+ min = (state.easyPieChartMin === null)?NETDATA.commonMin.get(state):state.easyPieChartMin;
+ max = (state.easyPieChartMax === null)?NETDATA.commonMax.get(state):state.easyPieChartMax;
+ pcent = NETDATA.easypiechartPercentFromValueMinMax(value, min, max);
}
- state.easyPieChartLabel.innerHTML = state.legendFormatValue(value);
+ state.easyPieChartLabel.innerText = state.legendFormatValue(value);
state.easyPieChart_instance.update(pcent);
return true;
};
var chart = $(state.element_chart);
var value = data.result[0];
+ var min = self.data('easypiechart-min-value') || null;
var max = self.data('easypiechart-max-value') || null;
var adjust = self.data('easypiechart-adjust') || null;
+ if(min === null) {
+ min = NETDATA.commonMin.get(state);
+ state.easyPieChartMin = null;
+ }
+ else
+ state.easyPieChartMin = min;
+
if(max === null) {
- max = data.max;
+ max = NETDATA.commonMax.get(state);
state.easyPieChartMax = null;
}
else
state.easyPieChartMax = max;
- var pcent = NETDATA.percentFromValueMax(value, max);
+ var pcent = NETDATA.easypiechartPercentFromValueMinMax(value, min, max);
chart.data('data-percent', pcent);
var valuetop = Math.round((size - valuefontsize - (size / 40)) / 2);
state.easyPieChartLabel = document.createElement('span');
state.easyPieChartLabel.className = 'easyPieChartLabel';
- state.easyPieChartLabel.innerHTML = state.legendFormatValue(value);
+ state.easyPieChartLabel.innerText = state.legendFormatValue(value);
state.easyPieChartLabel.style.fontSize = valuefontsize + 'px';
state.easyPieChartLabel.style.top = valuetop.toString() + 'px';
state.element_chart.appendChild(state.easyPieChartLabel);
var titletop = Math.round(valuetop - (titlefontsize * 2) - (size / 40));
state.easyPieChartTitle = document.createElement('span');
state.easyPieChartTitle.className = 'easyPieChartTitle';
- state.easyPieChartTitle.innerHTML = state.title;
+ state.easyPieChartTitle.innerText = state.title;
state.easyPieChartTitle.style.fontSize = titlefontsize + 'px';
state.easyPieChartTitle.style.lineHeight = titlefontsize + 'px';
state.easyPieChartTitle.style.top = titletop.toString() + 'px';
var unittop = Math.round(valuetop + (valuefontsize + unitfontsize) + (size / 40));
state.easyPieChartUnits = document.createElement('span');
state.easyPieChartUnits.className = 'easyPieChartUnits';
- state.easyPieChartUnits.innerHTML = state.units;
+ state.easyPieChartUnits.innerText = state.units;
state.easyPieChartUnits.style.fontSize = unitfontsize + 'px';
state.easyPieChartUnits.style.top = unittop.toString() + 'px';
state.element_chart.appendChild(state.easyPieChartUnits);
trackWidth: self.data('easypiechart-trackwidth') || undefined,
size: self.data('easypiechart-size') || size,
rotate: self.data('easypiechart-rotate') || 0,
- animate: self.data('easypiechart-rotate') || {duration: 500, enabled: true},
+ animate: self.data('easypiechart-animate') || {duration: 500, enabled: true},
easing: self.data('easypiechart-easing') || undefined
});
})
.always(function() {
if(typeof callback === "function")
- callback();
+ return callback();
})
}
else {
NETDATA.chartLibraries.gauge.enabled = false;
if(typeof callback === "function")
- callback();
+ return callback();
}
};
min = max;
max = t;
}
- else if(min == max)
+ else if(min === max)
max = min + 1;
// gauge.js has an issue if the needle
// 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);
NETDATA.gaugeSetLabels = function(state, value, min, max) {
if(state.___gaugeOld__.valueLabel !== value) {
state.___gaugeOld__.valueLabel = value;
- state.gaugeChartLabel.innerHTML = state.legendFormatValue(value);
+ state.gaugeChartLabel.innerText = state.legendFormatValue(value);
}
if(state.___gaugeOld__.minLabel !== min) {
state.___gaugeOld__.minLabel = min;
- state.gaugeChartMin.innerHTML = state.legendFormatValue(min);
+ state.gaugeChartMin.innerText = state.legendFormatValue(min);
}
if(state.___gaugeOld__.maxLabel !== max) {
state.___gaugeOld__.maxLabel = max;
- state.gaugeChartMax.innerHTML = state.legendFormatValue(max);
+ state.gaugeChartMax.innerText = state.legendFormatValue(max);
}
};
NETDATA.gaugeClearSelection = function(state) {
if(typeof state.gaugeEvent !== 'undefined') {
- if(state.gaugeEvent.timer !== null)
+ if(state.gaugeEvent.timer !== undefined) {
clearTimeout(state.gaugeEvent.timer);
+ }
- state.gaugeEvent.timer = null;
+ state.gaugeEvent.timer = undefined;
}
if(state.isAutoRefreshable() === true && state.data !== null) {
if(typeof state.gaugeEvent === 'undefined') {
state.gaugeEvent = {
- timer: null,
+ timer: undefined,
value: 0,
min: 0,
max: 0
}
var value = state.data.result[state.data.result.length - 1 - slot];
- var max = (state.gaugeMax === null)?state.data.max:state.gaugeMax;
- var min = 0;
+ var min = (state.gaugeMin === null)?NETDATA.commonMin.get(state):state.gaugeMin;
+ var max = (state.gaugeMax === null)?NETDATA.commonMax.get(state):state.gaugeMax;
+
+ // make sure it is zero based
+ if(min > 0) min = 0;
+ if(max < 0) max = 0;
state.gaugeEvent.value = value;
- state.gaugeEvent.max = max;
state.gaugeEvent.min = min;
+ state.gaugeEvent.max = max;
NETDATA.gaugeSetLabels(state, value, min, max);
- if(state.gaugeEvent.timer === null) {
+ if(state.gaugeEvent.timer === undefined) {
NETDATA.gaugeAnimation(state, false);
state.gaugeEvent.timer = setTimeout(function() {
- state.gaugeEvent.timer = null;
+ state.gaugeEvent.timer = undefined;
NETDATA.gaugeSet(state, state.gaugeEvent.value, state.gaugeEvent.min, state.gaugeEvent.max);
}, NETDATA.options.current.charts_selection_animation_delay);
}
}
else {
value = data.result[0];
- min = 0;
- max = (state.gaugeMax === null)?data.max:state.gaugeMax;
+ min = (state.gaugeMin === null)?NETDATA.commonMin.get(state):state.gaugeMin;
+ max = (state.gaugeMax === null)?NETDATA.commonMax.get(state):state.gaugeMax;
+ if(value < min) min = value;
if(value > max) max = value;
+
+ // make sure it is zero based
+ if(min > 0) min = 0;
+ if(max < 0) max = 0;
+
NETDATA.gaugeSetLabels(state, value, min, max);
}
// var chart = $(state.element_chart);
var value = data.result[0];
+ var min = self.data('gauge-min-value') || null;
var max = self.data('gauge-max-value') || null;
var adjust = self.data('gauge-adjust') || null;
var pointerColor = self.data('gauge-pointer-color') || NETDATA.themes.current.gauge_pointer;
var stopColor = self.data('gauge-stop-color') || void 0;
var generateGradient = self.data('gauge-generate-gradient') || false;
+ if(min === null) {
+ min = NETDATA.commonMin.get(state);
+ state.gaugeMin = null;
+ }
+ else
+ state.gaugeMin = min;
+
if(max === null) {
- max = data.max;
+ max = NETDATA.commonMax.get(state);
state.gaugeMax = null;
}
else
state.gaugeMax = max;
+ // make sure it is zero based
+ if(min > 0) min = 0;
+ if(max < 0) max = 0;
+
var width = state.chartWidth(), height = state.chartHeight(); //, ratio = 1.5;
//switch(adjust) {
// case 'width': width = height * ratio; break;
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)?true:false,
- gradientType: 0
+ generateGradient: (generateGradient === true),
+ gradientType: 0,
+ highDpiSupport: true // High resolution support
};
if (generateGradient.constructor === Array) {
// data-gauge-gradient-percent-color-50="#999900"
// data-gauge-gradient-percent-color-100="#000000"
- options.percentColors = new Array();
+ options.percentColors = [];
var len = generateGradient.length;
while(len--) {
var pcent = generateGradient[len];
var color = self.data('gauge-gradient-percent-color-' + pcent.toString()) || false;
if(color !== false) {
- var a = new Array();
+ var a = [];
a[0] = pcent / 100;
a[1] = color;
options.percentColors.unshift(a);
delete options.percentColors;
}
else if(generateGradient === false && NETDATA.themes.current.gauge_gradient === true) {
+ //noinspection PointlessArithmeticExpressionJS
options.percentColors = [
[0.0, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 0))],
[0.1, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 1))],
var titletop = 0;
state.gaugeChartTitle = document.createElement('span');
state.gaugeChartTitle.className = 'gaugeChartTitle';
- state.gaugeChartTitle.innerHTML = state.title;
+ state.gaugeChartTitle.innerText = state.title;
state.gaugeChartTitle.style.fontSize = titlefontsize + 'px';
state.gaugeChartTitle.style.lineHeight = titlefontsize + 'px';
state.gaugeChartTitle.style.top = titletop.toString() + 'px';
var unitfontsize = Math.round(titlefontsize * 0.9);
state.gaugeChartUnits = document.createElement('span');
state.gaugeChartUnits.className = 'gaugeChartUnits';
- state.gaugeChartUnits.innerHTML = state.units;
+ state.gaugeChartUnits.innerText = state.units;
state.gaugeChartUnits.style.fontSize = unitfontsize + 'px';
state.element_chart.appendChild(state.gaugeChartUnits);
state.___gaugeOld__ = {
value: value,
- min: 0,
+ min: min,
max: max,
valueLabel: null,
minLabel: null,
state.gauge_instance.maxValue = 100;
NETDATA.gaugeAnimation(state, animate);
- NETDATA.gaugeSet(state, value, 0, max);
- NETDATA.gaugeSetLabels(state, value, 0, max);
+ NETDATA.gaugeSet(state, value, min, max);
+ NETDATA.gaugeSetLabels(state, value, min, max);
NETDATA.gaugeAnimation(state, true);
return true;
};
toolboxPanAndZoom: NETDATA.dygraphToolboxPanAndZoom,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return 'ms|flip'; },
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return 'ms|flip'; },
legend: function(state) {
- if(this.isSparkline(state) === false)
- return 'right-side';
- else
- return null;
+ return (this.isSparkline(state) === false)?'right-side':null;
},
- autoresize: function(state) { return true; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
+ autoresize: function(state) { void(state); return true; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
pixels_per_point: function(state) {
- if(this.isSparkline(state) === false)
- return 3;
- else
- return 2;
+ return (this.isSparkline(state) === false)?3:2;
},
-
isSparkline: function(state) {
if(typeof state.dygraph_sparkline === 'undefined') {
var t = $(state.element).data('dygraph-theme');
- if(t === 'sparkline')
- state.dygraph_sparkline = true;
- else
- state.dygraph_sparkline = false;
+ state.dygraph_sparkline = (t === 'sparkline');
}
return state.dygraph_sparkline;
}
create: NETDATA.sparklineChartCreate,
update: NETDATA.sparklineChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'flip|abs'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'flip|abs'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"peity": {
initialize: NETDATA.peityInitialize,
create: NETDATA.peityChartCreate,
update: NETDATA.peityChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'ssvcomma'; },
- options: function(state) { return 'null2zero|flip|abs'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'ssvcomma'; },
+ options: function(state) { void(state); return 'null2zero|flip|abs'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"morris": {
initialize: NETDATA.morrisInitialize,
create: NETDATA.morrisChartCreate,
update: NETDATA.morrisChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return 'objectrows|ms'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 50; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 15; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return 'objectrows|ms'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 50; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 15; }
},
"google": {
initialize: NETDATA.googleInitialize,
create: NETDATA.googleChartCreate,
update: NETDATA.googleChartUpdate,
resize: null,
- setSelection: undefined, //function(state, t) { return true; },
- clearSelection: undefined, //function(state) { return true; },
+ setSelection: undefined, //function(state, t) { void(state); return true; },
+ clearSelection: undefined, //function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'datatable'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 300; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 4; }
+ format: function(state) { void(state); return 'datatable'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 300; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 4; }
},
"raphael": {
initialize: NETDATA.raphaelInitialize,
create: NETDATA.raphaelChartCreate,
update: NETDATA.raphaelChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"c3": {
initialize: NETDATA.c3Initialize,
create: NETDATA.c3ChartCreate,
update: NETDATA.c3ChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'csvjsonarray'; },
- options: function(state) { return 'milliseconds'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 15; }
+ format: function(state) { void(state); return 'csvjsonarray'; },
+ options: function(state) { void(state); return 'milliseconds'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 15; }
},
"d3": {
initialize: NETDATA.d3Initialize,
create: NETDATA.d3ChartCreate,
update: NETDATA.d3ChartUpdate,
resize: null,
- setSelection: undefined, // function(state, t) { return true; },
- clearSelection: undefined, // function(state) { return true; },
+ setSelection: undefined, // function(state, t) { void(state); return true; },
+ clearSelection: undefined, // function(state) { void(state); return true; },
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'json'; },
- options: function(state) { return ''; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return false; },
- pixels_per_point: function(state) { return 3; }
+ format: function(state) { void(state); return 'json'; },
+ options: function(state) { void(state); return ''; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return false; },
+ pixels_per_point: function(state) { void(state); return 3; }
},
"easypiechart": {
initialize: NETDATA.easypiechartInitialize,
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'absolute'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
- pixels_per_point: function(state) { return 3; },
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'absolute'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
+ pixels_per_point: function(state) { void(state); return 3; },
aspect_ratio: 100
},
"gauge": {
toolboxPanAndZoom: null,
initialized: false,
enabled: true,
- format: function(state) { return 'array'; },
- options: function(state) { return 'absolute'; },
- legend: function(state) { return null; },
- autoresize: function(state) { return false; },
- max_updates_to_recreate: function(state) { return 5000; },
- track_colors: function(state) { return true; },
- pixels_per_point: function(state) { return 3; },
+ format: function(state) { void(state); return 'array'; },
+ options: function(state) { void(state); return 'absolute'; },
+ legend: function(state) { void(state); return null; },
+ autoresize: function(state) { void(state); return false; },
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
+ track_colors: function(state) { void(state); return true; },
+ pixels_per_point: function(state) { void(state); return 3; },
aspect_ratio: 70
}
};
async: false,
isAlreadyLoaded: function() {
// check if bootstrap is loaded
- if(typeof $().emulateTransitionEnd == 'function')
+ if(typeof $().emulateTransitionEnd === 'function')
return true;
else {
- if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
- return true;
- else
- return false;
+ return (typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap === true);
}
}
},
{
- url: NETDATA.serverDefault + 'lib/jquery.nanoscroller-0.8.7.min.js',
+ url: NETDATA.serverDefault + 'lib/perfect-scrollbar-0.6.15.min.js',
isAlreadyLoaded: function() { return false; }
}
];
{
url: NETDATA.themes.current.bootstrap_css,
isAlreadyLoaded: function() {
- if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
- return true;
- else
- return false;
+ return (typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap === true);
}
},
{
- url: NETDATA.serverDefault + 'css/font-awesome.min.css?v4.6.3',
+ url: NETDATA.serverDefault + 'css/font-awesome.min.css?v4.7.0',
isAlreadyLoaded: function() { return false; }
},
{
NETDATA.loadRequiredJs = function(index, callback) {
if(index >= NETDATA.requiredJs.length) {
if(typeof callback === 'function')
- callback();
+ return callback();
return;
}
if(async === false)
NETDATA.loadRequiredJs(++index, callback);
- })
+ });
if(async === true)
NETDATA.loadRequiredJs(++index, callback);
last_notification_id: 0, // the id of the last alarm_log we have raised an alarm for
first_notification_id: 0, // the id of the first alarm_log entry for this session
// this is used to prevent CLEAR notifications for past events
- // notifications_shown: new Array(),
+ // notifications_shown: [],
server: null, // the server to connect to for fetching alarms
current: null, // the list of raised alarms - updated in the background
return;
}
- var value = entry.value;
+ var value_string = entry.value_string;
+
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)
- value = t.value;
+ if(typeof t !== 'undefined' && entry.status === t.status && typeof t.value_string !== 'undefined')
+ value_string = t.value_string;
}
var name = entry.name.replace(/_/g, ' ');
var status = entry.status.toLowerCase();
- var title = name + ' = ' + ((value === null)?'NaN':Math.floor(value)).toString() + ' ' + entry.units;
+ var title = name + ' = ' + value_string.toString();
var tag = entry.alarm_id;
var icon = 'images/seo-performance-128.png';
var interaction = false;
// console.log('alarm' + entry.unique_id + ' switch to CLEAR from ' + entry.old_status);
return;
}
- title = name + ' back to normal';
- icon = 'images/check-mark-2-128-green.png'
+ if(entry.no_clear_notification === true) {
+ // console.log('alarm' + entry.unique_id + ' is CLEAR but has no_clear_notification flag');
+ return;
+ }
+ title = name + ' back to normal (' + value_string.toString() + ')';
+ icon = 'images/check-mark-2-128-green.png';
interaction = false;
break;
if(entry.old_status === 'WARNING')
status = 'escalated to ' + entry.status.toLowerCase();
- icon = 'images/alert-128-red.png'
+ icon = 'images/alert-128-red.png';
interaction = true;
break;
NETDATA.alarms.first_notification_id = data.latest_alarm_log_unique_id;
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(415, NETDATA.alarms.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
})
.done(function(data) {
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(416, NETDATA.alarms.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
init: function() {
- var host = NETDATA.serverDefault;
- while(host.slice(-1) === '/')
- host = host.substring(0, host.length - 1);
- NETDATA.alarms.server = host;
+ NETDATA.alarms.server = NETDATA.fixHost(NETDATA.serverDefault);
- NETDATA.alarms.last_notification_id = NETDATA.localStorageGet('last_notification_id', NETDATA.alarms.last_notification_id, null);
+ NETDATA.alarms.last_notification_id =
+ NETDATA.localStorageGet('last_notification_id', NETDATA.alarms.last_notification_id, null);
if(NETDATA.alarms.onclick === null)
NETDATA.alarms.onclick = NETDATA.alarms.scrollToAlarm;
// Registry of netdata hosts
NETDATA.registry = {
- server: null, // the netdata registry server
- person_guid: null, // the unique ID of this browser / user
- machine_guid: null, // the unique ID the netdata server that served dashboard.js
- hostname: null, // the hostname of the netdata server that served dashboard.js
- machines: null, // the user's other URLs
- machines_array: null, // the user's other URLs in an array
+ server: null, // the netdata registry server
+ person_guid: null, // the unique ID of this browser / user
+ machine_guid: null, // the unique ID the netdata server that served dashboard.js
+ hostname: 'unknown', // the hostname of the netdata server that served dashboard.js
+ machines: null, // the user's other URLs
+ machines_array: null, // the user's other URLs in an array
person_urls: null,
parsePersonUrls: function(person_urls) {
if(person_urls) {
NETDATA.registry.machines = {};
- NETDATA.registry.machines_array = new Array();
+ NETDATA.registry.machines_array = [];
- var now = new Date().getTime();
var apu = person_urls;
var i = apu.length;
while(i--) {
last_t: apu[i][2],
accesses: apu[i][3],
name: apu[i][4],
- alternate_urls: new Array()
+ alternate_urls: []
};
obj.alternate_urls.push(apu[i][1]);
},
hello: function(host, callback) {
- while(host.slice(-1) === '/')
- host = host.substring(0, host.length - 1);
+ host = NETDATA.fixHost(host);
// send HELLO to a netdata server:
// 1. verifies the server is reachable
}
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(407, host);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
}
else {
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
}
}
else {
NETDATA.registry.person_guid = data.person_guid;
if(typeof callback === 'function')
- callback(data.urls);
+ return callback(data.urls);
}
})
.fail(function() {
NETDATA.error(410, NETDATA.registry.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
}
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(412, NETDATA.registry.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
}
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(418, NETDATA.registry.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
},
}
if(typeof callback === 'function')
- callback(data);
+ return callback(data);
})
.fail(function() {
NETDATA.error(414, NETDATA.registry.server);
if(typeof callback === 'function')
- callback(null);
+ return callback(null);
});
}
};
}
});
});
-
- // window.NETDATA = NETDATA;
-// })(window, document);
+})(window, document);