]> arthur.barton.de Git - netdata.git/blob - web/dashboard.js
dygraphs support now panning and zooming
[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 // var netdataStopGoogleCharts = 1;             // do not use google
7 // var netdataStopMorris = 1;                   // do not use morris
8 //
9 // You can also set the default netdata server, using the following.
10 // When this variable is not set, we assume the page is hosted on your
11 // netdata server already.
12 // var netdataServer = "http://yourhost:19999"; // set your NetData server
13
14 (function(window)
15 {
16         // fix IE bug with console
17         if(!window.console){ window.console = {log: function(){} }; }
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: '100%',                                 // the chart height
81                 library: 'dygraph',                             // 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                 last_paused: 0,
92                 page_is_visible: 1,
93                 double_click_ms: 100,
94                 refreshed_stop_until: 0,
95
96                 current: {
97                         pixels_per_point: 1,
98                         idle_between_charts: 100,
99                         idle_between_loops: 500,
100                         idle_lost_focus: 500,
101                         fast_render_timeframe: 200 // render continously for these many ms
102                 },
103
104                 debug: {
105                         show_boxes:             0,
106                         main_loop:                      0,
107                         focus:                          0,
108                         visibility:             0,
109                         chart_data_url:         0,
110                         chart_errors:           0,
111                         chart_timing:           0,
112                         chart_calls:            0,
113                         dygraph:                        0
114                 }
115         }
116
117         if(NETDATA.options.debug.main_loop) console.log('welcome to NETDATA');
118
119
120         // ----------------------------------------------------------------------------------------------------------------
121         // Error Handling
122
123         NETDATA.errorCodes = {
124                 100: { message: "Cannot load chart library", alert: true },
125                 101: { message: "Cannot load jQuery", alert: true },
126                 402: { message: "Chart library not found", alert: false },
127                 403: { message: "Chart library not enabled/is failed", alert: false },
128                 404: { message: "Chart not found", alert: false }
129         };
130         NETDATA.errorLast = {
131                 code: 0,
132                 message: "",
133                 datetime: 0
134         };
135
136         NETDATA.error = function(code, msg) {
137                 NETDATA.errorLast.code = code;
138                 NETDATA.errorLast.message = msg;
139                 NETDATA.errorLast.datetime = new Date().getTime();
140
141                 console.log("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
142
143                 if(NETDATA.errorCodes[code].alert)
144                         alert("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
145         }
146
147         NETDATA.errorReset = function() {
148                 NETDATA.errorLast.code = 0;
149                 NETDATA.errorLast.message = "You are doing fine!";
150                 NETDATA.errorLast.datetime = 0;
151         }
152
153         NETDATA.messageInABox = function(element, message) {
154                 self = $(element);
155
156                 bgcolor = ""
157                 if(NETDATA.options.debug.show_boxes)
158                         bgcolor = " background-color: lightgrey;";
159
160                 element.innerHTML = '<div style="font-size: xx-small; overflow: hidden;' + bgcolor + ' width: 100%; height: 100%;"><small>'
161                         + message
162                         + '</small></div>';
163
164                 self.data('chart-created', false);
165         }
166
167         // ----------------------------------------------------------------------------------------------------------------
168         // Library functions
169
170         // Load a script without jquery
171         // This is used to load jquery - after it is loaded, we use jquery
172         NETDATA._loadjQuery = function(callback) {
173                 if(typeof jQuery == 'undefined') {
174                         var script = document.createElement('script');
175                         script.type = 'text/javascript';
176                         script.async = true;
177                         script.src = NETDATA.jQuery;
178
179                         // script.onabort = onError;
180                         script.onerror = function(err, t) { NETDATA.error(101, NETDATA.jQuery); };
181                         if(typeof callback == "function")
182                                 script.onload = callback;
183
184                         var s = document.getElementsByTagName('script')[0];
185                         s.parentNode.insertBefore(script, s);
186                 }
187                 else if(typeof callback == "function")
188                         callback();
189         }
190
191         NETDATA.ColorLuminance = function(hex, lum) {
192                 // validate hex string
193                 hex = String(hex).replace(/[^0-9a-f]/gi, '');
194                 if (hex.length < 6)
195                         hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
196
197                 lum = lum || 0;
198
199                 // convert to decimal and change luminosity
200                 var rgb = "#", c, i;
201                 for (i = 0; i < 3; i++) {
202                         c = parseInt(hex.substr(i*2,2), 16);
203                         c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
204                         rgb += ("00"+c).substr(c.length);
205                 }
206
207                 return rgb;
208         }
209
210         NETDATA.guid = function() {
211                 function s4() {
212                         return Math.floor((1 + Math.random()) * 0x10000)
213                                         .toString(16)
214                                         .substring(1);
215                         }
216
217                         return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
218         }
219
220         // this is the main function - where everything starts
221         NETDATA.init = function() {
222                 // this should be called only once
223
224                 $(window).blur(function() {
225                         NETDATA.options.page_is_visible = 0;
226                         if(NETDATA.options.debug.focus) console.log('Lost Focus!');
227                 });
228
229                 $(window).focus(function() {
230                         NETDATA.options.page_is_visible = 1;
231                         if(NETDATA.options.debug.focus) console.log('Focus restored!');
232                 });
233
234                 NETDATA.getDomCharts(function() {
235                         NETDATA.chartRefresher(0);
236                 });
237         }
238
239         // user function to signal us the DOM has been
240         // updated.
241         NETDATA.updatedDom = function() {
242                 NETDATA.options.updated_dom = 1;
243         }
244
245         // ----------------------------------------------------------------------------------------------------------------
246
247         NETDATA.generateChartDataURL = function() {
248                 self = $(this);
249
250                 var chart = self.data('chart');
251                 var host = self.data('host') || NETDATA.chartDefaults.host;
252                 var width = self.width();
253                 var height = self.height();
254                 var method = self.data('method') || NETDATA.chartDefaults.method;
255                 var after = self.data('after') || NETDATA.chartDefaults.after;
256                 var before = self.data('before') || NETDATA.chartDefaults.before;
257                 var library = self.data('chart-library') || NETDATA.chartDefaults.library;
258                 var dimensions = self.data('dimensions') || null;
259                 var pixels_per_point = self.data('pixels-per-point') || NETDATA.chartLibraries[library].pixels_per_point;
260
261                 if(self.data('chart-panning') || self.data('chart-zooming')) {
262                         before = self.data('panning-before') || 0;
263                         after = self.data('panning-after') || 0;
264                 }
265
266                 // force an options provided detail
267                 if(pixels_per_point < NETDATA.options.current.pixels_per_point)
268                         pixels_per_point = NETDATA.options.current.pixels_per_point
269
270                 var points = self.data('points') || Math.round(width / pixels_per_point);
271                 var format = self.data('format') || NETDATA.chartLibraries[library].format;
272                 var options = self.data('options') || NETDATA.chartLibraries[library].options;
273
274                 // build the data URL
275                 var url = host + chart.data_url;
276                 url += "&format="  + format;
277                 url += "&points="  + points.toString();
278                 url += "&group="   + method;
279                 url += "&options=" + options;
280                 if(NETDATA.chartLibraries[library].jsonWrapper) url += '|jsonwrap';
281
282                 if(after)
283                         url += "&after="  + after.toString();
284
285                 if(before)
286                         url += "&before=" + before.toString();
287
288                 if(dimensions)
289                         url += "&dimensions=" + dimensions;
290
291                 self.data('calculated-width', width)
292                         .data('calculated-height', height)
293                         .data('calculated-points', points)
294                         .data('calculated-options', options)
295                         .data('calculated-url', url);
296
297                 if(NETDATA.options.debug.chart_data_url) console.log('generateChartDataURL(): ' + url + ' WxH:' + width + 'x' + height + ' points: ' + points + ' library: ' + library);
298                 return url;
299         }
300
301         NETDATA.validateDomCharts = function(targets, index, callback) {
302                 if(NETDATA.options.debug.main_loop) console.log('validateDomCharts() working on ' + index);
303
304                 var target = targets.get(index);
305                 if(target == null) {
306                         if(NETDATA.options.debug.main_loop) console.log('validateDomCharts(): all ' + (index - 1) + ' charts parsed.');
307                         if(typeof callback == 'function') callback();
308                 }
309                 else {
310                         var self = $(target);
311                         if(!self.data('prepared')) {
312                                 self.data('prepared', true)
313                                         .data('updated', 0)
314                                         .data('chart-created', false)
315                                         .data('refresher-enabled', false)
316                                         .data('chart-panning', false)
317                                         .data('chart-zooming', false)
318                                         .data('chart-paused', false)
319                                         .data('panning-before', 0)
320                                         .data('panning-after', 0);
321
322                                 var id = self.data('netdata');
323                                 var host = self.data('host') || NETDATA.chartDefaults.host;
324                                 var library = self.data('chart-library') || NETDATA.chartDefaults.library;
325
326                                 if(NETDATA.options.debug.main_loop) console.log('validateDomCharts() parsing ' + id + ' of type ' + library);
327
328                                 if(typeof NETDATA.chartLibraries[library] == 'undefined') {
329                                         NETDATA.error(402, library);
330                                         NETDATA.messageInABox(target, 'chart library "' + library + '" is not found');
331                                         NETDATA.validateDomCharts(targets, ++index, callback);
332                                 }
333                                 else if(!NETDATA.chartLibraries[library].enabled) {
334                                         NETDATA.error(403, library);
335                                         NETDATA.messageInABox(target, 'chart library "' + library + '" is not enabled');
336                                         NETDATA.validateDomCharts(targets, ++index, callback);
337                                 }
338                                 else if(!NETDATA.chartLibraries[library].initialized) {
339                                         self.data('prepared', false);
340                                         NETDATA.chartLibraries[library].initialize(function() {
341                                                 NETDATA.validateDomCharts(targets, index, callback);
342                                         });
343                                 }
344                                 else {
345                                         var url = host + "/api/v1/chart?chart=" + id;
346
347                                         $.ajax( {
348                                                 url:  url,
349                                                 crossDomain: true
350                                         })
351                                         .done(function(chart) {
352                                                 self.data('chart', chart)
353                                                         .data('update-every', chart.update_every * 1000)
354                                                         .data('refresher-enabled', true)
355                                                         .data('host', host)
356                                                         .data('chart-library', library);
357                                         })
358                                         .fail(function() {
359                                                 NETDATA.error(404, url);
360                                                 NETDATA.messageInABox(target, 'chart "' + id + '" not found on url "' + url + '"');
361                                         })
362                                         .always(function() {
363                                                 NETDATA.validateDomCharts(targets, ++index, callback);
364                                         });
365                                 }
366                         }
367                         else {
368                                 NETDATA.validateDomCharts(targets, ++index, callback);
369                         }
370                 }
371         }
372
373         NETDATA.sizeDomCharts = function(targets, index, callback) {
374                 // this is used to quickly size all charts to their size
375
376                 if(NETDATA.options.debug.main_loop) console.log('sizeDomCharts() working on ' + index);
377
378                 var target = targets.get(index);
379                 if(target == null) {
380                         if(NETDATA.options.debug.main_loop) console.log('sizeDomCharts(): all ' + (index - 1) + ' charts sized.');
381                         if(typeof callback == 'function') callback();
382                 }
383                 else {
384                         var self = $(target);
385
386                         var id = self.data('netdata');
387                         var width = self.data('width') || NETDATA.chartDefaults.width;
388                         var height = self.data('height') || NETDATA.chartDefaults.height;
389
390                         self.css('width', width)
391                                 .css('height', height)
392                                 .css('display', 'inline-block')
393                                 .css('overflow', 'hidden');
394
395                         NETDATA.messageInABox(target, 'chart "' + id + '" is loading...');
396                         NETDATA.sizeDomCharts(targets, ++index, callback);
397                 }
398         }
399
400         NETDATA.getDomCharts = function(callback) {
401                 NETDATA.options.updated_dom = 0;
402
403                 NETDATA.options.targets = $('div[data-netdata]').filter(':visible')
404                         .bind('create', function(event, data) {
405                                 var self = $(this);
406
407                                 if(NETDATA.options.debug.chart_errors) {
408                                         NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
409                                         self.data('chart-created', true);
410                                 }
411                                 else {
412                                         try {
413                                                 NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
414                                                 self.data('chart-created', true);
415                                         }
416                                         catch(err) {
417                                                 NETDATA.messageInABox(this, 'chart "' + self.data('netdata') + '" failed to be created as ' + self.data('chart-library'));
418                                                 self.data('chart-created', false);
419                                         }
420                                 }
421                         })
422                         .bind('update', function(event, data) {
423                                 var self = $(this);
424                                 if(NETDATA.options.debug.chart_errors)
425                                         NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
426                                 else {
427                                         try {
428                                                 NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
429                                         }
430                                         catch(err) {
431                                                 NETDATA.messageInABox(this, 'chart "' + self.data('netdata') + '" failed to be updated as ' + self.data('chart-library'));
432                                                 self.data('chart-created', false);
433                                         }
434                                 }
435                         });
436
437                 if(NETDATA.options.debug.main_loop)
438                         console.log('DOM updated - there are ' + NETDATA.options.targets.length + ' charts on page.');
439
440                 NETDATA.sizeDomCharts(NETDATA.options.targets, 0, function() {
441                         NETDATA.validateDomCharts(NETDATA.options.targets, 0, callback);
442                 });
443         }
444
445         // ----------------------------------------------------------------------------------------------------------------
446
447         //var chart = function() {
448         //}
449
450         //chart.prototype.color = function() {
451         //      return 'red';
452         //}
453
454         //var c = new chart();
455         //c.color();
456
457         NETDATA.chartValuesDownloader = function(element, callback, panning) {
458                 var self = $(element);
459                 var last = self.data('updated') || 0;
460                 var every = self.data('update-every') || 1;
461
462                 // check if this chart has to be refreshed now
463                 var now = new Date().getTime();
464                 if(!panning && last + every > now) {
465                         if(NETDATA.options.debug.chart_timing) console.log(self.data('netdata') + ' too soon - skipping.');
466                         if(typeof callback == 'function') callback();
467                 }
468                 else if(!panning && !self.visible(true)) {
469                         if(NETDATA.options.debug.visibility) console.log(self.data('netdata') + ' is NOT visible.');
470                         if(typeof callback == 'function') callback();
471                 }
472                 else {
473                         if(NETDATA.options.debug.visibility) console.log(self.data('netdata') + ' is visible, downloading data...');
474                         $.ajax( {
475                                 url: NETDATA.generateChartDataURL.call(element), // self.data('chart-url'),
476                                 crossDomain: true
477                         })
478                         .then(function(data) {
479                                 var started = new Date().getTime();
480
481                                 // if the result is JSON, find the latest update-every
482                                 if(NETDATA.chartLibraries[self.data('chart-library')].jsonWrapper) {
483                                         if(!panning && typeof data.update_every != 'undefined')
484                                                 self.data('update-every', data.update_every * 1000);
485
486                                         if(typeof data.after != 'undefined')
487                                                 self.data('panning-after', data.after);
488
489                                         if(typeof data.before != 'undefined')
490                                                 self.data('panning-before', data.before);
491                                 }
492
493                                 if(self.data('chart-created')) {
494                                         if(NETDATA.options.debug.chart_calls) console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
495                                         self.trigger('update', [data]);
496                                         // NETDATA.chartLibraries[self.data('chart-library')].update(element, data);
497                                 }
498                                 else {
499                                         if(NETDATA.options.debug.chart_calls) console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
500                                         self.trigger('create', [data]);
501                                         //NETDATA.chartLibraries[self.data('chart-library')].create(element, data);
502                                 }
503
504                                 var ended = new Date().getTime();
505                                 self.data('updated', ended);
506
507                                 var dt = ended - started;
508
509                                 self.data('refresh-dt', dt);
510                                 var element_name = self.data('dt-element-name') || null;
511                                 if(element_name) {
512                                         var element = document.getElementById(element_name) || null;
513                                         if(element) {
514                                                 element.innerHTML = dt.toString();
515                                         }
516                                 }
517                         })
518                         .fail(function() {
519                                 NETDATA.messageInABox(element, 'cannot download chart "' + self.data('netdata') + '" values from url "' + self.data('chart-url') + '"');
520                         })
521                         .always(function() {
522                                 if(typeof callback == 'function') callback();
523                         });
524                 }
525         };
526
527         NETDATA.chartRefresher = function(index) {
528                 // if(NETDATA.options.debug.mail_loop) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
529
530                 if(!NETDATA.options.page_is_visible) {
531                         if(NETDATA.options.debug.main_loop) console.log('waiting focus...');
532                         setTimeout(function() {
533                                         NETDATA.chartRefresher(index);
534                                 }, NETDATA.options.current.idle_lost_focus);
535                 }
536                 else {
537                         now = new Date().getTime();
538
539                         if(now < NETDATA.options.refreshed_stop_until) {
540                                 if(NETDATA.options.debug.main_loop) console.log('refreshed stopped until...');
541                                 setTimeout(function() {
542                                                 NETDATA.chartRefresher(index);
543                                         }, NETDATA.options.current.idle_between_loops);
544                         }
545                         else if(NETDATA.options.updated_dom) {
546                                 // the dom has been updated
547                                 // get the dom parts again
548                                 NETDATA.getDomCharts(function() {
549                                         NETDATA.chartRefresher(0);
550                                 });
551                         }
552                         else {
553                                 var target = NETDATA.options.targets.get(index);
554                                 if(target == null) {
555                                         if(NETDATA.options.debug.main_loop) console.log('waiting to restart main loop...');
556                                         NETDATA.options.last_paused = now;
557
558                                         setTimeout(function() {
559                                                 NETDATA.chartRefresher(0);
560                                         }, NETDATA.options.current.idle_between_loops);
561                                 }
562                                 else {
563                                         var self = $(target);
564                                         if(!self.data('refresher-enabled')) {
565                                                 if(NETDATA.options.debug.main_loop) console.log('chart has refresher disabled...');
566                                                 NETDATA.chartRefresher(++index);
567                                         }
568                                         else if(self.data('chart-panning')) {
569                                                 if(NETDATA.options.debug.main_loop) console.log('chart is panning...');
570                                                 NETDATA.chartRefresher(++index);
571                                         }
572                                         else if(self.data('chart-zooming')) {
573                                                 if(NETDATA.options.debug.main_loop) console.log('chart is zooming...');
574                                                 NETDATA.chartRefresher(++index);
575                                         }
576                                         else if(self.data('chart-paused')) {
577                                                 if(NETDATA.options.debug.main_loop) console.log('chart is paused...');
578                                                 NETDATA.chartRefresher(++index);
579                                         }
580                                         else {
581                                                 if(now - NETDATA.options.last_paused < NETDATA.options.current.fast_render_timeframe) {
582                                                         if(NETDATA.options.debug.main_loop) console.log('fast rendering...');
583
584                                                         NETDATA.chartValuesDownloader(target, function() {
585                                                                 NETDATA.chartRefresher(++index);
586                                                         }, false);
587                                                 }
588                                                 else {
589                                                         if(NETDATA.options.debug.main_loop) console.log('waiting for next refresh...');
590                                                         NETDATA.options.last_paused = now;
591
592                                                         setTimeout(function() {
593                                                                 NETDATA.chartValuesDownloader(target, function() {
594                                                                         NETDATA.chartRefresher(++index);
595                                                                 }, false);
596                                                         }, NETDATA.options.current.idle_between_charts);
597                                                 }
598                                         }
599                                 }
600                         }
601                 }
602         }
603
604         // ----------------------------------------------------------------------------------------------------------------
605         // peity
606
607         NETDATA.peityInitialize = function(callback) {
608                 if(typeof netdataStopPeity == 'undefined') {
609                         $.getScript(NETDATA.peity_js)
610                                 .done(function() {
611                                         NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
612                                 })
613                                 .fail(function() {
614                                         NETDATA.error(100, NETDATA.peity_js);
615                                 })
616                                 .always(function() {
617                                         if(typeof callback == "function")
618                                                 callback();
619                                 })
620                 }
621                 else {
622                         NETDATA.chartLibraries.peity.enabled = false;
623                         if(typeof callback == "function")
624                                 callback();
625                 }
626         };
627
628         NETDATA.peityChartUpdate = function(element, data) {
629                 var self = $(element);
630                 var instance = self.data('peity-instance');
631                 var ins = $(instance);
632                 ins.html(data.result);
633
634                 // peity.change() does not accept options
635                 // to pass width and height
636                 //ins.change();
637                 ins.peity('line', { width: self.data('calculated-width'), height: self.data('calculated-height') })
638         }
639
640         NETDATA.peityChartCreate = function(element, data) {
641                 var self = $(element);
642
643                 var uuid = NETDATA.guid();
644                 element.innerHTML = '<div id="' + uuid + '">' + data.result + '</div>';
645                 var instance = document.getElementById(uuid);
646                 var ins = $(instance);
647
648                 ins.peity('line', { width: self.data('calculated-width'), height: self.data('calculated-height') })
649
650                 self.data('peity-uuid', uuid)
651                         .data('peity-instance', instance)
652                         .data('chart-created', true);
653         }
654
655         // ----------------------------------------------------------------------------------------------------------------
656         // sparkline
657
658         NETDATA.sparklineInitialize = function(callback) {
659                 if(typeof netdataStopSparkline == 'undefined') {
660                         $.getScript(NETDATA.sparkline_js)
661                                 .done(function() {
662                                         NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
663                                 })
664                                 .fail(function() {
665                                         NETDATA.error(100, NETDATA.sparkline_js);
666                                 })
667                                 .always(function() {
668                                         if(typeof callback == "function")
669                                                 callback();
670                                 })
671                 }
672                 else {
673                         NETDATA.chartLibraries.sparkline.enabled = false;
674                         if(typeof callback == "function") 
675                                 callback();
676                 }
677         };
678
679         NETDATA.sparklineChartUpdate = function(element, data) {
680                 var self = $(element);
681                 var options = self.data('sparkline-options');
682                 options.width = self.data('calculated-width');
683                 options.height = self.data('calculated-height');
684                 self.sparkline(data.result, options);
685         }
686
687         NETDATA.sparklineChartCreate = function(element, data) {
688                 var self = $(element);
689                 var chart = self.data('chart');
690                 var type = self.data('sparkline-type') || 'line';
691                 var lineColor = self.data('sparkline-linecolor') || NETDATA.colors[0];
692                 var fillColor = self.data('sparkline-fillcolor') || (chart.chart_type == 'line')?'#FFF':NETDATA.ColorLuminance(lineColor, 0.8);
693                 var chartRangeMin = self.data('sparkline-chartrangemin') || undefined;
694                 var chartRangeMax = self.data('sparkline-chartrangemax') || undefined;
695                 var composite = self.data('sparkline-composite') || undefined;
696                 var enableTagOptions = self.data('sparkline-enabletagoptions') || undefined;
697                 var tagOptionPrefix = self.data('sparkline-tagoptionprefix') || undefined;
698                 var tagValuesAttribute = self.data('sparkline-tagvaluesattribute') || undefined;
699                 var disableHiddenCheck = self.data('sparkline-disablehiddencheck') || undefined;
700                 var defaultPixelsPerValue = self.data('sparkline-defaultpixelspervalue') || undefined;
701                 var spotColor = self.data('sparkline-spotcolor') || undefined;
702                 var minSpotColor = self.data('sparkline-minspotcolor') || undefined;
703                 var maxSpotColor = self.data('sparkline-maxspotcolor') || undefined;
704                 var spotRadius = self.data('sparkline-spotradius') || undefined;
705                 var valueSpots = self.data('sparkline-valuespots') || undefined;
706                 var highlightSpotColor = self.data('sparkline-highlightspotcolor') || undefined;
707                 var highlightLineColor = self.data('sparkline-highlightlinecolor') || undefined;
708                 var lineWidth = self.data('sparkline-linewidth') || undefined;
709                 var normalRangeMin = self.data('sparkline-normalrangemin') || undefined;
710                 var normalRangeMax = self.data('sparkline-normalrangemax') || undefined;
711                 var drawNormalOnTop = self.data('sparkline-drawnormalontop') || undefined;
712                 var xvalues = self.data('sparkline-xvalues') || undefined;
713                 var chartRangeClip = self.data('sparkline-chartrangeclip') || undefined;
714                 var xvalues = self.data('sparkline-xvalues') || undefined;
715                 var chartRangeMinX = self.data('sparkline-chartrangeminx') || undefined;
716                 var chartRangeMaxX = self.data('sparkline-chartrangemaxx') || undefined;
717                 var disableInteraction = self.data('sparkline-disableinteraction') || false;
718                 var disableTooltips = self.data('sparkline-disabletooltips') || false;
719                 var disableHighlight = self.data('sparkline-disablehighlight') || false;
720                 var highlightLighten = self.data('sparkline-highlightlighten') || 1.4;
721                 var highlightColor = self.data('sparkline-highlightcolor') || undefined;
722                 var tooltipContainer = self.data('sparkline-tooltipcontainer') || undefined;
723                 var tooltipClassname = self.data('sparkline-tooltipclassname') || undefined;
724                 var tooltipFormat = self.data('sparkline-tooltipformat') || undefined;
725                 var tooltipPrefix = self.data('sparkline-tooltipprefix') || undefined;
726                 var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + chart.units;
727                 var tooltipSkipNull = self.data('sparkline-tooltipskipnull') || true;
728                 var tooltipValueLookups = self.data('sparkline-tooltipvaluelookups') || undefined;
729                 var tooltipFormatFieldlist = self.data('sparkline-tooltipformatfieldlist') || undefined;
730                 var tooltipFormatFieldlistKey = self.data('sparkline-tooltipformatfieldlistkey') || undefined;
731                 var numberFormatter = self.data('sparkline-numberformatter') || function(n){ return n.toFixed(2); };
732                 var numberDigitGroupSep = self.data('sparkline-numberdigitgroupsep') || undefined;
733                 var numberDecimalMark = self.data('sparkline-numberdecimalmark') || undefined;
734                 var numberDigitGroupCount = self.data('sparkline-numberdigitgroupcount') || undefined;
735                 var animatedZooms = self.data('sparkline-animatedzooms') || false;
736
737                 var options = {
738                         type: type,
739                         lineColor: lineColor,
740                         fillColor: fillColor,
741                         chartRangeMin: chartRangeMin,
742                         chartRangeMax: chartRangeMax,
743                         composite: composite,
744                         enableTagOptions: enableTagOptions,
745                         tagOptionPrefix: tagOptionPrefix,
746                         tagValuesAttribute: tagValuesAttribute,
747                         disableHiddenCheck: disableHiddenCheck,
748                         defaultPixelsPerValue: defaultPixelsPerValue,
749                         spotColor: spotColor,
750                         minSpotColor: minSpotColor,
751                         maxSpotColor: maxSpotColor,
752                         spotRadius: spotRadius,
753                         valueSpots: valueSpots,
754                         highlightSpotColor: highlightSpotColor,
755                         highlightLineColor: highlightLineColor,
756                         lineWidth: lineWidth,
757                         normalRangeMin: normalRangeMin,
758                         normalRangeMax: normalRangeMax,
759                         drawNormalOnTop: drawNormalOnTop,
760                         xvalues: xvalues,
761                         chartRangeClip: chartRangeClip,
762                         chartRangeMinX: chartRangeMinX,
763                         chartRangeMaxX: chartRangeMaxX,
764                         disableInteraction: disableInteraction,
765                         disableTooltips: disableTooltips,
766                         disableHighlight: disableHighlight,
767                         highlightLighten: highlightLighten,
768                         highlightColor: highlightColor,
769                         tooltipContainer: tooltipContainer,
770                         tooltipClassname: tooltipClassname,
771                         tooltipChartTitle: chart.title,
772                         tooltipFormat: tooltipFormat,
773                         tooltipPrefix: tooltipPrefix,
774                         tooltipSuffix: tooltipSuffix,
775                         tooltipSkipNull: tooltipSkipNull,
776                         tooltipValueLookups: tooltipValueLookups,
777                         tooltipFormatFieldlist: tooltipFormatFieldlist,
778                         tooltipFormatFieldlistKey: tooltipFormatFieldlistKey,
779                         numberFormatter: numberFormatter,
780                         numberDigitGroupSep: numberDigitGroupSep,
781                         numberDecimalMark: numberDecimalMark,
782                         numberDigitGroupCount: numberDigitGroupCount,
783                         animatedZooms: animatedZooms,
784                         width: self.data('calculated-width'),
785                         height: self.data('calculated-height')
786                 };
787
788                 var uuid = NETDATA.guid();
789                 element.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
790                 var div = document.getElementById(uuid);
791
792                 self.sparkline(data.result, options);
793                 self.data('sparkline-options', options)
794                         .data('uuid', uuid)
795                         .data('chart-created', true);
796         };
797
798         // ----------------------------------------------------------------------------------------------------------------
799         // dygraph
800
801         NETDATA.dygraphAllCharts = [];
802         NETDATA.dygraphInitSync = function(callback) {
803                 //$.getScript(NETDATA.serverDefault + 'dygraph-synchronizer.js')
804                 //      .always(function() {
805                                 if(typeof callback == "function")
806                                         callback();
807                 //      })
808         }
809
810         NETDATA.dygraphSync = null;
811         NETDATA.dygraphSyncAll = function() {
812                 if(NETDATA.dygraphSync) {
813                         NETDATA.dygraphSync.detach();
814                         NETDATA.dygraphSync = null;
815                 }
816
817                 NETDATA.dygraphSync = Dygraph.synchronize(NETDATA.dygraphAllCharts, {
818                         selection: true,
819                         zoom: false
820                 });
821         }
822
823         NETDATA.dygraphInitialize = function(callback) {
824                 if(typeof netdataStopDygraph == 'undefined') {
825                         $.getScript(NETDATA.dygraph_js)
826                                 .done(function() {
827                                         NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
828                                 })
829                                 .fail(function() {
830                                         NETDATA.error(100, NETDATA.dygraph_js);
831                                 })
832                                 .always(function() {
833                                         NETDATA.dygraphInitSync(callback);
834                                 })
835                 }
836                 else {
837                         NETDATA.chartLibraries.dygraph.enabled = false;
838                         if(typeof callback == "function")
839                                 callback();
840                 }
841         };
842
843         NETDATA.dygraphClickCallback = function(element, dygraph, event, x, points) {
844                 if(NETDATA.options.debug.dygraph) console.log('dygraphClickCallback()');
845                 
846                 // NETDATA.dygraphDoubleClickDetect(element, dygraph);
847                 NETDATA.dygraphReset(element, dygraph);
848         }
849
850         NETDATA.dygraphPointClickCallback = function(element, dygraph, event, point) {
851                 if(NETDATA.options.debug.dygraph) console.log('dygraphPointClickCallback()');
852
853                 // NETDATA.dygraphDoubleClickDetect(element, dygraph);
854                 NETDATA.dygraphReset(element, dygraph);
855         }
856
857         NETDATA.dygraphDrawCallback = function(element, dygraph, is_initial) {
858                 if(NETDATA.options.debug.dygraph) console.log('dygraphDrawCallback()');
859
860                 var x_range = dygraph.xAxisRange();
861                 var after = Math.round(x_range[0] / 1000);
862                 var before = Math.round(x_range[1] / 1000);
863
864                 NETDATA.dygraphZoomOrPan(element, dygraph, after, before, false, true);
865         }
866
867         NETDATA.dygraphZoomCallback = function(element, dygraph, minDate, maxDate, yRanges) {
868                 if(NETDATA.options.debug.dygraph) console.log('dygraphZoomCallback()');
869                 
870                 NETDATA.dygraphZoomOrPan(element, dygraph, Math.round(minDate / 1000), Math.round(maxDate / 1000), false, true);
871         }
872
873         NETDATA.dygraphHighlightCallback = function(element, dygraph, event, x, points, row, seriesName) {
874                 if(NETDATA.options.debug.dygraph) console.log('dygraphHighlightCallback()');
875
876                 // stop refreshing
877                 self = $(element);
878                 self.data('chart-paused', true);
879         }
880
881         NETDATA.dygraphUnhighlightCallback = function(element, dygraph) {
882                 if(NETDATA.options.debug.dygraph) console.log('dygraphUnhighlightCallback()');
883
884                 // start refreshing
885                 self = $(element);
886                 self.data('chart-paused', false);
887         }
888
889         NETDATA.dygraphMouseDown = function(element, dygraph, event, context) {
890                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseDown()');
891
892                 context.initializeMouseDown(event, dygraph, context);
893                 if (event.altKey || event.shiftKey)
894                         Dygraph.startZoom(event, dygraph, context);
895                 else
896                         Dygraph.startPan(event, dygraph, context);
897         }
898
899         NETDATA.dygraphMouseMove = function(element, dygraph, event, context) {
900                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseMove()');
901
902                 if (context.isPanning)
903                         Dygraph.movePan(event, dygraph, context);
904                 else if (context.isZooming)
905                         Dygraph.moveZoom(event, dygraph, context);
906         }
907
908         NETDATA.dygraphMouseUp = function(element, dygraph, event, context) {
909                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseUp()');
910
911                 if (context.isPanning)
912                         Dygraph.endPan(event, dygraph, context);
913                 else if (context.isZooming)
914                         Dygraph.endZoom(event, dygraph, context);
915         }
916
917         NETDATA.dygraphMouseClick = function(element, dygraph, event, context) {
918                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseClick()');
919
920         }
921
922         NETDATA.dygraphMouseDoubleClick = function(element, dygraph, event, context) {
923                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseDoubleClick()');
924                 NETDATA.dygraphReset(element, dygraph);
925         }
926
927         NETDATA.dygraphMouseWheel = function(element, dygraph, event, context) {
928                 if(NETDATA.options.debug.dygraph) console.log('dygraphMouseWheel()');
929
930                 if(event.altKey || event.shiftKey) {
931                         // http://dygraphs.com/gallery/interaction-api.js
932                         var normal = (event.detail) ? event.detail * -1 : event.wheelDelta / 40;
933                         var percentage = normal / 10;
934
935                         self = $(element);
936                         var before_old = self.data('panning-before');
937                         var after_old = self.data('panning-after');
938                         var range_old = before_old - after_old;
939
940                         var range = range_old * ( 1 - percentage );
941                         var dt = Math.round((range_old - range) / 2);
942                         before = before_old - dt;
943                         after  = after_old  + dt;
944
945                         if(NETDATA.options.debug.dygraph) console.log('percent: ' + percentage + ' from ' + after_old + ' - ' + before_old + ' to ' + after + ' - ' + before + ', range from ' + (before_old - after_old).toString() + ' to ' + (before - after).toString());
946
947                         NETDATA.dygraphZoomOrPan(element, dygraph, after, before, true);
948                 }
949         }
950
951         NETDATA.dygraphReset = function(element, dygraph) {
952                 if(NETDATA.options.debug.dygraph) console.log('dygraphReset()');
953
954                 self = $(element);
955
956                 if(self.data('chart-panning') || self.data('chart-paused')) {
957                         self.data('chart-panning', false)
958                                 .data('chart-zooming', false)
959                                 .data('chart-paused', false)
960                                 .data('panning-before', 0)
961                                 .data('panning-after', 0)
962                                 .data('updated', 0)
963                                 .data('panning-before-max', 0);
964                         
965                         NETDATA.options.refreshed_stop_until = 0;
966                         NETDATA.chartValuesDownloader(element, null, false);
967                 }
968         }
969
970         NETDATA.dygraphZoomOrPan = function(element, dygraph, after, before, zoom) {
971                 if(NETDATA.options.debug.dygraph) console.log('dygraphZoomOrPan()');
972
973                 self = $(element);
974
975                 var before_old = self.data('panning-before');
976                 var after_old = self.data('panning-after');
977                 var range_old = before_old - after_old;
978
979                 var shift = Math.abs(before_old - before);
980
981                 var range = before - after;
982
983                 if((shift > range_old / 20 || zoom) && range > 10) {
984                         // the user is panning
985                         if(NETDATA.options.debug.dygraph) console.log('dygraphZoomOrPan() ' + after_old + ' - ' + before_old + ', NEW: ' + after + ' - ' + before + ', shift by: ' + shift + ' old range: ' + (before_old - after_old).toString() + ' new range: ' + (before - after).toString());
986                         
987                         if(!self.data('chart-panning') && !self.data('chart-zooming')) {
988                                 self.data('chart-panning', true)
989                                         .data('panning-before-max', before);
990                         }
991
992                         var before_max = self.data('panning-before-max');
993                         if(zoom || before <= before_max) {
994                                 NETDATA.options.refreshed_stop_until = now + 2000;
995
996                                 console.log('dygraphZoomOrPan() rendering.......................................................................................................');
997
998                                 if(zoom) {
999                                         self.data('chart-panning', false)
1000                                                 .data('chart-zooming', true);
1001                                 }
1002                                 else {
1003                                         self.data('chart-panning', true)
1004                                                 .data('chart-zooming', false);
1005                                 }
1006
1007                                 self.data('chart-paused', true)
1008                                         .data('panning-before', before)
1009                                         .data('panning-after', after)
1010                                         .data('updated', 0);
1011                                 
1012                                 NETDATA.chartValuesDownloader(element, null, true);
1013                         }
1014                 }
1015         }
1016
1017         NETDATA.dygraphChartUpdate = function(element, data) {
1018                 if(NETDATA.options.debug.dygraph) console.log('dygraphChartUpdate()');
1019
1020                 var self = $(element);
1021                 var dygraph = self.data('dygraph-instance');
1022
1023                 if(self.data('chart-panning')) {
1024                         dygraph.updateOptions({
1025                                 file: data.result.data,
1026                                 labels: data.result.labels,
1027                                 labelsDivWidth: self.width() - 70
1028                         });
1029                 }
1030                 else {
1031                         dygraph.updateOptions({
1032                                 file: data.result.data,
1033                                 labels: data.result.labels,
1034                                 labelsDivWidth: self.width() - 70,
1035                                 dateWindow: null,
1036                         valueRange: null
1037                         });
1038                 }
1039         };
1040
1041         NETDATA.dygraphChartCreate = function(element, data) {
1042                 if(NETDATA.options.debug.dygraph) console.log('dygraphChartCreate()');
1043
1044                 var self = $(element);
1045                 var chart = self.data('chart');
1046                 var title = self.data('dygraph-title') || chart.title;
1047                 var titleHeight = self.data('dygraph-titleheight') || 20;
1048                 var labelsDiv = self.data('dygraph-labelsdiv') || undefined;
1049                 var connectSeparatedPoints = self.data('dygraph-connectseparatedpoints') || false;
1050                 var yLabelWidth = self.data('dygraph-ylabelwidth') || 12;
1051                 var stackedGraph = self.data('dygraph-stackedgraph') || (chart.chart_type == 'stacked')?true:false;
1052                 var stackedGraphNaNFill = self.data('dygraph-stackedgraphnanfill') || 'none';
1053                 var hideOverlayOnMouseOut = self.data('dygraph-hideoverlayonmouseout') || true;
1054                 var fillGraph = self.data('dygraph-fillgraph') || (chart.chart_type == 'area')?true:false;
1055                 var drawPoints = self.data('dygraph-drawpoints') || false;
1056                 var labelsDivStyles = self.data('dygraph-labelsdivstyles') || { 'fontSize':'10px' };
1057                 var labelsDivWidth = self.data('dygraph-labelsdivwidth') || self.width() - 70;
1058                 var labelsSeparateLines = self.data('dygraph-labelsseparatelines') || false;
1059                 var labelsShowZeroValues = self.data('dygraph-labelsshowzerovalues') || true;
1060                 var legend = self.data('dygraph-legend') || 'onmouseover';
1061                 var showLabelsOnHighlight = self.data('dygraph-showlabelsonhighlight') || true;
1062                 var gridLineColor = self.data('dygraph-gridlinecolor') || '#EEE';
1063                 var axisLineColor = self.data('dygraph-axislinecolor') || '#EEE';
1064                 var maxNumberWidth = self.data('dygraph-maxnumberwidth') || 8;
1065                 var sigFigs = self.data('dygraph-sigfigs') || null;
1066                 var digitsAfterDecimal = self.data('dygraph-digitsafterdecimal') || 2;
1067                 var axisLabelFontSize = self.data('dygraph-axislabelfontsize') || 10;
1068                 var axisLineWidth = self.data('dygraph-axislinewidth') || 0.3;
1069                 var drawAxis = self.data('dygraph-drawaxis') || true;
1070                 var strokeWidth = self.data('dygraph-strokewidth') || 1.0;
1071                 var drawGapEdgePoints = self.data('dygraph-drawgapedgepoints') || true;
1072                 var colors = self.data('dygraph-colors') || NETDATA.colors;
1073                 var pointSize = self.data('dygraph-pointsize') || 1;
1074                 var stepPlot = self.data('dygraph-stepplot') || false;
1075                 var strokeBorderColor = self.data('dygraph-strokebordercolor') || 'white';
1076                 var strokeBorderWidth = self.data('dygraph-strokeborderwidth') || (chart.chart_type == 'stacked')?1.0:0.0;
1077                 var strokePattern = self.data('dygraph-strokepattern') || undefined;
1078                 var highlightCircleSize = self.data('dygraph-highlightcirclesize') || 3;
1079                 var highlightSeriesOpts = self.data('dygraph-highlightseriesopts') || { strokeWidth: 1.5 };
1080                 var highlightSeriesBackgroundAlpha = self.data('dygraph-highlightseriesbackgroundalpha') || (chart.chart_type == 'stacked')?0.7:0.5;
1081                 var pointClickCallback = self.data('dygraph-pointclickcallback') || undefined;
1082                 var showRangeSelector = self.data('dygraph-showrangeselector') || false;
1083                 var showRoller = self.data('dygraph-showroller') || false;
1084                 var valueFormatter = self.data('dygraph-valueformatter') || undefined; //function(x){ return x.toFixed(2); };
1085                 var rightGap = self.data('dygraph-rightgap') || 5;
1086                 var drawGrid = self.data('dygraph-drawgrid') || true;
1087                 var drawXGrid = self.data('dygraph-drawxgrid') || undefined;
1088                 var drawYGrid = self.data('dygraph-drawygrid') || undefined;
1089                 var gridLinePattern = self.data('dygraph-gridlinepattern') || null;
1090                 var gridLineWidth = self.data('dygraph-gridlinewidth') || 0.3;
1091
1092                 var options = {
1093                         title: title,
1094                         titleHeight: titleHeight,
1095                         ylabel: chart.units,
1096                         yLabelWidth: yLabelWidth,
1097                         connectSeparatedPoints: connectSeparatedPoints,
1098                         drawPoints: drawPoints,
1099                         fillGraph: fillGraph,
1100                         stackedGraph: stackedGraph,
1101                         stackedGraphNaNFill: stackedGraphNaNFill,
1102                         drawGrid: drawGrid,
1103                         drawXGrid: drawXGrid,
1104                         drawYGrid: drawYGrid,
1105                         gridLinePattern: gridLinePattern,
1106                         gridLineWidth: gridLineWidth,
1107                         gridLineColor: gridLineColor,
1108                         axisLineColor: axisLineColor,
1109                         axisLineWidth: axisLineWidth,
1110                         drawAxis: drawAxis,
1111                         hideOverlayOnMouseOut: hideOverlayOnMouseOut,
1112                         labelsDiv: labelsDiv,
1113                         labelsDivStyles: labelsDivStyles,
1114                         labelsDivWidth: labelsDivWidth,
1115                         labelsSeparateLines: labelsSeparateLines,
1116                         labelsShowZeroValues: labelsShowZeroValues,
1117                         labelsKMB: false,
1118                         labelsKMG2: false,
1119                         legend: legend,
1120                         showLabelsOnHighlight: showLabelsOnHighlight,
1121                         maxNumberWidth: maxNumberWidth,
1122                         sigFigs: sigFigs,
1123                         digitsAfterDecimal: digitsAfterDecimal,
1124                         axisLabelFontSize: axisLabelFontSize,
1125                         colors: colors,
1126                         strokeWidth: strokeWidth,
1127                         drawGapEdgePoints: drawGapEdgePoints,
1128                         pointSize: pointSize,
1129                         stepPlot: stepPlot,
1130                         strokeBorderColor: strokeBorderColor,
1131                         strokeBorderWidth: strokeBorderWidth,
1132                         strokePattern: strokePattern,
1133                         highlightCircleSize: highlightCircleSize,
1134                         highlightSeriesOpts: highlightSeriesOpts,
1135                         highlightSeriesBackgroundAlpha: highlightSeriesBackgroundAlpha,
1136                         pointClickCallback: pointClickCallback,
1137                         showRangeSelector: showRangeSelector,
1138                         showRoller: showRoller,
1139                         valueFormatter: valueFormatter,
1140                         rightGap: rightGap,
1141                         labels: data.result.labels,
1142                         axes: {
1143                                 x: {
1144                                         pixelsPerLabel: 50,
1145                                         ticker: Dygraph.dateTicker,
1146                                         axisLabelFormatter: function (d, gran) {
1147                                                 return Dygraph.zeropad(d.getHours()) + ":" + Dygraph.zeropad(d.getMinutes()) + ":" + Dygraph.zeropad(d.getSeconds());
1148                                         },
1149                                         valueFormatter :function (ms) {
1150                                                 var d = new Date(ms);
1151                                                 return Dygraph.zeropad(d.getHours()) + ":" + Dygraph.zeropad(d.getMinutes()) + ":" + Dygraph.zeropad(d.getSeconds());
1152                                         }
1153                                 },
1154                                 y: {
1155                                         pixelsPerLabel: 15
1156                                 }
1157                         },
1158                         //clickCallback: function(e, x, points) { NETDATA.dygraphClickCallback(element, this, e, x, points); },
1159                         //pointClickCallback: function(e, point) { NETDATA.dygraphPointClickCallback(element, this, e, point); },
1160                         drawCallback: function(dygraph, is_initial) { NETDATA.dygraphDrawCallback(element, dygraph, is_initial); },
1161                         zoomCallback: function(minDate, maxDate, yRanges) { NETDATA.dygraphZoomCallback(element, this, minDate, maxDate, yRanges); },
1162                         highlightCallback: function(event, x, points, row, seriesName) { NETDATA.dygraphHighlightCallback(element, this, event, x, points, row, seriesName); },
1163                         unhighlightCallback: function(event) { NETDATA.dygraphUnhighlightCallback(element, this, event); },
1164                         interactionModel : {
1165                                 mousedown: function(event, dygraph, context) { NETDATA.dygraphMouseDown(element, dygraph, event, context); },
1166                                 mousemove: function(event, dygraph, context) { NETDATA.dygraphMouseMove(element, dygraph, event, context); },
1167                                 mouseup: function(event, dygraph, context) { NETDATA.dygraphMouseUp(element, dygraph, event, context); },
1168                                 click: function(event, dygraph, context) { NETDATA.dygraphMouseClick(element, dygraph, event, context); },
1169                                 dblclick: function(event, dygraph, context) { NETDATA.dygraphMouseDoubleClick(element, dygraph, event, context); },
1170                                 mousewheel: function(event, dygraph, context) { NETDATA.dygraphMouseWheel(element, dygraph, event, context); }
1171                         }                       
1172                 };
1173
1174                 var uuid = NETDATA.guid();
1175                 self.html('<div id="' + uuid + '" style="width: 100%; height: 100%;"></div>');
1176
1177                 var dchart = new Dygraph(document.getElementById(uuid),
1178                         data.result.data, options);
1179
1180                 self.data('dygraph-instance', dchart)
1181                         .data('dygraph-options', options)
1182                         .data('uuid', uuid)
1183                         .data('chart-created', true);
1184
1185                 //NETDATA.dygraphAllCharts.push(dchart);
1186                 //if(NETDATA.dygraphAllCharts.length > 1)
1187                 //      NETDATA.dygraphSyncAll();
1188         };
1189
1190         // ----------------------------------------------------------------------------------------------------------------
1191         // morris
1192
1193         NETDATA.morrisInitialize = function(callback) {
1194                 if(typeof netdataStopMorris == 'undefined') {
1195
1196                         // morris requires raphael
1197                         if(!NETDATA.chartLibraries.raphael.initialized) {
1198                                 if(NETDATA.chartLibraries.raphael.enabled) {
1199                                         NETDATA.raphaelInitialize(function() {
1200                                                 NETDATA.morrisInitialize(callback);
1201                                         });
1202                                 }
1203                                 else {
1204                                         NETDATA.chartLibraries.morris.enabled = false;
1205                                         if(typeof callback == "function")
1206                                                 callback();
1207                                 }
1208                         }
1209
1210                         var fileref = document.createElement("link");
1211                         fileref.setAttribute("rel", "stylesheet");
1212                         fileref.setAttribute("type", "text/css");
1213                         fileref.setAttribute("href", NETDATA.morris_css);
1214
1215                         if (typeof fileref != "undefined")
1216                                 document.getElementsByTagName("head")[0].appendChild(fileref);
1217
1218                         $.getScript(NETDATA.morris_js)
1219                                 .done(function() {
1220                                         NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
1221                                 })
1222                                 .fail(function() {
1223                                         NETDATA.error(100, NETDATA.morris_js);
1224                                 })
1225                                 .always(function() {
1226                                         if(typeof callback == "function")
1227                                                 callback();
1228                                 })
1229                 }
1230                 else {
1231                         NETDATA.chartLibraries.morris.enabled = false;
1232                         if(typeof callback == "function")
1233                                 callback();
1234                 }
1235         };
1236
1237         NETDATA.morrisChartUpdate = function(element, data) {
1238                 var self = $(element);
1239                 var morris = self.data('morris-instance');
1240
1241                 if(morris != null) {
1242                         console.log('updating morris');
1243                         morris.setData(data.result.data);
1244                 }
1245                 else
1246                         console.log('not updating morris');
1247         };
1248
1249         NETDATA.morrisChartCreate = function(element, data) {
1250                 var self = $(element);
1251                 var chart = self.data('chart');
1252
1253                 var uuid = NETDATA.guid();
1254                 self.html('<div id="' + uuid + '" style="width: ' + self.data('calculated-width') + 'px; height: ' + self.data('calculated-height') + 'px;"></div>');
1255
1256                 var options = {
1257                                 element: uuid,
1258                                 data: data.result.data,
1259                                 xkey: 'time',
1260                                 ykeys: data.dimension_names,
1261                                 labels: data.dimension_names,
1262                                 lineWidth: 2,
1263                                 pointSize: 2,
1264                                 smooth: true,
1265                                 hideHover: 'auto',
1266                                 parseTime: true,
1267                                 continuousLine: false,
1268                                 behaveLikeLine: false
1269                 };
1270
1271                 var morris;
1272                 if(chart.chart_type == 'line')
1273                         morris = new Morris.Line(options);
1274
1275                 else if(chart.chart_type == 'area') {
1276                         options.behaveLikeLine = true;
1277                         morris = new Morris.Area(options);
1278                 }
1279                 else // stacked
1280                         morris = new Morris.Area(options);
1281
1282                 self.data('morris-instance', morris)
1283                         .data('chart-created', true);
1284         };
1285
1286         // ----------------------------------------------------------------------------------------------------------------
1287         // raphael
1288
1289         NETDATA.raphaelInitialize = function(callback) {
1290                 if(typeof netdataStopRaphael == 'undefined') {
1291                         $.getScript(NETDATA.raphael_js)
1292                                 .done(function() {
1293                                         NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
1294                                 })
1295                                 .fail(function() {
1296                                         NETDATA.error(100, NETDATA.raphael_js);
1297                                 })
1298                                 .always(function() {
1299                                         if(typeof callback == "function")
1300                                                 callback();
1301                                 })
1302                 }
1303                 else {
1304                         NETDATA.chartLibraries.raphael.enabled = false;
1305                         if(typeof callback == "function")
1306                                 callback();
1307                 }
1308         };
1309
1310         NETDATA.raphaelChartUpdate = function(element, data) {
1311                 var self = $(element);
1312
1313                 self.raphael(data, {
1314                         width: self.data('calculated-width'),
1315                         height: self.data('calculated-height')
1316                 })
1317         };
1318
1319         NETDATA.raphaelChartCreate = function(element, data) {
1320                 var self = $(element);
1321
1322                 self.raphael(data, {
1323                         width: self.data('calculated-width'),
1324                         height: self.data('calculated-height')
1325                 })
1326                 .data('chart-created', true);
1327         };
1328
1329         // ----------------------------------------------------------------------------------------------------------------
1330         // google charts
1331
1332         NETDATA.googleInitialize = function(callback) {
1333                 if(typeof netdataStopGoogleCharts == 'undefined') {
1334                         $.getScript(NETDATA.google_js)
1335                                 .done(function() {
1336                                         NETDATA.registerChartLibrary('google', NETDATA.google_js);
1337
1338                                         google.load('visualization', '1.1', {
1339                                                 'packages': ['corechart', 'controls'],
1340                                                 'callback': callback
1341                                         });
1342                                 })
1343                                 .fail(function() {
1344                                         NETDATA.error(100, NETDATA.google_js);
1345                                         if(typeof callback == "function")
1346                                                 callback();
1347                                 })
1348                 }
1349                 else {
1350                         NETDATA.chartLibraries.google.enabled = false;
1351                         if(typeof callback == "function")
1352                                 callback();
1353                 }
1354         };
1355
1356         NETDATA.googleChartUpdate = function(element, data) {
1357                 var self = $(element);
1358                 var gchart = self.data('google-instance');
1359                 var options = self.data('google-options');
1360
1361                 var datatable = new google.visualization.DataTable(data.result);
1362
1363                 gchart.draw(datatable, options);
1364         };
1365
1366         NETDATA.googleChartCreate = function(element, data) {
1367                 var self = $(element);
1368                 var chart = self.data('chart');
1369
1370                 var datatable = new google.visualization.DataTable(data.result);
1371                 var gchart;
1372
1373                 var options = {
1374                         // do not set width, height - the chart resizes itself
1375                         //width: self.data('calculated-width'),
1376                         //height: self.data('calculated-height'),
1377                         lineWidth: 1,
1378                         title: chart.title,
1379                         fontSize: 11,
1380                         hAxis: {
1381                         //      title: "Time of Day",
1382                         //      format:'HH:mm:ss',
1383                                 viewWindowMode: 'maximized',
1384                                 slantedText: false,
1385                                 format:'HH:mm:ss',
1386                                 textStyle: {
1387                                         fontSize: 9
1388                                 },
1389                                 gridlines: {
1390                                         color: '#EEE'
1391                                 }
1392                         },
1393                         vAxis: {
1394                                 title: chart.units,
1395                                 viewWindowMode: 'pretty',
1396                                 minValue: -0.1,
1397                                 maxValue: 0.1,
1398                                 direction: 1,
1399                                 textStyle: {
1400                                         fontSize: 9
1401                                 },
1402                                 gridlines: {
1403                                         color: '#EEE'
1404                                 }
1405                         },
1406                         chartArea: {
1407                                 width: '65%',
1408                                 height: '80%'
1409                         },
1410                         focusTarget: 'category',
1411                         annotation: {
1412                                 '1': {
1413                                         style: 'line'
1414                                 }
1415                         },
1416                         pointsVisible: 0,
1417                         titlePosition: 'out',
1418                         titleTextStyle: {
1419                                 fontSize: 11
1420                         },
1421                         tooltip: {
1422                                 isHtml: false,
1423                                 ignoreBounds: true,
1424                                 textStyle: {
1425                                         fontSize: 9
1426                                 }
1427                         },
1428                         curveType: 'function',
1429                         areaOpacity: 0.3,
1430                         isStacked: false
1431                 };
1432
1433                 var uuid = NETDATA.guid();
1434                 self.html('<div id="' + uuid + '" style="width: 100%; height: 100%;"></div>');
1435
1436                 switch(chart.chart_type) {
1437                         case "area":
1438                                 options.vAxis.viewWindowMode = 'maximized';
1439                                 gchart = new google.visualization.AreaChart(document.getElementById(uuid));
1440                                 break;
1441
1442                         case "stacked":
1443                                 options.isStacked = true;
1444                                 options.areaOpacity = 0.85;
1445                                 options.vAxis.viewWindowMode = 'maximized';
1446                                 options.vAxis.minValue = null;
1447                                 options.vAxis.maxValue = null;
1448                                 gchart = new google.visualization.AreaChart(document.getElementById(uuid));
1449                                 break;
1450
1451                         default:
1452                         case "line":
1453                                 options.lineWidth = 2;
1454                                 gchart = new google.visualization.LineChart(document.getElementById(uuid));
1455                                 break;
1456                 }
1457
1458                 gchart.draw(datatable, options);
1459
1460                 self.data('google-instance', gchart)
1461                         .data('google-options', options)
1462                         .data('uuid', uuid)
1463                         .data('chart-created', true);
1464         };
1465
1466         // ----------------------------------------------------------------------------------------------------------------
1467         // Charts Libraries Registration
1468
1469         NETDATA.chartLibraries = {
1470                 "dygraph": {
1471                         initialize: NETDATA.dygraphInitialize,
1472                         create: NETDATA.dygraphChartCreate,
1473                         update: NETDATA.dygraphChartUpdate,
1474                         initialized: false,
1475                         enabled: true,
1476                         format: 'json',
1477                         options: 'ms|flip',
1478                         jsonWrapper: true,
1479                         pixels_per_point: 2,
1480                         detects_dimensions_on_update: false
1481                 },
1482                 "sparkline": {
1483                         initialize: NETDATA.sparklineInitialize,
1484                         create: NETDATA.sparklineChartCreate,
1485                         update: NETDATA.sparklineChartUpdate,
1486                         initialized: false,
1487                         enabled: true,
1488                         format: 'array',
1489                         options: 'flip|abs',
1490                         jsonWrapper: true,
1491                         pixels_per_point: 2,
1492                         detects_dimensions_on_update: false
1493                 },
1494                 "peity": {
1495                         initialize: NETDATA.peityInitialize,
1496                         create: NETDATA.peityChartCreate,
1497                         update: NETDATA.peityChartUpdate,
1498                         initialized: false,
1499                         enabled: true,
1500                         format: 'ssvcomma',
1501                         options: 'null2zero|flip|abs',
1502                         jsonWrapper: true,
1503                         pixels_per_point: 2,
1504                         detects_dimensions_on_update: false
1505                 },
1506                 "morris": {
1507                         initialize: NETDATA.morrisInitialize,
1508                         create: NETDATA.morrisChartCreate,
1509                         update: NETDATA.morrisChartUpdate,
1510                         initialized: false,
1511                         enabled: true,
1512                         format: 'json',
1513                         options: 'objectrows|ms',
1514                         jsonWrapper: true,
1515                         pixels_per_point: 10,
1516                         detects_dimensions_on_update: false
1517                 },
1518                 "google": {
1519                         initialize: NETDATA.googleInitialize,
1520                         create: NETDATA.googleChartCreate,
1521                         update: NETDATA.googleChartUpdate,
1522                         initialized: false,
1523                         enabled: true,
1524                         format: 'datatable',
1525                         options: '',
1526                         jsonWrapper: true,
1527                         pixels_per_point: 2,
1528                         detects_dimensions_on_update: true
1529                 },
1530                 "raphael": {
1531                         initialize: NETDATA.raphaelInitialize,
1532                         create: NETDATA.raphaelChartCreate,
1533                         update: NETDATA.raphaelChartUpdate,
1534                         initialized: false,
1535                         enabled: true,
1536                         format: 'json',
1537                         options: '',
1538                         jsonWrapper: false,
1539                         pixels_per_point: 1,
1540                         detects_dimensions_on_update: false
1541                 }
1542         };
1543
1544         NETDATA.registerChartLibrary = function(library, url) {
1545                 console.log("registering chart library: " + library);
1546
1547                 NETDATA.chartLibraries[library].url = url;
1548                 NETDATA.chartLibraries[library].initialized = true;
1549                 NETDATA.chartLibraries[library].enabled = true;
1550
1551                 console.log(NETDATA.chartLibraries);
1552         }
1553
1554         // ----------------------------------------------------------------------------------------------------------------
1555         // load all libraries and initialize
1556
1557         NETDATA.errorReset();
1558
1559         NETDATA._loadjQuery(function() {
1560                 $.getScript(NETDATA.serverDefault + 'lib/visible.js').then(function() {
1561                         NETDATA.init();
1562                 })
1563         });
1564
1565 })(window);