4 <meta http-equiv="Content-Type" content="text/html; 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">
13 <title>NetData</title>
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>
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">
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">
30 // Set a callback to run when the Google Visualization API is loaded.
31 google.setOnLoadCallback(initCharts);
33 var TARGET_THUMB_GRAPH_WIDTH = 500; // thumb charts width will range from 0.5 to 1.5 of that
34 var MINIMUM_THUMB_GRAPH_WIDTH = 400; // thumb chart will generally try to be wider than that
35 var TARGET_THUMB_GRAPH_HEIGHT = 220; // the height of the thumb charts
36 var THUMBS_MAX_TIME_TO_SHOW = 600; // how much time the thumb charts will present?
38 var MAINCHART_MAX_TIME_TO_SHOW = 600; // how much time the main chart will present by default?
39 var MAINCHART_POINTS_DIVISOR = 10; // how much detailed will the main chart be by default? 1 = finest, higher is faster
40 var MAINCHART_CONTROL_HEIGHT = 75; // how tall the control chart will be
41 var MAINCHART_CONTROL_DIVISOR = 2; // how much detailed will the control chart be? 1 = finest, higher is faster
45 var MODE_GROUP_THUMBS = 3;
46 var mode; // one of the MODE_* values
48 var mycharts = new Array();
51 // html for the main menu
55 // ------------------------------------------------------------------------
56 // common HTML generation
58 function chartIsLoadingHTML(name, 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 " + name + "<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
60 function showChartIsLoading(id, name, width, height) {
61 //mylog('adding loading chart html in div with id ' + id);
62 document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height);
65 function thumbChartActions(i, c, nogroup) {
67 if(!nogroup) name = c.group_tag;
69 var refinfo = "the chart is drawing ";
70 if(c.group == 1) refinfo += "every single point collected.";
71 else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";
73 var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" title=\"" + refinfo + "\">"
74 + "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"
76 + "<div class=\"btn-group btn-group\"><button type=\"button\" class=\"btn btn-default disabled\"><small> " + name + "</small></button>";
80 var ingroup_detail = 0;
82 $.each(mycharts, function(i, d) {
83 if(d.group_tag == c.group_tag) {
85 if(d.isdetail) ingroup_detail++;
90 if(ingroup_detail) hidden = ", including " + ingroup_detail + " charts not shown now";
92 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>";
95 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>"
96 + "<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>"
97 + "<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>"
103 function mylog(txt) {
107 function chartssort(a, b) {
108 if(a.userpriority < b.userpriority) return -1;
113 // ------------------------------------------------------------------------
114 // MAINGRAPH = fullscreen view of 1 graph
116 function calculateChartGroup(c, divisor, maxtime, group) {
117 var before = c.before?c.before:new Date().getTime() / 1000;
118 var after = c.after?c.after:c.first_entry_t;
120 var dt = before - after;
121 if(dt > c.entries * c.update_every) dt = c.entries * c.update_every;
123 if(maxtime) dt = maxtime;
125 var data_points = Math.round(dt / c.update_every);
126 var screen_points = Math.round(c.chartOptions.width / divisor);
127 //mylog('screen = ' + screen_points + ', data = ' + data_points + ', divisor = ' + divisor);
130 if(screen_points > data_points) {
132 c.points_to_show = data_points;
133 //mylog("rendering at full detail");
136 c.group = Math.round(data_points / screen_points);
139 if(c.group > 60) c.group = 60;
140 else if(c.group > 45) c.group = 45;
141 else if(c.group > 30) c.group = 30;
142 else if(c.group > 20) c.group = 20;
143 else if(c.group > 15) c.group = 15;
144 else if(c.group > 10) c.group = 10;
145 else if(c.group > 5) c.group = 5;
146 else if(c.group > 2) c.group = 2;
150 c.points_to_show = Math.round(data_points / c.group);
151 //mylog("rendering adaptive");
156 c.points_to_show = Math.round(data_points / group);
157 //mylog("rendering with given group");
159 //mylog('group = ' + c.group + ', points = ' + c.points_to_show);
161 if(mainchart.chartType == 'LineChart') {
162 if(mainchart.group <= 2) mainchart.chartOptions.lineWidth = 1;
163 else mainchart.chartOptions.lineWidth = 2;
167 // copy the chart c to mainchart
168 // switch to main graphs screen
169 function initMainChart(c) {
170 if(mainchart) cleanThisChart(mainchart);
172 mainchart = $.extend(true, {}, c);
173 mainchart.refreshCount = 0;
174 mainchart.last_updated = 0;
175 mainchart.chartOptions.explorer = null;
176 mainchart.chart = null;
178 mainchart.chartOptions.width = screenWidth();
179 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
180 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
181 //mainchart.chartOptions.chartArea = {'width': '80%'};
183 mainchart.div = 'maingraph';
184 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
186 // copy it to the hidden chart
187 mainchart.hiddenchart = $.extend(true, {}, mainchart);
188 mainchart.hiddenchart.chartOptions.height = MAINCHART_CONTROL_HEIGHT;
189 mainchart.hiddenchart.div = 'maingraph_control';
191 // initialize the div
192 showChartIsLoading(mainchart.div, mainchart.name, mainchart.chartOptions.width, mainchart.chartOptions.height);
194 // set the radio buttons
195 setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
196 setMainChartMax('normal');
198 $('#group' + mainchart.group).trigger('click');
199 setMainChartGroup(mainchart.group, 'no-refresh');
204 function refreshHiddenChart(doNext) {
205 if(refresh_mode == REFRESH_PAUSED && mainchart.hiddenchart.last_updated != 0) {
206 if(typeof doNext == "function") doNext();
210 // is it too soon for a refresh?
211 var now = new Date().getTime();
212 if((now - mainchart.hiddenchart.last_updated) < (mainchart.hiddenchart.group * mainchart.hiddenchart.update_every * 1000)) {
213 if(typeof doNext == "function") doNext();
217 if(mainchart.dashboard && mainchart.hiddenchart.refreshCount > 50) {
218 mainchart.dashboard.clear();
219 mainchart.control_wrapper.clear();
220 mainchart.hidden_wrapper.clear();
222 mainchart.dashboard = null;
223 mainchart.control_wrapper = null;
224 mainchart.hidden_wrapper = null;
225 mainchart.hiddenchart.last_updated = 0;
228 if(!mainchart.dashboard) {
229 var controlopts = $.extend(true, {}, mainchart.chartOptions, {
231 height: mainchart.hiddenchart.chartOptions.height,
232 chartArea: {'width': '98%'},
233 hAxis: {'baselineColor': 'none'},
234 vAxis: {'title': null},
237 mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
238 mainchart.control_wrapper = new google.visualization.ControlWrapper({
239 controlType: 'ChartRangeFilter',
240 containerId: 'maingraph_control',
242 filterColumnIndex: 0,
244 chartType: mainchart.chartType,
245 chartOptions: controlopts,
246 minRangeSize: (MAINCHART_MAX_TIME_TO_SHOW * 1000 * mainchart.update_every) / MAINCHART_POINTS_DIVISOR,
250 mainchart.hidden_wrapper = new google.visualization.ChartWrapper({
251 chartType: mainchart.chartType,
252 containerId: 'maingraph_hidden',
254 isStacked: mainchart.chartOptions.isStacked,
255 width: mainchart.hiddenchart.chartOptions.width,
256 height: mainchart.hiddenchart.chartOptions.height,
257 //chartArea: {'height': '80%', 'width': '100%'},
258 //hAxis: {'slantedText': false},
259 //legend: {'position': 'none'}
263 mainchart.hiddenchart.refreshCount = 0;
266 // load the data for the control and the hidden wrappers
267 // calculate the group and points to show for the control chart
268 calculateChartGroup(mainchart.hiddenchart, MAINCHART_CONTROL_DIVISOR, 0, -1);
271 url: generateChartURL(mainchart.hiddenchart),
275 .done(function(jsondata) {
276 if(!jsondata || jsondata.length == 0) return;
278 mainchart.control_data = new google.visualization.DataTable(jsondata);
280 if(mainchart.hiddenchart.last_updated == 0) {
281 google.visualization.events.addListener(mainchart.control_wrapper, 'ready', mainchartControlReadyEvent);
282 mainchart.dashboard.bind(mainchart.control_wrapper, mainchart.hidden_wrapper);
284 if(refresh_mode != REFRESH_PAUSED)
285 mainchart.control_wrapper.setState({range: {
286 start: new Date((Math.round(new Date().getTime() / 1000) - MAINCHART_MAX_TIME_TO_SHOW) * 1000),
290 mainchart.dashboard.draw(mainchart.control_data);
291 mainchart.hiddenchart.last_updated = new Date().getTime();
292 mainchart.hiddenchart.refreshCount++;
295 if(typeof doNext == "function") doNext();
299 function mainchartControlReadyEvent() {
300 google.visualization.events.addListener(mainchart.control_wrapper, 'statechange', mainchartControlStateHandler);
304 function mainchartControlStateHandler() {
305 // setMainChartPlay('pause');
307 var state = mainchart.control_wrapper.getState();
308 mainchart.after = Math.round(state.range.start.getTime() / 1000);
309 mainchart.before = Math.round(state.range.end.getTime() / 1000);
311 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, 0);
312 //mylog('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
314 $('#group' + mainchart.group).trigger('click');
315 mainchart.last_updated = 0;
317 if(refresh_mode != REFRESH_PAUSED) pauseGraphs();
320 function initMainChartIndex(i) {
321 if(mode == MODE_GROUP_THUMBS)
322 initMainChart(group_charts[i]);
324 else if(mode == MODE_THUMBS)
325 initMainChart(mycharts[i]);
328 var last_main_chart_max='normal';
329 function setMainChartMax(m) {
330 if(!mainchart) return;
333 if(last_main_chart_max == 'maximized') m = 'normal';
334 else m = 'maximized';
337 if(m == "maximized") {
338 mainchart.chartOptions.theme = 'maximized';
339 //mainchart.chartOptions.axisTitlesPosition = 'in';
340 //mainchart.chartOptions.legend = {position: 'none'};
341 //mainchart.chartOptions.hAxis.title = null;
342 mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';
343 mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';
346 mainchart.chartOptions.theme = null;
347 mainchart.chartOptions.hAxis.viewWindowMode = null;
348 mainchart.chartOptions.vAxis.viewWindowMode = null;
350 $('.mainchart_max_button').button(m);
351 last_main_chart_max = m;
352 mainchart.last_updated = 0;
355 function setMainChartGroup(g, norefresh) {
356 if(!mainchart) return;
360 if(!mainchart.before && !mainchart.after)
361 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, mainchart.group);
363 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, mainchart.group);
366 mainchart.last_updated = 0;
370 var last_main_chart_avg = null;
371 function setMainChartGroupMethod(g, norefresh) {
372 if(!mainchart) return;
375 if(last_main_chart_avg == 'max') g = 'average';
379 mainchart.group_method = g;
381 $('.mainchart_avg_button').button(g);
384 mainchart.last_updated = 0;
387 last_main_chart_avg = g;
390 function setMainChartPlay(p) {
391 if(!mainchart) return;
394 if(refresh_mode != REFRESH_ALWAYS) p = 'play';
399 //mainchart.chartOptions.explorer = null;
401 mainchart.before = 0;
402 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
403 $('#group' + mainchart.group).trigger('click');
404 mainchart.last_updated = 0;
405 mainchart.hiddenchart.last_updated = 0;
409 //mainchart.chartOptions.explorer = {
410 // 'axis': 'horizontal',
413 //mainchart.last_updated = 0;
415 //if(!refreshChart(mainchart, pauseGraphs))
421 // ------------------------------------------------------------------------
424 function screenWidth() {
425 return (($(window).width() * 0.95) - 50);
428 // calculate the proper width for the thumb charts
429 function thumbWidth() {
430 var cwidth = screenWidth();
431 var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
432 if(items < 1) items = 1;
434 if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
436 return Math.round(cwidth / items) - 1;
439 function groupChartSizes() {
440 var s = { width: screenWidth() / 2, height: ($(window).height() - 130) / 3 - 10};
441 if(s.width < MINIMUM_THUMB_GRAPH_WIDTH * 1.5) s.width = screenWidth();
444 if(group_charts) $.each(group_charts, function(i, c) {
445 if(c.enabled) count++;
449 s.width = TARGET_THUMB_GRAPH_WIDTH;
450 s.height = TARGET_THUMB_GRAPH_HEIGHT;
453 s.width = screenWidth();
454 s.height = ($(window).height() - 130) / count - 10;
456 else if(count == 4) {
457 s.height = ($(window).height() - 130) / 2 - 10;
460 if(s.height < TARGET_THUMB_GRAPH_HEIGHT * 1.5)
461 s.height = TARGET_THUMB_GRAPH_HEIGHT * 1.5;
467 // if the thumb charts need resize in their width, reset them
468 function resizeCharts() {
469 var width = screenWidth();
472 mainchart.chartOptions.width = width;
473 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
474 mainchart.last_updated = 0;
476 mainchart.hidden_wrapper.setOption('width', width);
477 mainchart.control_wrapper.setOption('ui.chartOptions.width', width);
478 mainchart.hiddenchart.chartOptions.width = width;
479 mainchart.hiddenchart.last_updated = 0;
482 width = thumbWidth();
483 $.each(mycharts, function(i, c) {
484 if(c.enabled && c.chartOptions.width != width) {
486 c.chartOptions.width = width;
487 showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
492 if(group_charts) $.each(group_charts, function(i, c) {
493 var sizes = groupChartSizes();
495 if(c.enabled && (c.chartOptions.width != sizes.width || c.chartOptions.height != sizes.height)) {
497 c.chartOptions.width = sizes.width;
498 c.chartOptions.height = sizes.height;
499 showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
505 var resize_request = false;
506 window.onresize = function(event) {
507 resize_request = true;
511 // ------------------------------------------------------------------------
512 // Core of the thread refreshing the charts
514 var REFRESH_PAUSED = 0;
515 var REFRESH_ALWAYS = 1;
517 var refresh_mode = REFRESH_PAUSED;
518 var last_refresh = 0;
519 function playGraphs() {
520 if(refresh_mode == REFRESH_ALWAYS) return;
522 //mylog('PlayGraphs()');
523 refresh_mode = REFRESH_ALWAYS;
524 $('.mainchart_play_button').button('play');
526 // check if the thread died due to a javascript error
527 var now = new Date().getTime();
528 if((now - last_refresh) > 5000) {
529 // it died or never started
530 //mylog('It seems the refresh thread died. Restarting it.');
535 function pauseGraphs() {
536 if(refresh_mode == REFRESH_PAUSED) return;
538 //mylog('PauseGraphs()');
539 refresh_mode = REFRESH_PAUSED;
540 $('.mainchart_play_button').button('pause');
543 // refresh the proper chart
544 // this is an internal function.
545 // never call it directly, or new javascript threads will be spawn
547 function chartsRefresh() {
550 resize_request = false;
551 // refresh_mode = REFRESH_ALWAYS;
554 last_refresh = new Date().getTime();
556 if(refresh_mode == REFRESH_PAUSED) {
557 if(mode == MODE_MAIN && mainchart.last_updated == 0)
560 timeout = setTimeout(chartsRefresh, 100);
565 if(mode == MODE_THUMBS) thumbChartsRefresh();
566 else if(mode == MODE_GROUP_THUMBS) groupChartsRefresh();
567 else if(mode == MODE_MAIN) mainChartRefresh();
568 else timeout = setTimeout(triggerRefresh, 100);
571 // callback for refreshing the charts later
572 // this is an internal function.
573 // never call it directly, or new javascript threads will be spawn
574 function triggerRefresh() {
575 //mylog('triggerRefresh()');
577 // cleanup has to take place when the charts are not refreshed
578 // since the refreshing thread is in this function, it means
579 // nothing is being refreshed.
582 if(mode == MODE_THUMBS) timeout = setTimeout(chartsRefresh, 200);
583 else if(mode == MODE_GROUP_THUMBS) timeout = setTimeout(chartsRefresh, 200);
584 else if(mode == MODE_MAIN) timeout = setTimeout(chartsRefresh, 200);
585 else timeout = setTimeout(triggerRefresh, 100);
588 // refresh the main chart
589 // make sure we don't loose the refreshing thread
590 function mainChartRefresh() {
591 //mylog('mainChartRefresh()');
593 if(mode != MODE_MAIN || !mainchart) {
598 if(!refreshChart(mainchart, hiddenChartRefresh))
599 hiddenChartRefresh();
602 function hiddenChartRefresh() {
603 refreshHiddenChart(triggerRefresh);
606 function roundRobinRefresh(charts, startat) {
607 var refreshed = false;
609 // find a chart to refresh
610 var all = charts.length;
614 for(count = 0; count < all ; count++, cur++) {
615 if(cur >= all) cur = 0;
617 if(charts[cur].enabled) {
618 //mylog('going to refresh chart ' + charts[cur].name);
619 refreshed = refreshChart(charts[cur], chartsRefresh);
624 if(!refreshed) triggerRefresh();
628 // refresh the thumb charts
629 // make sure we don't loose the refreshing thread
630 var last_thumb_updated = 0;
631 function thumbChartsRefresh() {
632 //mylog('thumbChartsRefresh()');
634 if(mycharts.length == 0 || mode != MODE_THUMBS) {
639 last_thumb_updated = roundRobinRefresh(mycharts, last_thumb_updated);
642 // refresh the group charts
643 // make sure we don't loose the refreshing thread
644 var last_group_updated = 0;
645 function groupChartsRefresh() {
646 //mylog('groupChartsRefresh()');
648 if(!group_charts || group_charts.length == 0 || mode != MODE_GROUP_THUMBS) {
649 //mylog('cannot refresh charts');
654 last_group_updated = roundRobinRefresh(group_charts, last_group_updated);
658 // ------------------------------------------------------------------------
659 // switch the screen between views
660 // these should be called only from initXXXX()
662 function disableChart(i) {
663 //mylog('disableChart(' + i + ')');
668 if(mode == MODE_GROUP_THUMBS && group_charts) {
669 $.each(group_charts, function(i, c) {
670 if(c.enabled) count++;
673 if(i < group_charts.length) chart = group_charts[i];
675 else if(mode == MODE_THUMBS) {
676 $.each(mycharts, function(i, c) {
677 if(c.enabled) count++;
680 if(i < mycharts.length) chart = mycharts[i];
686 alert('Cannot close the last chart shown.');
691 //mylog("disabling chart " + chart.name);
692 chart.disablethisplease = true;
696 function cleanThisChart(chart, emptydivs) {
697 //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');
699 if(chart.dashboard) {
700 chart.dashboard.clear();
701 chart.dashboard = null;
703 if(chart.control_wrapper) {
704 chart.control_wrapper.clear();
705 chart.control_wrapper = null;
708 if(chart.hidden_wrapper) {
709 chart.hidden_wrapper.clear();
710 chart.hidden_wrapper = null;
713 chart.control_data = null;
716 if(chart.chart) chart.chart.clearChart();
720 var div = document.getElementById(chart.div);
722 div.style.display = 'none';
726 div = document.getElementById(chart.div + "_parent");
728 div.style.display = 'none';
733 //mylog("chart " + chart.name + " cleaned with option " + emptydivs);
736 // cleanup the previously shown charts
737 function cleanupCharts() {
738 //mylog('cleanupCharts()');
740 if(mode != MODE_MAIN && mainchart) {
741 if(mainchart.chart) cleanThisChart(mainchart);
745 if(mode != MODE_GROUP_THUMBS && group_charts) {
749 // cleanup the disabled charts
750 $.each(mycharts, function(i, c) {
751 if(c.disablethisplease && c.enabled) {
752 cleanThisChart(c, 'emptydivs');
753 c.disablethisplease = false;
755 resize_request = true;
756 //mylog("disabled chart " + c.name + " removed");
760 if(group_charts) $.each(group_charts, function(i, c) {
761 if(c.disablethisplease && c.enabled) {
762 cleanThisChart(c, 'emptydivs');
763 c.disablethisplease = false;
765 resize_request = true;
766 //mylog("disabled chart " + c.name + " removed");
770 // we never cleanup the thumb charts
773 function updateUI() {
774 $('[data-toggle="tooltip"]').tooltip({'placement': 'top', 'container': 'body', 'html': true});
776 $('[data-spy="scroll"]').each(function () {
777 var $spy = $(this).scrollspy('refresh')
781 var thumbsScrollPosition = null;
782 function switchToMainGraph() {
783 //mylog('switchToMainGraph()');
785 if(!mainchart) return;
787 if(!group_charts) thumbsScrollPosition = window.pageYOffset;
789 document.getElementById('maingraph_container').style.display = 'block';
790 document.getElementById('thumbgraphs_container').style.display = 'none';
791 document.getElementById('groupgraphs_container').style.display = 'none';
793 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>";
795 window.scrollTo(0, 0);
802 function switchToThumbGraphs() {
803 //mylog('switchToThumbGraphs()');
805 document.getElementById('maingraph_container').style.display = 'none';
806 document.getElementById('thumbgraphs_container').style.display = 'block';
807 document.getElementById('groupgraphs_container').style.display = 'none';
809 document.getElementById("main_menu_div").innerHTML = mainmenu;
811 if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);
819 function switchToGroupGraphs() {
820 //mylog('switchToGroupGraphs()');
822 if(!group_charts) return;
824 if(!mainchart) thumbsScrollPosition = window.pageYOffset;
826 document.getElementById('maingraph_container').style.display = 'none';
827 document.getElementById('thumbgraphs_container').style.display = 'none';
828 document.getElementById('groupgraphs_container').style.display = 'block';
830 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>";
832 window.scrollTo(0, 0);
834 mode = MODE_GROUP_THUMBS;
840 // ------------------------------------------------------------------------
843 var group_charts = null;
844 function initGroupGraphs(group) {
847 if(group_charts) clearGroupGraphs();
848 group_charts = new Array();
851 $.each(mycharts, function(i, c) {
852 if(c.group_tag == group) {
853 group_charts[count] = [];
854 group_charts[count] = $.extend(true, {}, c);
855 group_charts[count].div += "_group";
856 group_charts[count].enabled = true;
857 group_charts[count].chart = null;
858 group_charts[count].last_updated = 0;
862 group_charts.sort(chartssort);
864 var sizes = groupChartSizes();
867 $.each(group_charts, function(i, c) {
868 c.chartOptions.width = sizes.width;
869 c.chartOptions.height = sizes.height;
871 groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">" + thumbChartActions(i, c, 'nogroup') + "</td></tr></table></div>";
875 document.getElementById("groupgraphs").innerHTML = groupbody;
876 switchToGroupGraphs();
879 function clearGroupGraphs() {
880 if(group_charts && group_charts.length) {
881 $.each(group_charts, function(i, c) {
882 cleanThisChart(c, 'emptydivs');
888 document.getElementById("groupgraphs").innerHTML = "";
892 // ------------------------------------------------------------------------
893 // Global entry point
894 // initialize the thumb charts
896 // load the charts from the server
897 // generate html for the thumbgraphs to support them
898 function initCharts() {
899 var width = thumbWidth();
900 var height = TARGET_THUMB_GRAPH_HEIGHT;
902 loadCharts(null, function(c) {
905 if(mycharts == null || mycharts.length == 0) {
906 alert("Cannot load data from server.");
910 var thumbsContainer = document.getElementById("thumbgraphs");
911 if(!thumbsContainer) {
912 alert("Cannot find the thumbsContainer");
916 mycharts.sort(chartssort);
918 document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;
919 document.title = mycharts[0].hostname;
921 // create an array for grouping all same-type graphs together
922 var categories = new Array();
923 $.each(mycharts, function(i, c) {
924 c.chartOptions.width = width;
925 c.chartOptions.height = height;
927 // calculate how many point to show for each chart
928 c.points_to_show = Math.round(c.entries / c.group) - 1;
930 // show max 10 mins of data
931 if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;
935 var h = "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">"
936 + thumbChartActions(i, c)
937 + "</td></tr></table></div>";
939 // find the categories object for this type
940 for(j = 0; j < categories.length ;j++) {
941 if(categories[j].name == c.type) {
942 categories[j].html += h;
943 categories[j].count++;
948 if(j == categories.length) {
949 categories.push({name: c.type, title: c.category, description: '', priority: 0, count: 1, glyphicon: c.glyphicon, html: h});
954 $.each(categories, function(i, a) {
955 if(a.name == "system") a.priority = 1;
956 else if(a.name == "net") a.priority = 2;
957 else if(a.name == "tc") a.priority = 3;
958 else if(a.name == "conntrack") a.priority = 4;
959 else if(a.name == "ipvs") a.priority = 5;
960 else if(a.name == "ipv4") a.priority = 6;
961 else if(a.name == "cpu") a.priority = 7;
962 else if(a.name == "mem") a.priority = 8;
963 else if(a.name == "disk") a.priority = 9;
964 else a.priority = 99;
966 a.html = "<tr><td id=\"" + a.name + "\"><ol class=\"breadcrumb graphs\"><li class=\"active\"><span class=\"glyphicon " + a.glyphicon + "\"></span> <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>";
969 function categoriessort(a, b) {
970 if(a.priority < b.priority) return -1;
973 categories.sort(categoriessort);
975 // combine all the htmls into one
976 var allcategories = "<table width=\"100%\">";
977 mainmenu = "<ul class=\"nav navbar-nav\"><li><a href=\"#\">Home</a></li>";
978 $.each(categories, function(i, a) {
979 allcategories += a.html;
980 mainmenu += "<li><a href=\"#" + a.name + "\">" + a.title + "</a></li>";
982 allcategories += "</table>";
985 thumbsContainer.innerHTML = allcategories;
986 switchToThumbGraphs();
993 <body role="document" data-spy="scroll" data-target="#main_menu_div">
994 <nav id="mynav" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
995 <div class="container">
996 <div class="navbar-header">
997 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main_menu_div">
998 <span class="sr-only">Toggle navigation</span>
999 <span class="icon-bar"></span>
1000 <span class="icon-bar"></span>
1001 <span class="icon-bar"></span>
1003 <a class="navbar-brand" href="javascript:switchToThumbGraphs();" id="hostname_id">NetData</a>
1005 <div class="collapse navbar-collapse" id="main_menu_div">
1006 <ul class="nav navbar-nav">
1007 <li><a href="#">Home</a></li>
1009 </div><!--/.nav-collapse -->
1013 <div class="container graphs" id="maingraph_container" style="display: none">
1016 <div class="maingraph">
1019 <div class="maingraph" id="maingraph"></div>
1020 <div id="maingraph_dashboard">
1021 <div class="maingraph" id="maingraph_hidden" style="display: none"></div>
1022 <div class="maingraph" id="maingraph_control"></div>
1025 <tr><td align="center">
1026 <div class="btn-group">
1027 <form id="mainchartform">
1028 <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." >
1029 <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');">
1030 <span class="glyphicon glyphicon-pause"></span>
1033 <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" >
1034 <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');">
1035 <span class="glyphicon glyphicon-signal"></span>
1038 <!-- <div class="btn-group btn-group" data-toggle="buttons">
1039 <label class="btn btn-primary" data-toggle="tooltip" title="show the MAX point among all points grouped">
1040 <input type="radio" name="groupmethod" id="groupmax" onChange="setMainChartGroupMethod('max');">
1041 <span class="glyphicon glyphicon-signal"></span>
1043 <label class="btn btn-primary" data-toggle="tooltip" title="show the AVERAGE of all points grouped">
1044 <input type="radio" name="groupmethod" id="groupaverage" onChange="setMainChartGroupMethod('average');">
1045 <span class="glyphicon glyphicon-align-justify"></span>
1048 --> <div class="btn-group btn-group" data-toggle="buttons" >
1049 <label class="btn btn-primary" data-toggle="tooltip" title="do not group points, show the raw data">
1050 <input type="radio" name="group" id="group1" onChange="setMainChartGroup(1);">1
1053 <label class="btn btn-primary" data-toggle="tooltip" title="group in half, show 1 every 2 points of data">
1054 <input type="radio" name="group" id="group2" onChange="setMainChartGroup(2);">2
1057 <label class="btn btn-primary" data-toggle="tooltip" title="group every 5 points of data">
1058 <input type="radio" name="group" id="group5" onChange="setMainChartGroup(5);">5
1060 <label class="btn btn-primary" data-toggle="tooltip" title="group every 10 points of data">
1061 <input type="radio" name="group" id="group10" onChange="setMainChartGroup(10);">10
1063 <label class="btn btn-primary" data-toggle="tooltip" title="group every 15 points of data">
1064 <input type="radio" name="group" id="group15" onChange="setMainChartGroup(15);">15
1066 <label class="btn btn-primary" data-toggle="tooltip" title="group every 20 points of data">
1067 <input type="radio" name="group" id="group20" onChange="setMainChartGroup(20);">20
1069 <label class="btn btn-primary" data-toggle="tooltip" title="group every 30 points of data">
1070 <input type="radio" name="group" id="group30" onChange="setMainChartGroup(30);">30
1072 <label class="btn btn-primary" data-toggle="tooltip" title="group every 45 points of data">
1073 <input type="radio" name="group" id="group45" onChange="setMainChartGroup(45);">45
1075 <label class="btn btn-primary" data-toggle="tooltip" title="group every 60 points of data">
1076 <input type="radio" name="group" id="group60" onChange="setMainChartGroup(60);">60
1079 <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" >
1080 <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');">
1081 <span class="glyphicon glyphicon-fullscreen"></span>
1084 <!-- <div class="btn-group btn-group" data-toggle="buttons" >
1085 <label class="btn btn-primary" data-toggle="tooltip" title="NORMAL chart size">
1086 <input type="radio" name="chartmax" id="chartnormal" onChange="setMainChartMax('normal');">
1087 <span class="glyphicon glyphicon-resize-small"></span>
1089 <label class="btn btn-primary" data-toggle="tooltip" title="MAXIMIZED chart size">
1090 <input type="radio" name="chartmax" id="chartmax" onChange="setMainChartMax('maximized');">
1091 <span class="glyphicon glyphicon-fullscreen"></span>
1098 </div><!-- /.maingraph -->
1103 <div class="container graphs" id="thumbgraphs_container">
1104 <div class="allgraphs" id="thumbgraphs">
1105 <table width="100%">
1106 <tr><td id="splash" align="center" style="vertical-align:middle">
1108 Welcome to <b>NetData</b>!
1110 <span class="glyphicon glyphicon-off"></span>
1114 <span class="label label-default">Please wait...</span>
1121 <div class="container graphs" id="groupgraphs_container">
1122 <div class="allgraphs" id="groupgraphs">
1126 <div class="container graphs" id="groupgraphs_container">
1130 Realtime System Information over the web for all linux systems.
1132 Distributed under GPL.
1134 (c) 2014 Costa Tsaousis <a href="mailto:costa@tsaousis.gr">costa@tsaousis.gr</a>
1137 <script type='text/javascript'>
1138 google.load('visualization', '1.1', {packages: ['controls']});
1140 $(document).ready(function(){
1141 document.getElementById('splash').height = $(window).height();
1143 $(document).on('click','.navbar-collapse.in',function(e) {
1144 if( $(e.target).is('a') ) {
1145 $(this).collapse('hide');
1149 $('body').scrollspy({ target: '#main_menu_div' })