]> arthur.barton.de Git - netdata.git/blob - web/dashboard.js
minor code cleanups; updated the dashboard to fix inline charts
[netdata.git] / web / dashboard.js
1 // You can set the following variables before loading this script:
2 //
3 // var netdataStopDygraph = 1;                  // do not use dygraph
4 // var netdataStopSparkline = 1;                // do not use sparkline
5 // var netdataStopPeity = 1;                    // do not use peity
6 //
7 // You can also set the default netdata server, using the following.
8 // When this variable is not set, we assume the page is hosted on your
9 // netdata server already.
10 // var netdataServer = "http://yourhost:19999"; // set your NetData server
11
12 // --------------------------------------------------------------------------------------------------------------------
13 // For google charts you need this in your page:
14 //      <script type="text/javascript" src="https://www.google.com/jsapi"></script>
15 //      <script type='text/javascript'>google.load('visualization', '1.1', {'packages':['corechart', 'controls']});</script>
16
17 (function(window)
18 {
19         var NETDATA = window.NETDATA || {};
20
21         // ----------------------------------------------------------------------------------------------------------------
22         // Detect the netdata server
23
24         // http://stackoverflow.com/questions/984510/what-is-my-script-src-url
25         // http://stackoverflow.com/questions/6941533/get-protocol-domain-and-port-from-url
26         NETDATA._scriptSource = function(scripts) {
27                 var script = null, base = null;
28
29                 if(typeof document.currentScript != 'undefined') {
30                         script = document.currentScript;
31                 }
32                 else {
33                         var all_scripts = document.getElementsByTagName('script');
34                         script = all_scripts[all_scripts.length - 1];
35                 }
36
37                 if (script.getAttribute.length != 'undefined')
38                         script = script.src;
39                 else
40                         script = script.getAttribute('src', -1);
41
42                 var link = document.createElement('a');
43                 link.setAttribute('href', script);
44
45                 if(!link.protocol || !link.hostname) return null;
46
47                 base = link.protocol;
48                 if(base) base += "//";
49                 base += link.hostname;
50
51                 if(link.port) base += ":" + link.port;
52                 base += "/";
53
54                 return base;
55         };
56
57         if(typeof netdataServer != 'undefined')
58                 NETDATA.serverDefault = netdataServer + "/";
59         else
60                 NETDATA.serverDefault = NETDATA._scriptSource();
61
62         NETDATA.jQuery       = NETDATA.serverDefault + 'lib/jquery-1.11.3.min.js';
63         NETDATA.peity_js     = NETDATA.serverDefault + 'lib/jquery.peity.min.js';
64         NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline.min.js';
65         NETDATA.dygraph_js   = NETDATA.serverDefault + 'lib/dygraph-combined.js';
66         NETDATA.raphael_js   = NETDATA.serverDefault + 'lib/raphael-min.js';
67         NETDATA.morris_js    = NETDATA.serverDefault + 'lib/morris.min.js';
68         NETDATA.morris_css   = NETDATA.serverDefault + 'css/morris.css';
69         NETDATA.google_js    = 'https://www.google.com/jsapi';
70         NETDATA.colors  = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6',
71                                                 '#DD4477', '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11',
72                                                 '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC' ];
73
74         // ----------------------------------------------------------------------------------------------------------------
75         // the defaults for all charts
76
77         NETDATA.chartDefaults = {
78                 host: NETDATA.serverDefault,    // the server to get data from
79                 width: 100,                                             // the chart width
80                 height: 20,                                             // the chart height
81                 library: 'peity',                               // the graphing library to use
82                 method: 'average',                              // the grouping method
83                 before: 0,                                              // panning
84                 after: -600,                                    // panning
85                 pixels_per_point: 1,                                    // the detail of the chart
86         }
87
88         NETDATA.options = {
89                 targets: null,
90                 updated_dom: 1,
91                 debug: 1,
92
93                 current: {
94                         pixels_per_point: 1,
95                         idle_between_charts: 50,
96                         idle_between_loops: 100,
97                         debug: 1
98                 }
99         }
100
101         if(NETDATA.options.debug) console.log('welcome to NETDATA');
102
103
104         // ----------------------------------------------------------------------------------------------------------------
105         // Error Handling
106
107         NETDATA.errorCodes = {
108                 100: { message: "Cannot load chart library", alert: true },
109                 101: { message: "Cannot load jQuery", alert: true },
110                 402: { message: "Chart library not found", alert: false },
111                 404: { message: "Chart not found", alert: false },
112         };
113         NETDATA.errorLast = {
114                 code: 0,
115                 message: "",
116                 datetime: 0,
117         };
118
119         NETDATA.error = function(code, msg) {
120                 NETDATA.errorLast.code = code;
121                 NETDATA.errorLast.message = msg;
122                 NETDATA.errorLast.datetime = new Date().getTime();
123
124                 console.log("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
125
126                 if(NETDATA.errorCodes[code].alert)
127                         alert("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
128         }
129
130         NETDATA.errorReset = function() {
131                 NETDATA.errorLast.code = 0;
132                 NETDATA.errorLast.message = "You are doing fine!";
133                 NETDATA.errorLast.datetime = 0;
134         }
135
136         NETDATA.chartContainer = function(element, width, height) {
137                 self = $(element);
138                 self.css('width', width)
139                         .css('height', height)
140                         .css('display', 'inline-block')
141                         .css('overflow', 'hidden');
142         }
143
144         NETDATA.messageInABox = function(element, width, height, message) {
145                 NETDATA.chartContainer(element, width, height);
146                 element.innerHTML = '<div style="overflow: hidden; border: 0px; background-color: lightgrey; width: ' + width + '; height: ' + height + ';"><small>'
147                         + message
148                         + '</small></div>';
149         }
150
151         // ----------------------------------------------------------------------------------------------------------------
152         // Load a script without jquery
153         // This is used to load jquery - after it is loaded, we use jquery
154
155         NETDATA._loadjQuery = function(callback) {
156                 if(typeof jQuery == 'undefined') {
157                         var script = document.createElement('script');
158                         script.type = 'text/javascript';
159                         script.async = true;
160                         script.src = NETDATA.jQuery;
161
162                         // script.onabort = onError;
163                         script.onerror = function(err, t) { NETDATA.error(101, NETDATA.jQuery); };
164                         if(typeof callback == "function")
165                                 script.onload = callback;
166
167                         var s = document.getElementsByTagName('script')[0];
168                         s.parentNode.insertBefore(script, s);
169                 }
170                 else if(typeof callback == "function")
171                         callback();
172         }
173
174         NETDATA.generateChartDataURL = function(options) {
175                 // build the data URL
176                 var url = options.host + options.url;
177                 url += "&points=";
178                 url += options.points.toString();
179                 url += "&group=";
180                 url += options.method;
181                 url += "&after=";
182                 url += options.after || "0";
183                 url += "&before=";
184                 url += options.before || "0";
185                 url += "&options=" + NETDATA.chartLibraries[options.library].options + '|';
186                 url += (options.non_zero)?"nonzero":"";
187                 url += "&format=" + NETDATA.chartLibraries[options.library].format;
188
189                 if(options.dimensions)
190                         url += "&dimensions=" + options.dimensions;
191
192                 if(NETDATA.options.debug) console.log('generateChartDataURL(' + options + ') = ' + url );
193                 return url;
194         }
195
196         NETDATA.parseDomCharts = function(targets, index, callback) {
197                 if(NETDATA.options.debug) console.log('parseDomCharts() working on ' + index);
198
199                 var target = targets.get(index);
200                 if(target == null) {
201                         if(NETDATA.options.debug) console.log('parseDomCharts(): all ' + (index - 1) + ' charts parsed.');
202                         if(typeof callback == 'function') callback();
203                 }
204                 else {
205                         var self = $(target);
206                         if(!self.data('prepared')) {
207                                 self.data('prepared', true);
208
209                                 var id = self.data('netdata');
210                                 var host = self.data('host') || NETDATA.chartDefaults.host;
211                                 var width = self.data('width') || NETDATA.chartDefaults.width;
212                                 var height = self.data('height') || NETDATA.chartDefaults.height;
213                                 var method = self.data('method') || NETDATA.chartDefaults.method;
214                                 var after = self.data('after') || NETDATA.chartDefaults.after;
215                                 var before = self.data('before') || NETDATA.chartDefaults.before;
216                                 var library = self.data('chart-library') || NETDATA.chartDefaults.library;
217                                 var dimensions = self.data('dimensions') || null;
218
219                                 NETDATA.chartContainer(target, width, height);
220                                 if(NETDATA.options.debug) console.log('parseDomCharts() parsing ' + id + ' of type ' + library);
221
222                                 if(typeof NETDATA.chartLibraries[library] == 'undefined') {
223                                         self.data('created', false)
224                                                 .data('updated', 0)
225                                                 .data('enabled', false);
226
227                                         NETDATA.error(402, library);
228                                         NETDATA.messageInABox(target, width, height, 'chart library "' + library + '" is not found');
229
230                                         NETDATA.parseDomCharts(targets, ++index, callback);
231                                 }
232                                 else {
233                                         var url = host + "/api/v1/chart?chart=" + id;
234
235                                         $.ajax( {
236                                                 url:  url,
237                                                 crossDomain: true
238                                         })
239                                         .done(function(chart) {
240                                                 var pixels_per_point = self.data('point-width') || NETDATA.chartLibraries[library].pixels_per_point;
241                                                 var points = self.data('points') || Math.round(width / pixels_per_point);
242
243                                                 var url = NETDATA.generateChartDataURL({
244                                                         host: host,
245                                                         url: chart.data_url,
246                                                         dimensions: dimensions,
247                                                         library: library,
248                                                         method: method,
249                                                         before: before,
250                                                         points: points,
251                                                         after: after,
252                                                         non_zero: null
253                                                 });
254
255                                                 // done processing of this DIV
256                                                 // store the processing result, in
257                                                 // 'data' sections in the DIV
258                                                 self.data('chart', chart)
259                                                         .data('chart-url', url)
260                                                         .data('update-every', chart.update_every * 1000)
261                                                         .data('created', false)
262                                                         .data('updated', 0)
263                                                         .data('enabled', true)
264                                                         .data('host', host)
265                                                         .data('width', width)
266                                                         .data('height', height)
267                                                         .data('method', method)
268                                                         .data('after', after)
269                                                         .data('before', before)
270                                                         .data('chart-library', library)
271                                                         .data('dimensions', dimensions)
272                                                         ;
273                                                 
274                                                 NETDATA.messageInABox(target, width, height, 'chart "' + id + '" is loading...');
275                                         })
276                                         .fail(function() {
277                                                 self.data('created', false)
278                                                         .data('enabled', false);
279
280                                                 NETDATA.error(404, url);
281                                                 NETDATA.messageInABox(target, width, height, 'chart "' + id + '" not found on url "' + url + '"');
282                                         })
283                                         .always(function() {
284                                                 self.data('updated', 0);
285                                                 NETDATA.parseDomCharts(targets, ++index, callback);
286                                         });
287                                 }
288                         }
289                 }
290         }
291
292         NETDATA.domUpdated = function(callback) {
293                 NETDATA.options.updated_dom = 0;
294
295                 NETDATA.options.targets = $('div[data-netdata]') // .filter(':visible')
296                         .bind('create', function(event, data) {
297                                 var self = $(this);
298                                 try {
299                                         NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
300                                 }
301                                 catch(err) {
302                                         NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be created as ' + self.data('chart-library'));
303                                 }
304                         })
305                         .bind('update', function(event, data) {
306                                 var self = $(this);
307                                 try {
308                                         NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
309                                 }
310                                 catch(err) {
311                                         NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be updated as ' + self.data('chart-library'));
312                                 }
313                         });
314
315                 if(NETDATA.options.debug)
316                         console.log('DOM updated - there are ' + NETDATA.options.targets.length + ' charts on page.');
317
318                 NETDATA.parseDomCharts(NETDATA.options.targets, 0, callback);
319         }
320
321         NETDATA.init = function() {
322                 NETDATA.domUpdated(function() {
323                         // done processing all netdata DIVs in this page
324                         // call the refresh handler
325
326                         // FIXME
327                         NETDATA.chartRefresher(0);
328                 });
329         }
330
331         // ----------------------------------------------------------------------------------------------------------------
332
333         //var chart = function() {
334         //}
335
336         //chart.prototype.color = function() {
337         //      return 'red';
338         //}
339
340         //var c = new chart();
341         //c.color();
342
343         NETDATA.chartValuesDownloader = function(element, callback) {
344                 var self = $(element);
345                 var last = self.data('updated') || 0;
346                 var every = self.data('update-every') || 1;
347
348                 // check if this chart has to be refreshed now
349                 var now = new Date().getTime();
350                 if(last + every > now) {
351                         console.log(self.data('netdata') + ' too soon - skipping.');
352                         if(typeof callback == 'function') callback();
353                 }
354                 else if(!self.visible(true)) {
355                         console.log(self.data('netdata') + ' is NOT visible.');
356                         if(typeof callback == 'function') callback();
357                 }
358                 else {
359                         console.log(self.data('netdata') + ' is visible, downloading data...');
360                         $.ajax( {
361                                 url: self.data('chart-url'),
362                                 crossDomain: true
363                         })
364                         .then(function(data) {
365                                 var started = new Date().getTime();
366
367                                 if(self.data('created')) {
368                                         console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
369                                         self.trigger('update', [data]);
370                                         // NETDATA.chartLibraries[self.data('chart-library')].update(element, data);
371                                 }
372                                 else {
373                                         console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
374                                         self.trigger('create', [data]);
375                                         //NETDATA.chartLibraries[self.data('chart-library')].create(element, data);
376                                         self.data('created', true);
377                                 }
378
379                                 var ended = new Date().getTime();
380                                 self.data('updated', ended);
381
382                                 var dt = ended - started;
383
384                                 self.data('refresh-dt', dt);
385                                 var element_name = self.data('dt-element-name') || null;
386                                 if(element_name) {
387                                         var element = document.getElementById(element_name) || null;
388                                         if(element) {
389                                                 element.innerHTML = dt.toString();
390                                         }
391                                 }
392                         })
393                         .fail(function() {
394                                 NETDATA.messageInABox(element, width, height, 'chart "' + id + '" not found on url "' + url + '"');
395                         })
396                         .always(function() {
397                                 if(typeof callback == 'function') callback();
398                         });
399                 }
400         };
401
402         NETDATA.chartRefresher = function(index) {
403                 // if(NETDATA.options.debug) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
404
405                 if(NETDATA.options.updated_dom) {
406                         NETDATA.domUpdated(function() {
407                                 NETDATA.chartRefresher(0);
408                         });
409                 }
410                 else {
411                         var target = NETDATA.options.targets.get(index);
412                         if(target == null) {
413                                 console.log('waiting to restart main loop...');
414
415                                 // finished, restart
416                                 setTimeout(function() {
417                                         NETDATA.chartRefresher(0);
418                                 }, NETDATA.options.current.idle_between_loops);
419                         }
420                         else {
421                                 var self = $(target);
422                                 if(!self.data('enabled')) {
423                                         NETDATA.chartRefresher(++index);
424                                 }
425                                 else {
426                                         setTimeout(function() {
427                                                 NETDATA.chartValuesDownloader(target, function() {
428                                                         NETDATA.chartRefresher(++index);
429                                                 });
430                                         }, NETDATA.options.current.idle_between_charts);
431                                 }
432                         }
433                 }
434         }
435
436         NETDATA.guid = function() {
437                 function s4() {
438                         return Math.floor((1 + Math.random()) * 0x10000)
439                                         .toString(16)
440                                         .substring(1);
441                         }
442
443                         return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
444         }
445
446         // ----------------------------------------------------------------------------------------------------------------
447         // piety
448
449         NETDATA.peityInitialize = function(callback) {
450                 if(typeof netdataStopPeity == 'undefined') {
451                         $.getScript(NETDATA.peity_js)
452                                 .done(function() {
453                                         NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
454                                 })
455                                 .fail(function() {
456                                         NETDATA.error(100, NETDATA.peity_js);
457                                 })
458                                 .always(function() {
459                                         if(typeof callback == "function")
460                                                 callback();
461                                 })
462                 }
463                 else if(typeof callback == "function")
464                         callback();
465         };
466
467         NETDATA.peityChartUpdate = function(element, data) {
468                 var self = $(element);
469                 var instance = self.html(data).not('[data-created]');
470                 instance.change();
471         }
472
473         NETDATA.peityChartCreate = function(element, data) {
474                 var self = $(element);
475                 var width = self.data('width') || NETDATA.chartDefaults.width;
476                 var height = self.data('height') || NETDATA.chartDefaults.height;
477                 var instance = self.html(data).not('[data-created]');
478
479                 instance.peity('line', {
480                         width: width,
481                         height: height
482                 })
483                 .data('created', true);
484         }
485
486         // ----------------------------------------------------------------------------------------------------------------
487         // sparkline
488
489         NETDATA.sparklineInitialize = function(callback) {
490                 if(typeof netdataStopSparkline == 'undefined') {
491                         $.getScript(NETDATA.sparkline_js)
492                                 .done(function() {
493                                         NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
494                                 })
495                                 .fail(function() {
496                                         NETDATA.error(100, NETDATA.sparkline_js);
497                                 })
498                                 .always(function() {
499                                         if(typeof callback == "function")
500                                                 callback();
501                                 })
502                 }
503                 else if(typeof callback == "function")
504                         callback();
505         };
506
507         NETDATA.sparklineChartUpdate = function(element, data) {
508                 var self = $(element);
509                 var options = self.data('sparkline-options');
510                 self.sparkline(data, options);
511         }
512
513         NETDATA.sparklineChartCreate = function(element, data) {
514                 var self = $(element);
515                 var chart = self.data('chart');
516                 var width = self.data('width') || NETDATA.chartDefaults.width;
517                 var height = self.data('height') || NETDATA.chartDefaults.height;
518                 var type = self.data('sparkline-type') || 'line';
519                 var lineColor = self.data('sparkline-lineColor') || undefined;
520                 var fillColor = self.data('sparkline-fillColor') || (chart.chart_type == 'line')?'#FFF':undefined;
521                 var chartRangeMin = self.data('sparkline-chartRangeMin') || undefined;
522                 var chartRangeMax = self.data('sparkline-chartRangeMax') || undefined;
523                 var composite = self.data('sparkline-composite') || undefined;
524                 var enableTagOptions = self.data('sparkline-enableTagOptions') || undefined;
525                 var tagOptionPrefix = self.data('sparkline-tagOptionPrefix') || undefined;
526                 var tagValuesAttribute = self.data('sparkline-tagValuesAttribute') || undefined;
527                 var disableHiddenCheck = self.data('sparkline-disableHiddenCheck') || undefined;
528                 var defaultPixelsPerValue = self.data('sparkline-defaultPixelsPerValue') || undefined;
529                 var spotColor = self.data('sparkline-spotColor') || undefined;
530                 var minSpotColor = self.data('sparkline-minSpotColor') || undefined;
531                 var maxSpotColor = self.data('sparkline-maxSpotColor') || undefined;
532                 var spotRadius = self.data('sparkline-spotRadius') || undefined;
533                 var valueSpots = self.data('sparkline-valueSpots') || undefined;
534                 var highlightSpotColor = self.data('sparkline-highlightSpotColor') || undefined;
535                 var highlightLineColor = self.data('sparkline-highlightLineColor') || undefined;
536                 var lineWidth = self.data('sparkline-lineWidth') || undefined;
537                 var normalRangeMin = self.data('sparkline-normalRangeMin') || undefined;
538                 var normalRangeMax = self.data('sparkline-normalRangeMax') || undefined;
539                 var drawNormalOnTop = self.data('sparkline-drawNormalOnTop') || undefined;
540                 var xvalues = self.data('sparkline-xvalues') || undefined;
541                 var chartRangeClip = self.data('sparkline-chartRangeClip') || undefined;
542                 var xvalues = self.data('sparkline-xvalues') || undefined;
543                 var chartRangeMinX = self.data('sparkline-chartRangeMinX') || undefined;
544                 var chartRangeMaxX = self.data('sparkline-chartRangeMaxX') || undefined;
545                 var disableInteraction = self.data('sparkline-disableInteraction') || false;
546                 var disableTooltips = self.data('sparkline-disableTooltips') || false;
547                 var disableHighlight = self.data('sparkline-disableHighlight') || false;
548                 var highlightLighten = self.data('sparkline-highlightLighten') || 1.4;
549                 var highlightColor = self.data('sparkline-highlightColor') || undefined;
550                 var tooltipContainer = self.data('sparkline-tooltipContainer') || undefined;
551                 var tooltipClassname = self.data('sparkline-tooltipClassname') || undefined;
552                 var tooltipFormat = self.data('sparkline-tooltipFormat') || undefined;
553                 var tooltipPrefix = self.data('sparkline-tooltipPrefix') || undefined;
554                 var tooltipSuffix = self.data('sparkline-tooltipSuffix') || ' ' + chart.units;
555                 var tooltipSkipNull = self.data('sparkline-tooltipSkipNull') || true;
556                 var tooltipValueLookups = self.data('sparkline-tooltipValueLookups') || undefined;
557                 var tooltipFormatFieldlist = self.data('sparkline-tooltipFormatFieldlist') || undefined;
558                 var tooltipFormatFieldlistKey = self.data('sparkline-tooltipFormatFieldlistKey') || undefined;
559                 var numberFormatter = self.data('sparkline-numberFormatter') || function(n){ return n.toFixed(2); };
560                 var numberDigitGroupSep = self.data('sparkline-numberDigitGroupSep') || undefined;
561                 var numberDecimalMark = self.data('sparkline-numberDecimalMark') || undefined;
562                 var numberDigitGroupCount = self.data('sparkline-numberDigitGroupCount') || undefined;
563                 var animatedZooms = self.data('sparkline-animatedZooms') || false;
564
565                 var options = {
566                         type: type,
567                         lineColor: lineColor,
568                         fillColor: fillColor,
569                         chartRangeMin: chartRangeMin,
570                         chartRangeMax: chartRangeMax,
571                         composite: composite,
572                         enableTagOptions: enableTagOptions,
573                         tagOptionPrefix: tagOptionPrefix,
574                         tagValuesAttribute: tagValuesAttribute,
575                         disableHiddenCheck: disableHiddenCheck,
576                         defaultPixelsPerValue: defaultPixelsPerValue,
577                         spotColor: spotColor,
578                         minSpotColor: minSpotColor,
579                         maxSpotColor: maxSpotColor,
580                         spotRadius: spotRadius,
581                         valueSpots: valueSpots,
582                         highlightSpotColor: highlightSpotColor,
583                         highlightLineColor: highlightLineColor,
584                         lineWidth: lineWidth,
585                         normalRangeMin: normalRangeMin,
586                         normalRangeMax: normalRangeMax,
587                         drawNormalOnTop: drawNormalOnTop,
588                         xvalues: xvalues,
589                         chartRangeClip: chartRangeClip,
590                         chartRangeMinX: chartRangeMinX,
591                         chartRangeMaxX: chartRangeMaxX,
592                         disableInteraction: disableInteraction,
593                         disableTooltips: disableTooltips,
594                         disableHighlight: disableHighlight,
595                         highlightLighten: highlightLighten,
596                         highlightColor: highlightColor,
597                         tooltipContainer: tooltipContainer,
598                         tooltipClassname: tooltipClassname,
599                         tooltipChartTitle: chart.title,
600                         tooltipFormat: tooltipFormat,
601                         tooltipPrefix: tooltipPrefix,
602                         tooltipSuffix: tooltipSuffix,
603                         tooltipSkipNull: tooltipSkipNull,
604                         tooltipValueLookups: tooltipValueLookups,
605                         tooltipFormatFieldlist: tooltipFormatFieldlist,
606                         tooltipFormatFieldlistKey: tooltipFormatFieldlistKey,
607                         numberFormatter: numberFormatter,
608                         numberDigitGroupSep: numberDigitGroupSep,
609                         numberDecimalMark: numberDecimalMark,
610                         numberDigitGroupCount: numberDigitGroupCount,
611                         animatedZooms: animatedZooms,
612                         width: width,
613                         height: height
614                 };
615
616                 var uuid = NETDATA.guid();
617                 element.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
618                 var div = document.getElementById(uuid);
619
620                 self.sparkline(data, options);
621                 self.data('sparkline-options', options)
622                 .data('uuid', uuid)
623                 .data('created', true);
624         };
625
626         // ----------------------------------------------------------------------------------------------------------------
627         // dygraph
628
629         NETDATA.dygraphAllCharts = [];
630         NETDATA.dygraphInitSync = function(callback) {
631                 //$.getScript(NETDATA.serverDefault + 'dygraph-synchronizer.js')
632                 //      .always(function() {
633                                 if(typeof callback == "function")
634                                         callback();
635                 //      })
636         }
637
638         NETDATA.dygraphSync = null;
639         NETDATA.dygraphSyncAll = function() {
640                 if(NETDATA.dygraphSync) {
641                         NETDATA.dygraphSync.detach();
642                         NETDATA.dygraphSync = null;
643                 }
644
645                 NETDATA.dygraphSync = Dygraph.synchronize(NETDATA.dygraphAllCharts, {
646                         selection: true,
647                         zoom: false
648                 });
649         }
650
651         NETDATA.dygraphInitialize = function(callback) {
652                 if(typeof netdataStopDygraph == 'undefined') {
653                         $.getScript(NETDATA.dygraph_js)
654                                 .done(function() {
655                                         NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
656                                 })
657                                 .fail(function() {
658                                         NETDATA.error(100, NETDATA.dygraph_js);
659                                 })
660                                 .always(function() {
661                                         NETDATA.dygraphInitSync(callback);
662                                 })
663                 }
664                 else if(typeof callback == "function")
665                         callback();
666         };
667
668         NETDATA.dygraphChartUpdate = function(element, data) {
669                 var self = $(element);
670                 var dygraph = self.data('dygraph-instance');
671
672                 if(typeof data.update_every != 'undefined')
673                         self.data('update-every', data.update_every * 1000);
674
675                 if(dygraph != null) {
676                         console.log('updating dygraphs');
677                         dygraph.updateOptions( { 'file': data.data, 'labels': data.labels } );
678                 }
679                 else
680                         console.log('not updating dygraphs');
681         };
682
683         NETDATA.dygraphChartCreate = function(element, data) {
684                 var self = $(element);
685                 var width = self.data('width') || NETDATA.chartDefaults.width;
686                 var height = self.data('height') || NETDATA.chartDefaults.height;
687                 var chart = self.data('chart');
688                 var title = self.data('dygraph-title') || chart.title;
689                 var titleHeight = self.data('dygraph-titleHeight') || 20;
690                 var labelsDiv = self.data('dygraph-labelsDiv') || undefined;
691                 var connectSeparatedPoints = self.data('dygraph-connectSeparatedPoints') || false;
692                 var yLabelWidth = self.data('dygraph-yLabelWidth') || 12;
693                 var stackedGraph = self.data('dygraph-stackedGraph') || (chart.chart_type == 'stacked')?true:false;
694                 var stackedGraphNaNFill = self.data('dygraph-stackedGraphNaNFill') || 'none';
695                 var hideOverlayOnMouseOut = self.data('dygraph-hideOverlayOnMouseOut') || true;
696                 var fillGraph = self.data('dygraph-fillGraph') || (chart.chart_type == 'area')?true:false;
697                 var drawPoints = self.data('dygraph-drawPoints') || false;
698                 var labelsDivStyles = self.data('dygraph-labelsDivStyles') || { 'fontSize':'10' };
699                 var labelsDivWidth = self.data('dygraph-labelsDivWidth') || 250;
700                 var labelsSeparateLines = self.data('dygraph-labelsSeparateLines') || false;
701                 var labelsShowZeroValues = self.data('dygraph-labelsShowZeroValues') || true;
702                 var legend = self.data('dygraph-legend') || 'onmouseover';
703                 var showLabelsOnHighlight = self.data('dygraph-showLabelsOnHighlight') || true;
704                 var gridLineColor = self.data('dygraph-gridLineColor') || '#EEE';
705                 var axisLineColor = self.data('dygraph-axisLineColor') || '#EEE';
706                 var maxNumberWidth = self.data('dygraph-maxNumberWidth') || 8;
707                 var sigFigs = self.data('dygraph-sigFigs') || null;
708                 var digitsAfterDecimal = self.data('dygraph-digitsAfterDecimal') || 2;
709                 var axisLabelFontSize = self.data('dygraph-axisLabelFontSize') || 10;
710                 var axisLineWidth = self.data('dygraph-axisLineWidth') || 0.3;
711                 var drawAxis = self.data('dygraph-drawAxis') || true;
712                 var strokeWidth = self.data('dygraph-strokeWidth') || 1.0;
713                 var drawGapEdgePoints = self.data('dygraph-drawGapEdgePoints') || true;
714                 var colors = self.data('dygraph-colors') || NETDATA.colors;
715                 var pointSize = self.data('dygraph-pointSize') || 1;
716                 var stepPlot = self.data('dygraph-stepPlot') || false;
717                 var strokeBorderColor = self.data('dygraph-strokeBorderColor') || 'white';
718                 var strokeBorderWidth = self.data('dygraph-strokeBorderWidth') || (chart.chart_type == 'stacked')?1.0:0.0;
719                 var strokePattern = self.data('dygraph-strokePattern') || undefined;
720                 var highlightCircleSize = self.data('dygraph-highlightCircleSize') || 3;
721                 var highlightSeriesOpts = self.data('dygraph-highlightSeriesOpts') || { strokeWidth: 1.5 };
722                 var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightSeriesBackgroundAlpha') || (chart.chart_type == 'stacked')?0.7:0.5;
723                 var pointClickCallback = self.data('dygraph-pointClickCallback') || undefined;
724                 var showRangeSelector = self.data('dygraph-showRangeSelector') || false;
725                 var showRoller = self.data('dygraph-showRoller') || false;
726                 var valueFormatter = self.data('dygraph-valueFormatter') || undefined; //function(x){ return x.toFixed(2); };
727                 var rightGap = self.data('dygraph-rightGap') || 5;
728                 var drawGrid = self.data('dygraph-drawGrid') || true;
729                 var drawXGrid = self.data('dygraph-drawXGrid') || undefined;
730                 var drawYGrid = self.data('dygraph-drawYGrid') || undefined;
731                 var gridLinePattern = self.data('dygraph-gridLinePattern') || null;
732                 var gridLineWidth = self.data('dygraph-gridLineWidth') || 0.3;
733
734                 var options = {
735                         title: title,
736                         titleHeight: titleHeight,
737                         ylabel: chart.units,
738                         yLabelWidth: yLabelWidth,
739                         connectSeparatedPoints: connectSeparatedPoints,
740                         drawPoints: drawPoints,
741                         fillGraph: fillGraph,
742                         stackedGraph: stackedGraph,
743                         stackedGraphNaNFill: stackedGraphNaNFill,
744                         drawGrid: drawGrid,
745                         drawXGrid: drawXGrid,
746                         drawYGrid: drawYGrid,
747                         gridLinePattern: gridLinePattern,
748                         gridLineWidth: gridLineWidth,
749                         gridLineColor: gridLineColor,
750                         axisLineColor: axisLineColor,
751                         axisLineWidth: axisLineWidth,
752                         drawAxis: drawAxis,
753                         hideOverlayOnMouseOut: hideOverlayOnMouseOut,
754                         labelsDiv: labelsDiv,
755                         labelsDivStyles: labelsDivStyles,
756                         labelsDivWidth: labelsDivWidth,
757                         labelsSeparateLines: labelsSeparateLines,
758                         labelsShowZeroValues: labelsShowZeroValues,
759                         labelsKMB: false,
760                         labelsKMG2: false,
761                         legend: legend,
762                         showLabelsOnHighlight: showLabelsOnHighlight,
763                         maxNumberWidth: maxNumberWidth,
764                         sigFigs: sigFigs,
765                         digitsAfterDecimal: digitsAfterDecimal,
766                         axisLabelFontSize: axisLabelFontSize,
767                         colors: colors,
768                         strokeWidth: strokeWidth,
769                         drawGapEdgePoints: drawGapEdgePoints,
770                         pointSize: pointSize,
771                         stepPlot: stepPlot,
772                         strokeBorderColor: strokeBorderColor,
773                         strokeBorderWidth: strokeBorderWidth,
774                         strokePattern: strokePattern,
775                         highlightCircleSize: highlightCircleSize,
776                         highlightSeriesOpts: highlightSeriesOpts,
777                         highlightSeriesBackgroundAlpha: highlightSeriesBackgroundAlpha,
778                         pointClickCallback: pointClickCallback,
779                         showRangeSelector: showRangeSelector,
780                         showRoller: showRoller,
781                         valueFormatter: valueFormatter,
782                         rightGap: rightGap,
783                         width: width,
784                         height: height,
785                         labels: data.labels,
786                         axes: {
787                                 x: {
788                                         pixelsPerLabel: 50,
789                                         ticker: Dygraph.dateTicker,
790                                         axisLabelFormatter: function (d, gran) {
791                                                 return Dygraph.zeropad(d.getHours()) + ":" + Dygraph.zeropad(d.getMinutes()) + ":" + Dygraph.zeropad(d.getSeconds());
792                                         },
793                                         valueFormatter :function (ms) {
794                                                 var d = new Date(ms);
795                                                 return Dygraph.zeropad(d.getHours()) + ":" + Dygraph.zeropad(d.getMinutes()) + ":" + Dygraph.zeropad(d.getSeconds());
796                                         }
797                                 },
798                                 y: {
799                                         pixelsPerLabel: 15,
800                                 }
801                         }
802                 };
803
804                 var uuid = NETDATA.guid();
805                 self.html('<div id="' + uuid + '"></div>');
806
807                 var dchart = new Dygraph(document.getElementById(uuid),
808                         data.data, options);
809
810                 self.data('dygraph-instance', dchart)
811                 .data('dygraph-options', options)
812                 .data('uuid', uuid)
813                 .data('created', true);
814
815                 //NETDATA.dygraphAllCharts.push(dchart);
816                 //if(NETDATA.dygraphAllCharts.length > 1)
817                 //      NETDATA.dygraphSyncAll();
818         };
819
820         // ----------------------------------------------------------------------------------------------------------------
821         // morris
822
823         NETDATA.morrisInitialize = function(callback) {
824                 if(typeof netdataStopMorris == 'undefined') {
825                         var fileref = document.createElement("link");
826                         fileref.setAttribute("rel", "stylesheet");
827                         fileref.setAttribute("type", "text/css");
828                         fileref.setAttribute("href", NETDATA.morris_css);
829
830                         if (typeof fileref != "undefined")
831                                 document.getElementsByTagName("head")[0].appendChild(fileref);
832
833                         $.getScript(NETDATA.morris_js)
834                                 .done(function() {
835                                         NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
836                                 })
837                                 .fail(function() {
838                                         NETDATA.error(100, NETDATA.morris_js);
839                                 })
840                                 .always(function() {
841                                         if(typeof callback == "function")
842                                                 callback();
843                                 })
844                 }
845                 else if(typeof callback == "function")
846                         callback();
847         };
848
849         NETDATA.morrisChartUpdate = function(element, data) {
850                 var self = $(element);
851                 var width = self.data('width') || NETDATA.chartDefaults.width;
852                 var height = self.data('height') || NETDATA.chartDefaults.height;
853                 var morris = self.data('morris-instance');
854
855                 if(typeof data.update_every != 'undefined')
856                         self.data('update-every', data.update_every * 1000);
857
858                 if(morris != null) {
859                         console.log('updating morris');
860                         morris.setData(data.data);
861                 }
862                 else
863                         console.log('not updating morris');
864         };
865
866         NETDATA.morrisChartCreate = function(element, data) {
867                 var self = $(element);
868                 var width = self.data('width') || NETDATA.chartDefaults.width;
869                 var height = self.data('height') || NETDATA.chartDefaults.height;
870                 var chart = self.data('chart');
871
872                 self.html('<div id="morris-' + chart.id + '" style="width: ' + width + 'px; height: ' + height + 'px;"></div>');
873
874                 // remove the 'time' element from the labels
875                 data.labels.splice(0, 1);
876
877                 var options = {
878                                 element: 'morris-' + chart.id,
879                                 data: data.data,
880                                 xkey: 'time',
881                                 ykeys: data.labels,
882                                 labels: data.labels,
883                                 lineWidth: 2,
884                                 pointSize: 2,
885                                 smooth: true,
886                                 hideHover: 'auto',
887                                 parseTime: true,
888                                 continuousLine: false,
889                                 behaveLikeLine: false,
890                                 width: width,
891                                 height: height
892                 };
893
894                 var morris;
895                 if(chart.chart_type == 'line')
896                         morris = new Morris.Line(options);
897
898                 else if(chart.chart_type == 'area') {
899                         options.behaveLikeLine = true;
900                         morris = new Morris.Area(options);
901                 }
902                 else // stacked
903                         morris = new Morris.Area(options);
904
905                 self.data('morris-instance', morris)
906                 .data('created', true);
907         };
908
909         // ----------------------------------------------------------------------------------------------------------------
910         // raphael
911
912         NETDATA.raphaelInitialize = function(callback) {
913                 if(typeof netdataStopRaphael == 'undefined') {
914                         $.getScript(NETDATA.raphael_js)
915                                 .done(function() {
916                                         NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
917                                 })
918                                 .fail(function() {
919                                         NETDATA.error(100, NETDATA.raphael_js);
920                                 })
921                                 .always(function() {
922                                         if(typeof callback == "function")
923                                                 callback();
924                                 })
925                 }
926                 else if(typeof callback == "function")
927                         callback();
928         };
929
930         NETDATA.raphaelChartUpdate = function(element, data) {
931                 var self = $(element);
932                 var width = self.data('width') || NETDATA.chartDefaults.width;
933                 var height = self.data('height') || NETDATA.chartDefaults.height;
934
935                 self.raphael(data, {
936                         width: width,
937                         height: height
938                 })
939         };
940
941         NETDATA.raphaelChartCreate = function(element, data) {
942                 var self = $(element);
943                 var width = self.data('width') || NETDATA.chartDefaults.width;
944                 var height = self.data('height') || NETDATA.chartDefaults.height;
945
946                 self.raphael(data, {
947                         width: width,
948                         height: height
949                 })
950                 .data('created', true);
951         };
952
953         // ----------------------------------------------------------------------------------------------------------------
954         // google charts
955
956         NETDATA.googleInitialize = function(callback) {
957                 if(typeof netdataStopGoogleCharts == 'undefined' && typeof google != 'undefined') {
958                         NETDATA.registerChartLibrary('google', NETDATA.google_js);
959                         if(typeof callback == "function")
960                                 callback();
961                 }
962                 else if(typeof callback == "function")
963                         callback();
964         };
965
966         NETDATA.googleChartUpdate = function(element, data) {
967                 var self = $(element);
968                 var width = self.data('width') || NETDATA.chartDefaults.width;
969                 var height = self.data('height') || NETDATA.chartDefaults.height;
970                 var gchart = self.data('google-instance');
971                 var options = self.data('google-options');
972
973                 if(typeof data.update_every != 'undefined')
974                         self.data('update-every', data.update_every * 1000);
975
976                 var datatable = new google.visualization.DataTable(data);
977
978                 gchart.draw(datatable, options);
979         };
980
981         NETDATA.googleChartCreate = function(element, data) {
982                 var self = $(element);
983                 var width = self.data('width') || NETDATA.chartDefaults.width;
984                 var height = self.data('height') || NETDATA.chartDefaults.height;
985                 var chart = self.data('chart');
986
987                 var datatable = new google.visualization.DataTable(data);
988                 var gchart;
989
990                 var options = {
991                         width: width,
992                         height: height,
993                         lineWidth: 1,
994                         title: chart.title,
995                         fontSize: 11,
996                         hAxis: {
997                         //      title: "Time of Day",
998                         //      format:'HH:mm:ss',
999                                 viewWindowMode: 'maximized',
1000                                 slantedText: false,
1001                                 format:'HH:mm:ss',
1002                                 textStyle: {
1003                                         fontSize: 9
1004                                 },
1005                                 gridlines: {
1006                                         color: '#EEE'
1007                                 }
1008                         },
1009                         vAxis: {
1010                                 title: chart.units,
1011                                 viewWindowMode: 'pretty',
1012                                 minValue: -0.1,
1013                                 maxValue: 0.1,
1014                                 direction: 1,
1015                                 textStyle: {
1016                                         fontSize: 9
1017                                 },
1018                                 gridlines: {
1019                                         color: '#EEE'
1020                                 }
1021                         },
1022                         chartArea: {
1023                                 width: '65%',
1024                                 height: '80%'
1025                         },
1026                         focusTarget: 'category',
1027                         annotation: {
1028                                 '1': {
1029                                         style: 'line'
1030                                 }
1031                         },
1032                         pointsVisible: 0,
1033                         titlePosition: 'out',
1034                         titleTextStyle: {
1035                                 fontSize: 11
1036                         },
1037                         tooltip: {
1038                                 isHtml: false,
1039                                 ignoreBounds: true,
1040                                 textStyle: {
1041                                         fontSize: 9
1042                                 }
1043                         },
1044                         curveType: 'function',
1045                         areaOpacity: 0.3,
1046                         isStacked: false
1047                 };
1048
1049                 switch(chart.chart_type) {
1050                         case "area":
1051                                 options.vAxis.viewWindowMode = 'maximized';
1052                                 gchart = new google.visualization.AreaChart(element);
1053                                 break;
1054
1055                         case "stacked":
1056                                 options.isStacked = true;
1057                                 options.areaOpacity = 0.85;
1058                                 options.vAxis.viewWindowMode = 'maximized';
1059                                 options.vAxis.minValue = null;
1060                                 options.vAxis.maxValue = null;
1061                                 gchart = new google.visualization.AreaChart(element);
1062                                 break;
1063
1064                         default:
1065                         case "line":
1066                                 options.lineWidth = 2;
1067                                 gchart = new google.visualization.LineChart(element);
1068                                 break;
1069                 }
1070
1071                 gchart.draw(datatable, options);
1072
1073                 self.data('google-instance', gchart)
1074                 .data('google-options', options)
1075                 .data('created', true);
1076         };
1077
1078         // ----------------------------------------------------------------------------------------------------------------
1079         // Charts Libraries Registration
1080
1081         NETDATA.chartLibraries = {
1082                 "dygraph": {
1083                         initialize: NETDATA.dygraphInitialize,
1084                         create: NETDATA.dygraphChartCreate,
1085                         update: NETDATA.dygraphChartUpdate,
1086                         initialized: false,
1087                         enabled: true,
1088                         format: 'json',
1089                         options: 'ms|flip',
1090                         pixels_per_point: 2,
1091                         detects_dimensions_on_update: false
1092                 },
1093                 "sparkline": {
1094                         initialize: NETDATA.sparklineInitialize,
1095                         create: NETDATA.sparklineChartCreate,
1096                         update: NETDATA.sparklineChartUpdate,
1097                         initialized: false,
1098                         enabled: true,
1099                         format: 'array',
1100                         options: 'flip|min2max',
1101                         pixels_per_point: 2,
1102                         detects_dimensions_on_update: false
1103                 },
1104                 "peity": {
1105                         initialize: NETDATA.peityInitialize,
1106                         create: NETDATA.peityChartCreate,
1107                         update: NETDATA.peityChartUpdate,
1108                         initialized: false,
1109                         enabled: true,
1110                         format: 'ssvcomma',
1111                         options: 'null2zero|flip|min2max',
1112                         pixels_per_point: 2,
1113                         detects_dimensions_on_update: false
1114                 },
1115                 "morris": {
1116                         initialize: NETDATA.morrisInitialize,
1117                         create: NETDATA.morrisChartCreate,
1118                         update: NETDATA.morrisChartUpdate,
1119                         initialized: false,
1120                         enabled: true,
1121                         format: 'json',
1122                         options: 'objectrows|ms',
1123                         pixels_per_point: 10,
1124                         detects_dimensions_on_update: false
1125                 },
1126                 "google": {
1127                         initialize: NETDATA.googleInitialize,
1128                         create: NETDATA.googleChartCreate,
1129                         update: NETDATA.googleChartUpdate,
1130                         initialized: false,
1131                         enabled: true,
1132                         format: 'datatable',
1133                         options: '',
1134                         pixels_per_point: 2,
1135                         detects_dimensions_on_update: true
1136                 },
1137                 "raphael": {
1138                         initialize: NETDATA.raphaelInitialize,
1139                         create: NETDATA.raphaelChartCreate,
1140                         update: NETDATA.raphaelChartUpdate,
1141                         initialized: false,
1142                         enabled: true,
1143                         format: 'json',
1144                         options: '',
1145                         pixels_per_point: 1,
1146                         detects_dimensions_on_update: false
1147                 }
1148         };
1149
1150         NETDATA.registerChartLibrary = function(library, url) {
1151                 console.log("registering chart library: " + library);
1152
1153                 NETDATA.chartLibraries[library]
1154                         .url = url
1155                         .initialized = new Date().getTime();
1156
1157                 console.log(NETDATA.chartLibraries);
1158         }
1159
1160         // ----------------------------------------------------------------------------------------------------------------
1161         // load all libraries and initialize
1162
1163         NETDATA.errorReset();
1164
1165         NETDATA._loadjQuery(function() {
1166                 $.getScript(NETDATA.serverDefault + 'lib/visible.js').then(function() {
1167                         NETDATA.raphaelInitialize(function() {
1168                                 NETDATA.morrisInitialize(function() {
1169                                         NETDATA.peityInitialize(function() {
1170                                                 NETDATA.sparklineInitialize(function() {
1171                                                         NETDATA.dygraphInitialize(function() {
1172                                                                 NETDATA.googleInitialize(function() {
1173                                                                         NETDATA.init();
1174                                                                 }) // google
1175                                                         }) // dygraph.js
1176                                                 }) // sparkline.js
1177                                         }) // piety.js
1178                                 }) // morris.js
1179                         }) // raphael.js
1180                 })
1181         });
1182
1183 })(window);