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; // 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 = 1200;
37 var THUMBS_MAX_TIME_TO_SHOW = 600;
41 var mode; // one of the MODE_* values
43 var mycharts = new Array();
46 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>"; }
48 function showChartIsLoading(id, width, height) { document.getElementById(id).innerHTML = chartIsLoadingHTML(width, height); }
50 // copy the chart c to mainchart
51 // switch to main graphs screen
52 function mainChart(c) {
53 if(mainchart && mainchart.chart) mainchart.chart.clearChart();
55 mainchart = $.extend(true, {}, c);
57 mainchart.chart = null;
58 mainchart.chartOptions.width = screenWidth();
59 mainchart.chartOptions.height = $(window).height() - 200;
60 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
63 mainchart.div = 'maingraph';
64 mainchart.last_updated = 0;
66 if(mainchart.chartOptions.isStacked) mainchart.group = 5;
67 //mainchart.chartOptions.titlePosition = 'none';
68 mainchart.chartOptions.explorer = null;
71 showChartIsLoading(mainchart.div, mainchart.chartOptions.width, mainchart.chartOptions.height);
73 document.getElementById('maingraph_title').innerHTML = " " + mainchart.title + " ";
75 // set the radio buttons
76 setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
77 setMainChartMax('normal');
79 $('#group' + mainchart.group).trigger('click');
84 function setMainChart(i) {
85 mainChart(mycharts[i]);
88 var last_main_chart_max='normal';
89 function setMainChartMax(m) {
90 if(!mainchart) return;
93 if(last_main_chart_max == 'maximized') m = 'normal';
97 if(m == "maximized") {
98 mainchart.chartOptions.theme = 'maximized';
99 //mainchart.chartOptions.axisTitlesPosition = 'in';
100 //mainchart.chartOptions.legend = {position: 'none'};
101 //mainchart.chartOptions.hAxis.title = null;
102 mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';
103 mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';
106 mainchart.chartOptions.theme = null;
107 mainchart.chartOptions.hAxis.viewWindowMode = null;
108 mainchart.chartOptions.vAxis.viewWindowMode = null;
110 $('.mainchart_max_button').button(m);
111 last_main_chart_max = m;
112 mainchart.last_updated = 0;
115 function setMainChartGroup(g) {
116 if(!mainchart) return;
119 mainchart.last_updated = 0;
124 var last_main_chart_avg = null;
125 function setMainChartGroupMethod(g, norefresh) {
126 if(!mainchart) return;
129 if(last_main_chart_avg == 'max') g = 'average';
133 mainchart.group_method = g;
135 $('.mainchart_avg_button').button(g);
138 mainchart.last_updated = 0;
142 last_main_chart_avg = g;
145 var stop_refreshing = 0;
146 function playGraphs() {
148 $('.mainchart_play_button').button('play');
151 function pauseGraphs() {
153 $('.mainchart_play_button').button('pause');
156 function setMainChartPlay(p) {
157 if(!mainchart) return;
160 if(stop_refreshing) p = 'play';
165 mainchart.chartOptions.explorer = null;
169 mainchart.chartOptions.explorer = {
170 'axis': 'horizontal',
173 mainchart.last_updated = 0;
174 refreshChart(mainchart, pauseGraphs);
176 last_main_chart_play = p;
179 // refresh the main chart
180 // make sure it gets updated frequently
181 function mainChartRefresh() {
182 if(!mainchart || mode != MODE_MAIN) {
183 if(mainchart) mainchart.clearChart();
188 mainchart.points_to_show = Math.round(mainchart.entries / mainchart.group) - 1;
190 if(mainchart.points_to_show * mainchart.group > MAINCHART_MAX_TIME_TO_SHOW)
191 mainchart.points_to_show = MAINCHART_MAX_TIME_TO_SHOW / mainchart.group;
193 if(!refreshChart(mainchart, triggerRefresh)) triggerRefresh();
195 // FIXME for controlled charts
196 // showChartWithRange(mainchart);
199 function screenWidth() {
200 return (($(window).width() * 0.95) - 40);
203 // calculate the proper width for the thumb charts
204 function thumbWidth() {
205 var cwidth = screenWidth();
206 var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
207 if(items < 1) items = 1;
209 if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
211 return Math.round(cwidth / items) - 1;
215 // if the thumb charts need resize in their width, reset them
216 function resizeCharts() {
217 var width = screenWidth();
220 mainchart.chartOptions.width = width;
221 mainchart.chartOptions.height = $(window).height() - 200;
222 mainchart.last_updated = 0;
225 width = thumbWidth();
226 $.each(mycharts, function(i, c) {
227 if(c.enabled && c.chartOptions.width != width) {
228 if(c.chart) c.chart.clearChart();
230 c.chartOptions.width = width;
231 showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
239 // load the charts from the server
240 // generate html for the thumbgraphs to support them
241 function initCharts() {
242 var width = thumbWidth();
243 var height = TARGET_THUMB_GRAPH_HEIGHT;
245 loadCharts(null, function(c) {
248 if(mycharts == null || mycharts.length == 0) {
249 alert("Cannot load data from server.");
253 var thumbsContainer = document.getElementById("thumbgraphs");
254 if(!thumbsContainer) {
255 alert("Cannot find the thumbsContainer");
259 function chartssort(a, b) {
260 if(a.userpriority < b.userpriority) return -1;
263 mycharts.sort(chartssort);
265 document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;
266 document.title = mycharts[0].hostname;
268 // create an array for grouping all same-type graphs together
269 var categories = new Array();
270 $.each(mycharts, function(i, c) {
271 c.chartOptions.width = width;
272 c.chartOptions.height = height;
274 // calculate how many point to show for each chart
275 c.points_to_show = Math.round(c.entries / c.group) - 1;
277 // show max 10 mins of data
278 if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;
282 var h = "<div class=\"thumbgraph\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\"><div class=\"btn-group-xs\"><button type=\"button\" class=\"btn btn-default\" onclick=\"setMainChart(" + i +");\"> select " + c.name + " for zoom </button></div></td></tr></table></div>";
284 // find the categories object for this type
285 for(j = 0; j < categories.length ;j++) {
286 if(categories[j].name == c.type) {
287 categories[j].html += h;
288 categories[j].count++;
293 if(j == categories.length) {
294 var t = "(as " + c.group_method + " every " + (c.group * c.update_every) + " seconds)";
295 categories.push({name: c.type, title: c.category, description: t, priority: 0, count: 1, glyphicon: c.glyphicon, html: h});
300 $.each(categories, function(i, a) {
301 if(a.name == "system") a.priority = 1;
302 else if(a.name == "net") a.priority = 2;
303 else if(a.name == "tc") a.priority = 3;
304 else if(a.name == "conntrack") a.priority = 4;
305 else if(a.name == "ipvs") a.priority = 5;
306 else if(a.name == "ipv4") a.priority = 6;
307 else if(a.name == "cpu") a.priority = 7;
308 else if(a.name == "mem") a.priority = 8;
309 else if(a.name == "disk") a.priority = 9;
310 else a.priority = 99;
312 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>";
315 function categoriessort(a, b) {
316 if(a.priority < b.priority) return -1;
319 categories.sort(categoriessort);
321 // combine all the htmls into one
322 var allcategories = "<table width=\"100%\">";
323 $.each(categories, function(i, a) {
324 allcategories += a.html;
326 allcategories += "</table>";
328 thumbsContainer.innerHTML = allcategories;
333 var last_thumb_updated = 0;
334 function thumbChartsRefresh() {
335 if(mycharts.length == 0 || mode != MODE_THUMBS) return;
337 // find a chart to refresh
338 var orig = last_thumb_updated;
339 last_thumb_updated++;
340 if(last_thumb_updated >= mycharts.length) last_thumb_updated = 0;
342 while(last_thumb_updated != orig) {
343 if(refreshChart(mycharts[last_thumb_updated], chartsRefresh)) break;
345 last_thumb_updated++;
346 if(last_thumb_updated >= mycharts.length) last_thumb_updated = 0;
349 // no chart refreshed
350 if(last_thumb_updated == orig) triggerRefresh();
353 // refresh the proper chart
355 function chartsRefresh() {
356 if(stop_refreshing) return;
359 clearTimeout(timeout);
363 if(mode == MODE_THUMBS) thumbChartsRefresh();
364 else if(mode == MODE_MAIN) mainChartRefresh();
365 else timeout = setTimeout(triggerRefresh, 1000);
368 // callback for refreshing the charts later
369 function triggerRefresh() {
370 if(mode == MODE_THUMBS) timeout = setTimeout(chartsRefresh, 200);
371 else if(mode == MODE_MAIN) timeout = setTimeout(chartsRefresh, 500);
372 else timeout = setTimeout(triggerRefresh, 1000);
375 window.onresize = function(event) {
379 var thumbsScrollPosition = null;
380 function showMainGraph() {
381 if(!mainchart) return;
383 thumbsScrollPosition = window.pageYOffset;
387 document.getElementById('maingraph_container').style.display = 'block';
388 document.getElementById('thumbgraphs_container').style.display = 'none';
393 function showThumbGraphs() {
396 document.getElementById('maingraph_container').style.display = 'none';
397 document.getElementById('thumbgraphs_container').style.display = 'block';
399 if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);
402 if(mainchart.chart) mainchart.chart.clearChart();
412 <body role="document">
413 <nav id="mynav" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
414 <div class="container">
415 <div class="navbar-header">
416 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
417 <span class="sr-only">Toggle navigation</span>
418 <span class="icon-bar"></span>
419 <span class="icon-bar"></span>
420 <span class="icon-bar"></span>
422 <a class="navbar-brand" href="#" id="hostname_id">NetData</a>
424 <div class="collapse navbar-collapse">
425 <ul class="nav navbar-nav">
426 <li class="active"><a href="#">Home</a></li>
427 <li><a href="#system">System</a></li>
428 <li><a href="#net">Network</a></li>
429 <li><a href="#tc">QoS</a></li>
430 <li><a href="#conntrack">Netfilter</a></li>
431 <li><a href="#ipv4">IPv4</a></li>
432 <li><a href="#ipvs">IPVS</a></li>
433 <li><a href="#cpu">CPU</a></li>
434 <li><a href="#disk">Disk</a></li>
436 </div><!--/.nav-collapse -->
440 <div class="container graphs" id="maingraph_container" style="display: none">
442 <tr><td><ol class="breadcrumb graphs"><li class="active"><div class="btn-group btn-group-sm"><button type="button" onclick="showThumbGraphs();" class="btn btn-default"> ← Back </button></div><a id="maingraph_title" href="#maingraph"><b> Maingraph </b></a></li></ol></td></tr>
444 <div class="maingraph">
447 <div class="maingraph" id="maingraph"></div>
449 <tr><td align="center">
450 <div class="btn-group">
451 <form id="mainchartform">
452 <div class="btn-group btn-group-xs" 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." >
453 <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');">
454 <span class="glyphicon glyphicon-pause"></span>
457 <div class="btn-group btn-group-xs" 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" >
458 <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');">
459 <span class="glyphicon glyphicon-signal"></span>
462 <!-- <div class="btn-group btn-group-xs" data-toggle="buttons">
463 <label class="btn btn-primary" data-toggle="tooltip" title="show the MAX point among all points grouped">
464 <input type="radio" name="groupmethod" id="groupmax" onChange="setMainChartGroupMethod('max');">
465 <span class="glyphicon glyphicon-signal"></span>
467 <label class="btn btn-primary" data-toggle="tooltip" title="show the AVERAGE of all points grouped">
468 <input type="radio" name="groupmethod" id="groupaverage" onChange="setMainChartGroupMethod('average');">
469 <span class="glyphicon glyphicon-align-justify"></span>
472 --> <div class="btn-group btn-group-xs" data-toggle="buttons" >
473 <label class="btn btn-primary" data-toggle="tooltip" title="do not group points, show the raw data">
474 <input type="radio" name="group" id="group1" onChange="setMainChartGroup(1);">1
477 <label class="btn btn-primary" data-toggle="tooltip" title="group in half, show 1 every 2 points of data">
478 <input type="radio" name="group" id="group2" onChange="setMainChartGroup(2);">2
481 <label class="btn btn-primary" data-toggle="tooltip" title="group every 5 points of data">
482 <input type="radio" name="group" id="group5" onChange="setMainChartGroup(5);">5
484 <label class="btn btn-primary" data-toggle="tooltip" title="group every 10 points of data">
485 <input type="radio" name="group" id="group10" onChange="setMainChartGroup(10);">10
487 <label class="btn btn-primary" data-toggle="tooltip" title="group every 15 points of data">
488 <input type="radio" name="group" id="group15" onChange="setMainChartGroup(15);">15
490 <label class="btn btn-primary" data-toggle="tooltip" title="group every 20 points of data">
491 <input type="radio" name="group" id="group20" onChange="setMainChartGroup(20);">20
493 <label class="btn btn-primary" data-toggle="tooltip" title="group every 30 points of data">
494 <input type="radio" name="group" id="group30" onChange="setMainChartGroup(30);">30
496 <label class="btn btn-primary" data-toggle="tooltip" title="group every 45 points of data">
497 <input type="radio" name="group" id="group45" onChange="setMainChartGroup(45);">45
499 <label class="btn btn-primary" data-toggle="tooltip" title="group every 60 points of data">
500 <input type="radio" name="group" id="group60" onChange="setMainChartGroup(60);">60
503 <div class="btn-group btn-group-xs" data-toggle="tooltip" title="maximized ( <span class='glyphicon glyphicon-fullscreen'></span> ) or normal ( <span class='glyphicon glyphicon-resize-small'></span> ) view of the graph" >
504 <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');">
505 <span class="glyphicon glyphicon-fullscreen"></span>
508 <!-- <div class="btn-group btn-group-xs" data-toggle="buttons" >
509 <label class="btn btn-primary" data-toggle="tooltip" title="NORMAL chart size">
510 <input type="radio" name="chartmax" id="chartnormal" onChange="setMainChartMax('normal');">
511 <span class="glyphicon glyphicon-resize-small"></span>
513 <label class="btn btn-primary" data-toggle="tooltip" title="MAXIMIZED chart size">
514 <input type="radio" name="chartmax" id="chartmax" onChange="setMainChartMax('maximized');">
515 <span class="glyphicon glyphicon-fullscreen"></span>
522 </div><!-- /.maingraph -->
527 <div class="container graphs" id="thumbgraphs_container">
528 <div class="allgraphs" id="thumbgraphs">
530 <tr><td id="splash" align="center" style="vertical-align:middle">
532 Welcome to <b>NetData</b>!
534 <span class="glyphicon glyphicon-off"></span>
538 <span class="label label-default">Please wait...</span>
545 <script type='text/javascript'>
548 $(document).ready(function(){
549 document.getElementById('splash').height = $(window).height();
551 $('[data-toggle="tooltip"]').tooltip({'placement': 'top', 'container': 'body', 'html': true});