]> arthur.barton.de Git - netdata.git/blob - web/index.html
zoomed mode improvements - it still needs some work
[netdata.git] / web / index.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5     <meta charset="utf-8">
6     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
7     <meta name="viewport" content="width=device-width, initial-scale=1">
8     <meta name="apple-mobile-web-app-capable" content="yes">
9     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
10     <meta name="description" content="">
11     <meta name="author" content="costa@tsaousis.gr">
12  
13         <title>NetData</title>
14
15         <!-- Google AJAX API -->
16         <script type="text/javascript" src="https://www.google.com/jsapi"></script>
17         <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
18
19         <!-- Bootstrap -->
20         <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
21         <!-- <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css"> -->
22         <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
23         <link href="/file/theme.css" rel="stylesheet">
24
25         <!-- NetData -->
26         <script type="text/javascript" src="/file/netdata.js"></script>
27         <script type="text/javascript" src="/file/jquery.visible.js"></script>
28         <script type="text/javascript">
29         
30         // Set a callback to run when the Google Visualization API is loaded.
31         google.setOnLoadCallback(initCharts);
32         
33         var TARGET_THUMB_GRAPH_WIDTH = 500; // chart width will range from 0.5 to 1.5 of that
34         var MINIMUM_THUMB_GRAPH_WIDTH = 400; // chart will generally try to be wider than that
35         var TARGET_THUMB_GRAPH_HEIGHT = 220;
36         var MAINCHART_MAX_TIME_TO_SHOW = 600;
37         var THUMBS_MAX_TIME_TO_SHOW = 600;
38         var MAINCHART_CONTROL_HEIGHT = 100;
39         var MAINCHART_CONTROL_DIVISOR = 1;
40         var MAINCHART_POINTS_DIVISOR = 5;
41
42         var MODE_THUMBS = 1;
43         var MODE_MAIN = 2;
44         var MODE_GROUP_THUMBS = 3;
45         var mode; // one of the MODE_* values
46
47         var mycharts = new Array();
48         var mainchart;
49
50         // html for the main menu
51         var mainmenu = "";
52
53
54         // ------------------------------------------------------------------------
55         // common HTML generation
56
57         function chartIsLoadingHTML(width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading chart<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
58
59         function showChartIsLoading(id, width, height) {
60                 //mylog('adding loading chart html in div with id ' + id);
61                 document.getElementById(id).innerHTML = chartIsLoadingHTML(width, height);
62         }
63
64         function thumbChartActions(i, c, nogroup) {
65                 var name = c.name;
66                 if(!nogroup) name = c.group_tag;
67
68                 var refinfo = "the chart is drawing ";
69                 if(c.group == 1) refinfo += "every single point collected.";
70                 else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";
71
72                 var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" title=\"" + refinfo + "\">"
73                 +               "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"
74                 +       "</div>"
75                 +       "<div class=\"btn-group btn-group\"><button type=\"button\" class=\"btn btn-default disabled\"><small>&nbsp;&nbsp; " + name + "</small></button>";
76
77                 if(!nogroup) {
78                         var ingroup = 0;
79                         var ingroup_detail = 0;
80
81                         $.each(mycharts, function(i, d) {
82                                 if(d.group_tag == c.group_tag) {
83                                         ingroup++;
84                                         if(d.isdetail) ingroup_detail++;
85                                 }
86                         });
87
88                         var hidden = "";
89                         if(ingroup_detail) hidden = ", including " + ingroup_detail + " charts not shown now";
90
91                         html += "<button type=\"button\" data-toggle=\"tooltip\" title=\"Show all " + ingroup + " charts in group '" + c.group_tag + "'" + hidden + "\" class=\"btn btn-default\" onclick=\"initGroupGraphs('" + c.group_tag +"');\"><span class=\"glyphicon glyphicon-th-large\"></span></button>";
92                 }
93
94                 html += "<button type=\"button\" data-toggle=\"tooltip\" title=\"show chart '" + c.name + "' in fullscreen\" class=\"btn btn-default\" onclick=\"initMainChartIndex(" + i +");\"><span class=\"glyphicon glyphicon-resize-full\"></span></button>"
95                 +               "<button type=\"button\" data-toggle=\"tooltip\" title=\"set options for chart '" + c.name + "'\" class=\"btn btn-default disabled\" onclick=\"alert('Not implemented yet!');\"><span class=\"glyphicon glyphicon-cog\"></span></button>"
96                 +               "<button type=\"button\" data-toggle=\"tooltip\" title=\"ignore chart '" + c.name + "'\" class=\"btn btn-default\" onclick=\"disableChart(" + i + ");\"><span class=\"glyphicon glyphicon-trash\"></span></button>"
97                 +       "</div>";
98
99                 return html;
100         }
101
102         function mylog(txt) {
103                 console.log(txt);
104         }
105
106         function chartssort(a, b) {
107                 if(a.userpriority < b.userpriority) return -1;
108                 return 1;
109         }
110
111
112         // ------------------------------------------------------------------------
113         // MAINGRAPH = fullscreen view of 1 graph
114
115         function calculateChartGroup(c, divisor, maxtime, group) {
116                 var before = c.before?c.before:new Date().getTime() / 1000;
117                 var after = c.after?c.after:c.first_entry_t;
118
119                 var dt = before - after;
120                 if(dt > c.entries * c.update_every) dt = c.entries * c.update_every;
121
122                 if(maxtime && dt > maxtime) dt = maxtime;
123
124                 var data_points = dt / c.update_every;
125                 var screen_points = Math.round(c.chartOptions.width / divisor);
126
127                 if(!group) {
128                         if(screen_points > data_points) {
129                                 c.group = 1;
130                                 c.points_to_show = data_points;
131                         }
132                         else {
133                                 c.group = Math.round(data_points / screen_points);
134
135                                      if(c.group > 60) c.group = 60;
136                                 else if(c.group > 45) c.group = 45;
137                                 else if(c.group > 30) c.group = 30;
138                                 else if(c.group > 20) c.group = 20;
139                                 else if(c.group > 15) c.group = 15;
140                                 else if(c.group > 10) c.group = 10;
141                                 else if(c.group > 5) c.group = 5;
142                                 else if(c.group > 2) c.group = 2;
143                                 else c.group = 1;
144
145                                 c.points_to_show = Math.round(data_points / c.group);
146                         }
147                 }
148                 else {
149                         c.group = group;
150                         c.points_to_show = Math.round(data_points / group);
151                 }
152
153                 if(mainchart.chartType == 'LineChart') {
154                         if(mainchart.group <= 2) mainchart.chartOptions.lineWidth = 1;
155                         else mainchart.chartOptions.lineWidth = 2;
156                 }
157         }
158
159         // copy the chart c to mainchart
160         // switch to main graphs screen
161         function initMainChart(c) {
162                 if(mainchart) cleanThisChart(mainchart);
163
164                 mainchart = $.extend(true, {}, c);
165                 var tempchart = $.extend(true, {}, mainchart);
166
167                 mainchart.chart = null;
168                 mainchart.chartOptions.width = screenWidth();
169                 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
170                 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
171
172                 mainchart.div = 'maingraph';
173                 mainchart.last_updated = 0;
174
175                 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
176                 mainchart.chartOptions.explorer = null;
177
178                 // initialize the div
179                 showChartIsLoading(mainchart.div, mainchart.chartOptions.width, mainchart.chartOptions.height);
180
181                 // set the radio buttons
182                 setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
183                 setMainChartMax('normal');
184
185                 $('#group' + mainchart.group).trigger('click');
186                 setMainChartGroup(mainchart.group, 'no-refresh');
187
188                 var controlopts = $.extend(true, {}, mainchart.chartOptions, {
189                         lineWidth: 1,
190                         height: MAINCHART_CONTROL_HEIGHT,
191                         chartArea: {'width': '90%'},
192                         hAxis: {'baselineColor': 'none'},
193                         vAxis: {'title': null},
194                 });
195
196                 mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
197                 mainchart.control = new google.visualization.ControlWrapper({
198                         controlType: 'ChartRangeFilter',
199                         containerId: 'maingraph_control',
200                         options: {
201                                 filterColumnIndex: 0,
202                                 ui: {
203                                         chartType: mainchart.chartType,
204                                         chartOptions: controlopts,
205                                         minRangeSize: MAINCHART_MAX_TIME_TO_SHOW * mainchart.update_every / MAINCHART_POINTS_DIVISOR * 1000,
206                                 }
207                         },
208                 });
209                 mainchart.hiddenchart = new google.visualization.ChartWrapper({
210                         chartType: mainchart.chartType,
211                         containerId: 'maingraph_hidden',
212                         options: {
213                                 isStacked: mainchart.chartOptions.isStacked,
214                                 width: mainchart.chartOptions.width,
215                                 height: mainchart.chartOptions.height,
216                                 //chartArea: {'height': '80%', 'width': '100%'},
217                                 //hAxis: {'slantedText': false},
218                                 //legend: {'position': 'none'}
219                         },
220                 });
221
222                 // load the data for the control and the hidden chart
223                 calculateChartGroup(tempchart, MAINCHART_CONTROL_DIVISOR, 0, 0);
224                 // alert("diff = " + (tempchart.before - tempchart.after) + ", group = " + tempchart.group);
225
226                 switchToMainGraph();
227
228                 $.ajax({
229                         url: generateChartURL(tempchart),
230                         dataType:"json",
231                         cache: false
232                 })
233                 .done(function(jsondata) {
234                         if(!jsondata || jsondata.length == 0) return;
235
236                         mainchart.control_data = new google.visualization.DataTable(jsondata);
237
238                         google.visualization.events.addListener(mainchart.control, 'ready', mainchartControlReadyEvent);
239                         mainchart.dashboard.bind(mainchart.control, mainchart.hiddenchart);
240                         mainchart.dashboard.draw(mainchart.control_data);
241                 });
242         }
243
244         function mainchartControlReadyEvent() {
245                 google.visualization.events.addListener(mainchart.control, 'statechange', mainchartControlStateHandler);
246         }
247
248         function mainchartControlStateHandler() {
249                 // setMainChartPlay('pause');
250
251                 var state = mainchart.control.getState();
252                 mainchart.after = Math.round(state.range.start.getTime() / 1000);
253                 mainchart.before = Math.round(state.range.end.getTime() / 1000);
254
255                 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, 0);
256                 console.log('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
257
258                 $('#group' + mainchart.group).trigger('click');
259                 mainchart.last_updated = 0;
260
261                 if(refresh_mode != REFRESH_ZOOMED) zoomGraphs();
262         }
263
264         function initMainChartIndex(i) {
265                 if(mode == MODE_GROUP_THUMBS) 
266                         initMainChart(group_charts[i]);
267
268                 else if(mode == MODE_THUMBS)
269                         initMainChart(mycharts[i]);
270         }
271
272         var last_main_chart_max='normal';
273         function setMainChartMax(m) {
274                 if(!mainchart) return;
275
276                 if(m == 'toggle') {
277                         if(last_main_chart_max == 'maximized') m = 'normal';
278                         else m = 'maximized';
279                 }
280
281                 if(m == "maximized") {
282                         mainchart.chartOptions.theme = 'maximized';
283                         //mainchart.chartOptions.axisTitlesPosition = 'in';
284                         //mainchart.chartOptions.legend = {position: 'none'};
285                         //mainchart.chartOptions.hAxis.title = null;
286                         mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';
287                         mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';
288                 }
289                 else {
290                         mainchart.chartOptions.theme = null;
291                         mainchart.chartOptions.hAxis.viewWindowMode = null;
292                         mainchart.chartOptions.vAxis.viewWindowMode = null;
293                 }
294                 $('.mainchart_max_button').button(m);
295                 last_main_chart_max = m;
296                 mainchart.last_updated = 0;
297         }
298
299         function setMainChartGroup(g, norefresh) {
300                 if(!mainchart) return;
301
302                 mainchart.group = g;
303
304                 if(!mainchart.before && !mainchart.after)
305                         calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, mainchart.group);
306                 else
307                         calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, mainchart.group);
308
309                 if(!norefresh) {
310                         mainchart.last_updated = 0;
311                         if(refresh_mode == REFRESH_PAUSED) playGraphs();
312                 }
313         }
314
315         var last_main_chart_avg = null;
316         function setMainChartGroupMethod(g, norefresh) {
317                 if(!mainchart) return;
318
319                 if(g == 'toggle') {
320                         if(last_main_chart_avg == 'max') g = 'average';
321                         else g = 'max';
322                 }
323
324                 mainchart.group_method = g;
325
326                 $('.mainchart_avg_button').button(g);
327
328                 if(!norefresh) {
329                         mainchart.last_updated = 0;
330                         if(refresh_mode == REFRESH_PAUSED) playGraphs();
331                 }
332
333                 last_main_chart_avg = g;
334         }
335
336         function setMainChartPlay(p) {
337                 if(!mainchart) return;
338
339                 if(p == 'toggle') {
340                         if(refresh_mode != REFRESH_ALWAYS) p = 'play';
341                         else p = 'pause';
342                 }
343
344                 if(p == 'play') {
345                         //mainchart.chartOptions.explorer = null;
346                         mainchart.after = 0;
347                         mainchart.before = 0;
348                         calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
349                         $('#group' + mainchart.group).trigger('click');
350                         mainchart.last_updated = 0;
351                         playGraphs();
352                 }
353                 else {
354                         //mainchart.chartOptions.explorer = {
355                         //      'axis': 'horizontal',
356                         //      'maxZoomOut': 1,
357                         //};
358                         //mainchart.last_updated = 0;
359                         
360                         //if(!refreshChart(mainchart, pauseGraphs))
361                         pauseGraphs();
362                 }
363         }
364
365
366         // ------------------------------------------------------------------------
367         // Chart resizing
368
369         function screenWidth() {
370                 return (($(window).width() * 0.95) - 50);
371         }
372
373         // calculate the proper width for the thumb charts
374         function thumbWidth() {
375                 var cwidth = screenWidth();
376                 var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
377                 if(items < 1) items = 1;
378
379                 if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
380
381                 return Math.round(cwidth / items) - 1;
382         }
383
384         function groupChartSizes() {
385                 var s = { width: screenWidth() / 2, height: ($(window).height() - 130) / 3 - 10};
386                 if(s.width < MINIMUM_THUMB_GRAPH_WIDTH * 1.5) s.width = screenWidth();
387
388                 var count = 0;
389                 if(group_charts) $.each(group_charts, function(i, c) {
390                         if(c.enabled) count++;
391                 });
392
393                 if(count == 0) {
394                         s.width = TARGET_THUMB_GRAPH_WIDTH;
395                         s.height = TARGET_THUMB_GRAPH_HEIGHT;
396                 }
397                 if(count < 4) {
398                         s.width = screenWidth();
399                         s.height = ($(window).height() - 130) / count - 10;
400                 }
401                 else if(count == 4) {
402                         s.height = ($(window).height() - 130) / 2 - 10;
403                 }
404
405                 if(s.height < TARGET_THUMB_GRAPH_HEIGHT * 1.5)
406                         s.height = TARGET_THUMB_GRAPH_HEIGHT * 1.5;
407
408                 return s;
409         }
410
411         // resize all charts
412         // if the thumb charts need resize in their width, reset them
413         function resizeCharts() {
414                 var width = screenWidth();
415
416                 if(mainchart) {
417                         mainchart.chartOptions.width = width;
418                         mainchart.chartOptions.height = $(window).height() - 200;
419                         mainchart.last_updated = 0;
420                 }
421
422                 width = thumbWidth();
423                 $.each(mycharts, function(i, c) {
424                         if(c.enabled && c.chartOptions.width != width) {
425                                 cleanThisChart(c);
426                                 c.chartOptions.width = width;
427                                 showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
428                                 c.last_updated = 0;
429                         }
430                 });
431
432                 if(group_charts) $.each(group_charts, function(i, c) {
433                         var sizes = groupChartSizes();
434
435                         if(c.enabled && (c.chartOptions.width != sizes.width || c.chartOptions.height != sizes.height)) {
436                                 cleanThisChart(c);
437                                 c.chartOptions.width = sizes.width;
438                                 c.chartOptions.height = sizes.height;
439                                 showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
440                                 c.last_updated = 0;
441                         }
442                 });
443         }
444
445         var resize_request = false;
446         window.onresize = function(event) {
447                 resize_request = true;
448         };
449
450
451         // ------------------------------------------------------------------------
452         // Core of the thread refreshing the charts
453
454         var REFRESH_PAUSED = 0;
455         var REFRESH_ALWAYS = 1;
456         var REFRESH_ZOOMED = 2;
457
458         var refresh_mode = REFRESH_PAUSED;
459         var last_refresh = 0;
460         function playGraphs() {
461                 if(refresh_mode != REFRESH_PAUSED) {
462                         // check if the thread died due to a javascript error
463                         var now = new Date().getTime();
464                         if((now - last_refresh) > 5000) {
465                                 // it died!
466                                 //mylog('It seems the refresh thread died. Restarting it.');
467                                 chartsRefresh();
468                         }
469                         return;
470                 }
471
472                 refresh_mode = REFRESH_ALWAYS;
473                 $('.mainchart_play_button').button('play');
474                 chartsRefresh();
475         }
476
477         function pauseGraphs() {
478                 if(refresh_mode == REFRESH_PAUSED) return;
479
480                 refresh_mode = REFRESH_PAUSED;
481                 $('.mainchart_play_button').button('pause');
482         }
483
484         function zoomGraphs() {
485                 if(refresh_mode == REFRESH_ZOOMED) return;
486
487                 refresh_mode = REFRESH_ZOOMED;
488                 $('.mainchart_play_button').button('pause');
489         }
490
491         // refresh the proper chart
492         // this is an internal function.
493         // never call it directly, or new javascript threads will be spawn
494         var timeout;
495         var refresh_count = 0;
496         function chartsRefresh() {
497                 refresh_count++;
498
499                 if(resize_request) {
500                         resizeCharts();
501                         resize_request = false;
502                         refresh_mode = REFRESH_ALWAYS;
503                 }
504
505                 if(refresh_mode == REFRESH_PAUSED) {
506                         //mylog("stop refresh");
507                         return;
508                 }
509
510                 last_refresh = new Date().getTime();
511
512                      if(mode == MODE_THUMBS)            thumbChartsRefresh();
513                 else if(mode == MODE_GROUP_THUMBS)  groupChartsRefresh();
514                 else if(mode == MODE_MAIN)              mainChartRefresh();
515                 else                                    timeout = setTimeout(triggerRefresh, 500);
516         }
517
518         // callback for refreshing the charts later
519         // this is an internal function.
520         // never call it directly, or new javascript threads will be spawn
521         function triggerRefresh() {
522                 //mylog('triggerRefresh(' + refresh_count + ')');
523
524                 // cleanup has to take place when the charts are not refreshed
525                 // since the refreshing thread is in this function, it means
526                 // nothing is being refreshed.
527                 cleanupCharts();
528
529                      if(mode == MODE_THUMBS)            timeout = setTimeout(chartsRefresh, 200);
530                 else if(mode == MODE_GROUP_THUMBS)      timeout = setTimeout(chartsRefresh, 200);
531                 else if(mode == MODE_MAIN)              timeout = setTimeout(chartsRefresh, 200);
532                 else                                    timeout = setTimeout(triggerRefresh, 500);
533         }
534
535         // refresh the main chart
536         // make sure we don't loose the refreshing thread
537         function mainChartRefresh() {
538                 //mylog('mainChartRefresh()');
539
540                 if(mode != MODE_MAIN || !mainchart) {
541                         triggerRefresh();
542                         return;
543                 }
544
545                 if(!refreshChart(mainchart, triggerRefresh))
546                         triggerRefresh();
547         }
548
549         function roundRobinRefresh(charts, startat) {
550                 var refreshed = false;
551
552                 // find a chart to refresh
553                 var all = charts.length;
554                 var cur = startat;
555                 var count = 0;
556
557                 for(count = 0; count < all ; count++, cur++) {
558                         if(cur >= all) cur = 0;
559
560                         if(charts[cur].enabled) {
561                                 //mylog('going to refresh chart ' + charts[cur].name);
562                                 refreshed = refreshChart(charts[cur], chartsRefresh);
563                                 if(refreshed) break;
564                         }
565                 }
566
567                 if(!refreshed) triggerRefresh();
568                 return cur;
569         }
570
571         // refresh the thumb charts
572         // make sure we don't loose the refreshing thread
573         var last_thumb_updated = 0;
574         function thumbChartsRefresh() {
575                 //mylog('thumbChartsRefresh()');
576
577                 if(mycharts.length == 0 || mode != MODE_THUMBS) {
578                         triggerRefresh();
579                         return;
580                 }
581
582                 last_thumb_updated = roundRobinRefresh(mycharts, last_thumb_updated);
583         }
584
585         // refresh the group charts
586         // make sure we don't loose the refreshing thread
587         var last_group_updated = 0;
588         function groupChartsRefresh() {
589                 //mylog('groupChartsRefresh()');
590
591                 if(!group_charts || group_charts.length == 0 || mode != MODE_GROUP_THUMBS) {
592                         //mylog('cannot refresh charts');
593                         triggerRefresh();
594                         return;
595                 }
596
597                 last_group_updated = roundRobinRefresh(group_charts, last_group_updated);
598         }
599
600
601         // ------------------------------------------------------------------------
602         // switch the screen between views
603         // these should be called only from initXXXX()
604
605         function disableChart(i) {
606                 //mylog('disableChart(' + i + ')');
607
608                 var chart = null;
609
610                 var count = 0;
611                 if(mode == MODE_GROUP_THUMBS && group_charts) {
612                         $.each(group_charts, function(i, c) {
613                                 if(c.enabled) count++;
614                         });
615
616                         if(i < group_charts.length) chart = group_charts[i];
617                 }
618                 else if(mode == MODE_THUMBS) {
619                         $.each(mycharts, function(i, c) {
620                                 if(c.enabled) count++;
621                         });
622
623                         if(i < mycharts.length) chart = mycharts[i];
624                 }
625
626                 if(!chart) return;
627
628                 if(count <= 1) {
629                         alert('Cannot close the last chart shown.');
630                         return;
631                 }
632
633                 if(chart) {
634                         //mylog("disabling chart " + chart.name);
635                         chart.disablethisplease = true;
636                 }
637         }
638
639         function cleanThisChart(chart, emptydivs) {
640                 //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');
641
642                 if(chart.chart) chart.chart.clearChart();
643                 chart.chart = null;
644
645                 if(emptydivs) {
646                         var div = document.getElementById(chart.div);
647                         if(div) {
648                                 div.style.display = 'none';
649                                 div.innerHTML = "";
650                         }
651
652                         div = document.getElementById(chart.div + "_parent");
653                         if(div) {
654                                 div.style.display = 'none';
655                                 div.innerHTML = "";
656                         }
657                 }
658
659                 //mylog("chart " + chart.name + " cleaned with option " + emptydivs);
660         }
661
662         // cleanup the previously shown charts
663         function cleanupCharts() {
664                 //mylog('cleanupCharts()');
665
666                 if(mode != MODE_MAIN && mainchart) {
667                         if(mainchart.chart) cleanThisChart(mainchart);
668                         mainchart = null;
669                 }
670
671                 if(mode != MODE_GROUP_THUMBS && group_charts) {
672                         clearGroupGraphs();
673                 }
674
675                 // cleanup the disabled charts
676                 $.each(mycharts, function(i, c) {
677                         if(c.disablethisplease && c.enabled) {
678                                 cleanThisChart(c, 'emptydivs');
679                                 c.disablethisplease = false;
680                                 c.enabled = false;
681                                 resize_request = true;
682                                 //mylog("disabled chart " + c.name + " removed");
683                         }
684                 });
685
686                 if(group_charts) $.each(group_charts, function(i, c) {
687                         if(c.disablethisplease && c.enabled) {
688                                 cleanThisChart(c, 'emptydivs');
689                                 c.disablethisplease = false;
690                                 c.enabled = false;
691                                 resize_request = true;
692                                 //mylog("disabled chart " + c.name + " removed");
693                         }
694                 });
695
696                 // we never cleanup the thumb charts
697         }
698
699         function updateUI() {
700                 $('[data-toggle="tooltip"]').tooltip({'placement': 'top', 'container': 'body', 'html': true});
701
702                 $('[data-spy="scroll"]').each(function () {
703                         var $spy = $(this).scrollspy('refresh')
704                 })
705         }
706
707         var thumbsScrollPosition = null;
708         function switchToMainGraph() {
709                 //mylog('switchToMainGraph()');
710
711                 if(!mainchart) return;
712
713                 if(!group_charts) thumbsScrollPosition = window.pageYOffset;
714
715                 document.getElementById('maingraph_container').style.display = 'block';
716                 document.getElementById('thumbgraphs_container').style.display = 'none';
717                 document.getElementById('groupgraphs_container').style.display = 'none';
718
719                 document.getElementById("main_menu_div").innerHTML = "<ul class=\"nav navbar-nav\"><li><a href=\"javascript:switchToThumbGraphs();\">Back to Home</a></li><li class=\"active\"><a href=\"#\">" + mainchart.title + "</a></li></ul>";
720
721                 window.scrollTo(0, 0);
722
723                 mode = MODE_MAIN;
724                 playGraphs();
725                 updateUI();
726         }
727
728         function switchToThumbGraphs() {
729                 //mylog('switchToThumbGraphs()');
730
731                 document.getElementById('maingraph_container').style.display = 'none';
732                 document.getElementById('thumbgraphs_container').style.display = 'block';
733                 document.getElementById('groupgraphs_container').style.display = 'none';
734
735                 document.getElementById("main_menu_div").innerHTML = mainmenu;
736
737                 if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);
738
739                 // switch mode
740                 mode = MODE_THUMBS;
741                 playGraphs();
742                 updateUI();
743         }
744
745         function switchToGroupGraphs() {
746                 //mylog('switchToGroupGraphs()');
747
748                 if(!group_charts) return;
749
750                 if(!mainchart) thumbsScrollPosition = window.pageYOffset;
751
752                 document.getElementById('maingraph_container').style.display = 'none';
753                 document.getElementById('thumbgraphs_container').style.display = 'none';
754                 document.getElementById('groupgraphs_container').style.display = 'block';
755
756                 document.getElementById("main_menu_div").innerHTML = "<ul class=\"nav navbar-nav\"><li><a href=\"javascript:switchToThumbGraphs();\">Back to Home</a></li><li class=\"active\"><a href=\"#\">" + group_charts[0].group_tag + " charts</a></li></ul>";
757
758                 window.scrollTo(0, 0);
759
760                 mode = MODE_GROUP_THUMBS;
761                 playGraphs();
762                 updateUI();
763         }
764
765
766         // ------------------------------------------------------------------------
767         // Group Charts
768
769         var group_charts = null;
770         function initGroupGraphs(group) {
771                 var count = 0;
772                 
773                 if(group_charts) clearGroupGraphs();
774                 group_charts = new Array();
775
776                 var groupbody = "";
777                 $.each(mycharts, function(i, c) {
778                         if(c.group_tag == group) {
779                                 group_charts[count] = [];
780                                 group_charts[count] = $.extend(true, {}, c);
781                                 group_charts[count].div += "_group";
782                                 group_charts[count].enabled = true;
783                                 group_charts[count].chart = null;
784                                 group_charts[count].last_updated = 0;
785                                 count++;
786                         }
787                 });
788                 group_charts.sort(chartssort);
789
790                 var sizes = groupChartSizes();
791
792                 var groupbody = "";
793                 $.each(group_charts, function(i, c) {
794                         c.chartOptions.width = sizes.width;
795                         c.chartOptions.height = sizes.height;
796
797                         groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">" + thumbChartActions(i, c, 'nogroup') + "</td></tr></table></div>";
798                 });
799                 groupbody += "";
800
801                 document.getElementById("groupgraphs").innerHTML = groupbody;
802                 switchToGroupGraphs();
803         }
804
805         function clearGroupGraphs() {
806                 if(group_charts && group_charts.length) {
807                         $.each(group_charts, function(i, c) {
808                                 cleanThisChart(c, 'emptydivs');
809                         });
810
811                         group_charts = null;
812                 }
813
814                 document.getElementById("groupgraphs").innerHTML = "";
815         }
816
817
818         // ------------------------------------------------------------------------
819         // Global entry point
820         // initialize the thumb charts
821
822         // load the charts from the server
823         // generate html for the thumbgraphs to support them
824         function initCharts() {
825                 var width = thumbWidth();
826                 var height = TARGET_THUMB_GRAPH_HEIGHT;
827
828                 loadCharts(null, function(c) {
829                         mycharts = c;
830
831                         if(mycharts == null || mycharts.length == 0) {
832                                 alert("Cannot load data from server.");
833                                 return;
834                         }
835
836                         var thumbsContainer = document.getElementById("thumbgraphs");
837                         if(!thumbsContainer) {
838                                 alert("Cannot find the thumbsContainer");
839                                 return;
840                         }
841
842                         mycharts.sort(chartssort);
843
844                         document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;
845                         document.title = mycharts[0].hostname;
846
847                         // create an array for grouping all same-type graphs together
848                         var categories = new Array();
849                         $.each(mycharts, function(i, c) {
850                                 c.chartOptions.width = width;
851                                 c.chartOptions.height = height;
852
853                                 // calculate how many point to show for each chart
854                                 c.points_to_show = Math.round(c.entries / c.group) - 1;
855
856                                 // show max 10 mins of data
857                                 if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;
858
859                                 if(c.enabled) {
860                                         var j;
861                                         var h = "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">"
862                                         + thumbChartActions(i, c)
863                                         +       "</td></tr></table></div>";
864
865                                         // find the categories object for this type
866                                         for(j = 0; j < categories.length ;j++) {
867                                                 if(categories[j].name == c.type) {
868                                                         categories[j].html += h;
869                                                         categories[j].count++;
870                                                         break;
871                                                 }
872                                         }
873
874                                         if(j == categories.length) {
875                                                 categories.push({name: c.type, title: c.category, description: '', priority: 0, count: 1, glyphicon: c.glyphicon, html: h});
876                                         }
877                                 }
878                         });
879
880                         $.each(categories, function(i, a) {
881                                      if(a.name == "system") a.priority = 1;
882                                 else if(a.name == "net") a.priority = 2;
883                                 else if(a.name == "tc") a.priority = 3;
884                                 else if(a.name == "conntrack") a.priority = 4;
885                                 else if(a.name == "ipvs") a.priority = 5;
886                                 else if(a.name == "ipv4") a.priority = 6;
887                                 else if(a.name == "cpu") a.priority = 7;
888                                 else if(a.name == "mem") a.priority = 8;
889                                 else if(a.name == "disk") a.priority = 9;
890                                 else a.priority = 99;
891
892                                 a.html = "<tr><td id=\"" + a.name + "\"><ol class=\"breadcrumb graphs\"><li class=\"active\"><span class=\"glyphicon " + a.glyphicon + "\"></span> &nbsp; <a id=\"" + a.name + "\" href=\"#" + a.name + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";
893                         });
894
895                         function categoriessort(a, b) {
896                                 if(a.priority < b.priority) return -1;
897                                 return 1;
898                         }
899                         categories.sort(categoriessort);
900                         
901                         // combine all the htmls into one
902                         var allcategories = "<table width=\"100%\">";
903                         mainmenu = "<ul class=\"nav navbar-nav\"><li><a href=\"#\">Home</a></li>";
904                         $.each(categories, function(i, a) {
905                                 allcategories += a.html;
906                                 mainmenu += "<li><a href=\"#" + a.name + "\">" + a.title + "</a></li>";
907                         });
908                         allcategories += "</table>";
909                         mainmenu += "</ul>";
910
911                         thumbsContainer.innerHTML = allcategories;
912                         switchToThumbGraphs();
913                 });
914         }
915
916         </script>
917 </head>
918
919 <body role="document" data-spy="scroll" data-target="#main_menu_div">
920     <nav id="mynav" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
921       <div class="container">
922         <div class="navbar-header">
923           <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main_menu_div">
924             <span class="sr-only">Toggle navigation</span>
925             <span class="icon-bar"></span>
926             <span class="icon-bar"></span>
927             <span class="icon-bar"></span>
928           </button>
929           <a class="navbar-brand" href="javascript:switchToThumbGraphs();" id="hostname_id">NetData</a>
930         </div>
931         <div class="collapse navbar-collapse" id="main_menu_div">
932           <ul class="nav navbar-nav">
933             <li><a href="#">Home</a></li>
934           </ul>
935         </div><!--/.nav-collapse -->
936       </div>
937     </nav>
938
939     <div class="container graphs" id="maingraph_container" style="display: none">
940                 <table>
941                         <tr><td>
942                         <div class="maingraph">
943                                         <table>
944                                                 <tr><td>
945                                                 <div class="maingraph" id="maingraph"></div>
946                                                 <div id="maingraph_dashboard">
947                                                         <div class="maingraph" id="maingraph_hidden" style="display: none"></div>
948                                                         <div class="maingraph" id="maingraph_control"></div>
949                                                 </div>
950                                                 </td></tr>
951                                                 <tr><td align="center">
952                                                         <div class="btn-group">
953                                                                 <form id="mainchartform">
954                                                                         <div class="btn-group btn-group" data-toggle="tooltip" title=" click <span class='glyphicon glyphicon-play'></span> to have the graph auto-refresh, or click <span class='glyphicon glyphicon-pause'></span> to pause the graph. When paused the graph can be zoomed and panned horizontally." >
955                                                                                 <button type="button" class="btn btn-primary mainchart_play_button" data-play-text="<span class='glyphicon glyphicon-pause'></span>" data-pause-text="<span class='glyphicon glyphicon-play'></span>" onClick="setMainChartPlay('toggle');">
956                                                                                         <span class="glyphicon glyphicon-pause"></span>
957                                                                                 </button>
958                                                                         </div>
959                                                                         <div class="btn-group btn-group" data-toggle="tooltip" title="use the maximum ( <span class='glyphicon glyphicon-signal'></span> ) or the average ( <span class='glyphicon glyphicon-align-justify'></span> ) value of grouped points" >
960                                                                                 <button type="button" class="btn btn-primary mainchart_avg_button" data-max-text="<span class='glyphicon glyphicon-signal'></span>" data-average-text="<span class='glyphicon glyphicon-align-justify'></span>" onClick="setMainChartGroupMethod('toggle');">
961                                                                                         <span class="glyphicon glyphicon-signal"></span>
962                                                                                 </button>
963                                                                         </div>
964 <!--                                                                    <div class="btn-group btn-group" data-toggle="buttons">
965                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="show the MAX point among all points grouped">
966                                                                                         <input type="radio" name="groupmethod" id="groupmax" onChange="setMainChartGroupMethod('max');">
967                                                                                         <span class="glyphicon glyphicon-signal"></span>
968                                                                                 </label>
969                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="show the AVERAGE of all points grouped">
970                                                                                         <input type="radio" name="groupmethod" id="groupaverage" onChange="setMainChartGroupMethod('average');">
971                                                                                         <span class="glyphicon glyphicon-align-justify"></span>
972                                                                                 </label>
973                                                                         </div>
974 -->                                                                     <div class="btn-group btn-group" data-toggle="buttons" >
975                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="do not group points, show the raw data">
976                                                                                         <input type="radio" name="group" id="group1" onChange="setMainChartGroup(1);">1
977                                                                                 </label>
978                                                                                 
979                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group in half, show 1 every 2 points of data">
980                                                                                         <input type="radio" name="group" id="group2" onChange="setMainChartGroup(2);">2
981                                                                                 </label>
982
983                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 5 points of data">
984                                                                                         <input type="radio" name="group" id="group5" onChange="setMainChartGroup(5);">5
985                                                                                 </label>
986                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 10 points of data">
987                                                                                         <input type="radio" name="group" id="group10" onChange="setMainChartGroup(10);">10
988                                                                                 </label>
989                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 15 points of data">
990                                                                                         <input type="radio" name="group" id="group15" onChange="setMainChartGroup(15);">15
991                                                                                 </label>
992                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 20 points of data">
993                                                                                         <input type="radio" name="group" id="group20" onChange="setMainChartGroup(20);">20
994                                                                                 </label>
995                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 30 points of data">
996                                                                                         <input type="radio" name="group" id="group30" onChange="setMainChartGroup(30);">30
997                                                                                 </label>
998                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 45 points of data">
999                                                                                         <input type="radio" name="group" id="group45" onChange="setMainChartGroup(45);">45
1000                                                                                 </label>
1001                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="group every 60 points of data">
1002                                                                                         <input type="radio" name="group" id="group60" onChange="setMainChartGroup(60);">60
1003                                                                                 </label>
1004                                                                         </div>
1005                                                                         <div class="btn-group btn-group" data-toggle="tooltip" title="maximized ( <span class='glyphicon glyphicon-fullscreen'></span> ) or normal ( <span class='glyphicon glyphicon-resize-small'></span> ) view of the graph" >
1006                                                                                 <button type="button" class="btn btn-primary mainchart_max_button" data-maximized-text="<span class='glyphicon glyphicon-resize-small'></span>" data-normal-text="<span class='glyphicon glyphicon-fullscreen'></span>" onClick="setMainChartMax('toggle');">
1007                                                                                         <span class="glyphicon glyphicon-fullscreen"></span>
1008                                                                                 </button>
1009                                                                         </div>
1010 <!--                                                                    <div class="btn-group btn-group" data-toggle="buttons" >
1011                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="NORMAL chart size">
1012                                                                                         <input type="radio" name="chartmax" id="chartnormal" onChange="setMainChartMax('normal');">
1013                                                                                         <span class="glyphicon glyphicon-resize-small"></span>
1014                                                                                 </label>
1015                                                                                 <label class="btn btn-primary" data-toggle="tooltip" title="MAXIMIZED chart size">
1016                                                                                         <input type="radio" name="chartmax" id="chartmax" onChange="setMainChartMax('maximized');">
1017                                                                                         <span class="glyphicon glyphicon-fullscreen"></span>
1018                                                                                 </label>
1019                                                                         </div>
1020 -->                                                             </form>
1021                                                         </div>
1022                                                         </td></tr>
1023                                         </table>
1024                            </div><!-- /.maingraph -->
1025                         </td></tr>
1026                 </table>
1027         </div>
1028
1029     <div class="container graphs" id="thumbgraphs_container">
1030         <div class="allgraphs" id="thumbgraphs">
1031                 <table width="100%">
1032                         <tr><td id="splash" align="center" style="vertical-align:middle">
1033                                 <h1>
1034                                 Welcome to <b>NetData</b>!
1035                                 <br/><br/>
1036                                 <span class="glyphicon glyphicon-off"></span>
1037                                 <br/><br/>
1038                                 loading charts
1039                                 <br/><br/>
1040                                 <span class="label label-default">Please wait...</span>
1041                                 </h1>
1042                         </td></tr>
1043                 </table>
1044         </div>
1045         </div>
1046
1047     <div class="container graphs" id="groupgraphs_container">
1048         <div class="allgraphs" id="groupgraphs">
1049         </div>
1050         </div>
1051
1052     <div class="container graphs" id="groupgraphs_container">
1053         &nbsp;<p/>
1054         <hr/>
1055     <h4>NetData</h4>
1056     Realtime System Information over the web for all linux systems.
1057     <p/>
1058     Distributed under GPL.
1059     <p/>
1060     (c) 2014 Costa Tsaousis <a href="mailto:costa@tsaousis.gr">costa@tsaousis.gr</a>
1061         </div>
1062
1063         <script type='text/javascript'>
1064                 google.load('visualization', '1.1', {packages: ['controls']});
1065
1066                 $(document).ready(function(){
1067                         document.getElementById('splash').height = $(window).height();
1068
1069                         $(document).on('click','.navbar-collapse.in',function(e) {
1070                                 if( $(e.target).is('a') ) {
1071                                         $(this).collapse('hide');
1072                                 }
1073                         });
1074                         
1075                         $('body').scrollspy({ target: '#main_menu_div' })
1076                 });
1077
1078         </script>
1079 </html>