1 // fix old IE bug with console
2 if(!window.console){ window.console = {log: function(){} }; }
4 // Load the Visualization API and the piechart package.
5 google.load('visualization', '1.1', {'packages':['corechart']});
6 //google.load('visualization', '1.1', {'packages':['controls']});
8 function canChartBeRefreshed(chart) {
10 if(!chart.enabled) return false;
12 // is there something selected on the chart?
13 if(chart.chart && chart.chart.getSelection()[0]) return false;
15 // is it too soon for a refresh?
17 if((now - chart.last_updated) < (chart.group * chart.update_every * 1000)) return false;
19 // is the chart in the visible area?
20 //console.log(chart.div);
21 if($('#' + chart.div).visible(true) == false) return false;
27 function generateChartURL(chart) {
30 url += chart.points_to_show?chart.points_to_show.toString():"all";
32 url += chart.group?chart.group.toString():"1";
34 url += chart.group_method?chart.group_method:"average";
36 url += chart.after?chart.after.toString():"0";
38 url += chart.before?chart.before.toString():"0";
40 url += chart.non_zero?"nonzero":"all";
46 function renderChart(chart, doNext) {
47 if(canChartBeRefreshed(chart) == false) return false;
50 url: generateChartURL(chart),
54 .done(function(jsondata) {
55 if(!jsondata || jsondata.length == 0) return;
56 chart.jsondata = jsondata;
58 // Create our data table out of JSON data loaded from server.
59 chart.datatable = new google.visualization.DataTable(chart.jsondata);
60 //console.log(chart.datatable);
62 // cleanup once every 50 updates
63 // we don't cleanup on every single, to avoid firefox flashing effect
64 if(chart.chart && chart.refreshCount > 50) {
65 chart.chart.clearChart();
67 chart.refreshCount = 0;
70 // Instantiate and draw our chart, passing in some options.
72 // console.log('Creating new chart for ' + chart.url);
73 if(chart.chartType == "LineChart")
74 chart.chart = new google.visualization.LineChart(document.getElementById(chart.div));
76 chart.chart = new google.visualization.AreaChart(document.getElementById(chart.div));
80 chart.chart.draw(chart.datatable, chart.chartOptions);
82 chart.last_updated = Date.now();
84 else console.log('Cannot create chart for ' + chart.url);
87 // to avoid an infinite loop, let's assume it was refreshed
88 if(chart.chart) chart.chart.clearChart();
90 chart.refreshCount = 0;
91 showChartIsLoading(chart.div, chart.name, chart.chartOptions.width, chart.chartOptions.height, "failed to refresh");
92 chart.last_updated = Date.now();
95 if(typeof doNext == "function") doNext();
101 function chartIsLoadingHTML(name, width, height, message)
103 return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>" + name + "<br/><br/><span class=\"label label-default\">" + (message?message:"loading chart...") + "</span></h4></td></tr></table>";
106 function showChartIsLoading(id, name, width, height, message) {
107 document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height, message);
110 // calculateChartPointsToShow
111 // calculate the chart group and point to show properties.
112 // This uses the chartOptions.width and the supplied divisor
113 // to calculate the propers values so that the chart will
114 // be visually correct (not too much or too less points shown).
117 // divisor = when calculating screen points, divide width with this
118 // if all screen points are used the chart will be overcrowded
120 // maxtime = the maxtime to show
121 // the default is to render all the server data
122 // group = the required grouping on points
123 // if undefined or negative, any calculated value will be used
124 // if zero, one of 1,2,5,10,15,20,30,45,60 will be used
126 function calculateChartPointsToShow(c, divisor, maxtime, group, enable_curve) {
127 // console.log('calculateChartPointsToShow( c = ' + c.id + ', divisor = ' + divisor + ', maxtime = ' + maxtime + ', group = ' + group + ' )');
129 if(!divisor) divisor = 2;
131 var before = c.before?c.before:Date.now() / 1000;
132 var after = c.after?c.after:c.first_entry_t;
134 var dt = before - after;
135 if(dt > c.entries * c.update_every) dt = c.entries * c.update_every;
137 // console.log('chart ' + c.id + ' internal duration is ' + dt + ' secs, requested maxtime is ' + maxtime + ' secs');
139 if(!maxtime) maxtime = c.entries * c.update_every;
142 var data_points = Math.round(dt / c.update_every);
143 if(!data_points) data_points = 100;
145 var screen_points = Math.round(c.chartOptions.width / divisor);
146 if(!screen_points) screen_points = 100;
148 // console.log('screen_points = ' + screen_points + ', data_points = ' + data_points + ', divisor = ' + divisor);
150 if(group == undefined || group <= 0) {
151 if(screen_points > data_points) {
153 c.points_to_show = data_points;
154 // console.log("rendering at full detail (group = " + c.group + ", points_to_show = " + c.points_to_show + ')');
157 c.group = Math.round(data_points / screen_points);
159 if(c.group > 60) c.group = 90;
160 else if(c.group > 45) c.group = 60;
161 else if(c.group > 30) c.group = 45;
162 else if(c.group > 20) c.group = 30;
163 else if(c.group > 15) c.group = 20;
164 else if(c.group > 10) c.group = 15;
165 else if(c.group > 5) c.group = 10;
166 else if(c.group > 4) c.group = 5;
167 else if(c.group > 3) c.group = 4;
168 else if(c.group > 2) c.group = 3;
169 else if(c.group > 1) c.group = 2;
172 c.points_to_show = Math.round(data_points / c.group);
173 // console.log("rendering adaptive (group = " + c.group + ", points_to_show = " + c.points_to_show + ')');
178 c.points_to_show = Math.round(data_points / group);
179 // console.log("rendering with supplied group (group = " + c.group + ", points_to_show = " + c.points_to_show + ')');
182 // console.log("final configuration (group = " + c.group + ", points_to_show = " + c.points_to_show + ')');
184 // make sure the line width is not congesting the chart
185 if(c.chartType == 'LineChart') {
186 if(c.points_to_show > c.chartOptions.width / 3) {
187 c.chartOptions.lineWidth = 1;
191 c.chartOptions.lineWidth = 2;
194 else if(c.chartType == 'AreaChart') {
195 if(c.points_to_show > c.chartOptions.width / 2)
196 c.chartOptions.lineWidth = 0;
198 c.chartOptions.lineWidth = 1;
201 // do not render curves when we don't have at
202 // least 2 twice the space per point
203 if(!enable_curve || c.points_to_show > (c.chartOptions.width * c.chartOptions.lineWidth / 2) )
204 c.chartOptions.curveType = 'none';
206 c.chartOptions.curveType = c.default_curveType;
208 var hpoints = Math.round(maxtime / 30);
209 if(hpoints > 10) hpoints = 10;
210 c.chartOptions.hAxis.gridlines.count = hpoints;
215 // fetches all the charts from the server
216 // returns an array of objects, containing all the server metadata
217 // (not the values of the graphs - just the info about the graphs)
219 function loadCharts(base_url, doNext) {
221 url: ((base_url)?base_url:'') + '/all.json',
225 .done(function(json) {
226 $.each(json.charts, function(i, value) {
227 json.charts[i].div = json.charts[i].name.replace(/\./g,"_");
228 json.charts[i].div = json.charts[i].div.replace(/\-/g,"_");
229 json.charts[i].div = json.charts[i].div + "_div";
231 // make sure we have the proper values
232 if(!json.charts[i].update_every) chart.update_every = 1;
233 if(base_url) json.charts[i].url = base_url + json.charts[i].url;
235 json.charts[i].last_updated = 0;
236 json.charts[i].thumbnail = false;
237 json.charts[i].refreshCount = 0;
238 json.charts[i].group = 1;
239 json.charts[i].points_to_show = 0; // all
240 json.charts[i].group_method = "max";
242 json.charts[i].chart = null;
243 json.charts[i].jsondata = null;
244 json.charts[i].datatable = null;
245 json.charts[i].before = 0;
246 json.charts[i].after = 0;
248 // if it is detail, disable it by default
249 if(json.charts[i].isdetail) json.charts[i].enabled = false;
251 // set default chart options
252 json.charts[i].chartOptions = {
256 title: json.charts[i].title,
259 // title: "Time of Day",
260 // format:'HH:mm:ss',
261 viewWindowMode: 'maximized',
272 title: json.charts[i].units,
273 viewWindowMode: 'pretty',
288 focusTarget: 'category',
295 titlePosition: 'out',
308 json.charts[i].default_curveType = 'none';
310 // set the chart type
311 switch(json.charts[i].chart_type) {
313 json.charts[i].chartType = "AreaChart";
314 json.charts[i].chartOptions.isStacked = false;
315 json.charts[i].chartOptions.areaOpacity = 0.3;
317 json.charts[i].chartOptions.vAxis.viewWindowMode = 'maximized';
318 json.charts[i].non_zero = 0;
320 json.charts[i].group = 3;
324 json.charts[i].chartType = "AreaChart";
325 json.charts[i].chartOptions.isStacked = true;
326 json.charts[i].chartOptions.areaOpacity = 0.85;
327 json.charts[i].chartOptions.lineWidth = 1;
328 json.charts[i].group_method = "average";
329 json.charts[i].non_zero = 1;
331 json.charts[i].chartOptions.vAxis.viewWindowMode = 'maximized';
332 json.charts[i].chartOptions.vAxis.minValue = null;
333 json.charts[i].chartOptions.vAxis.maxValue = null;
335 json.charts[i].group = 10;
340 json.charts[i].chartType = "LineChart";
341 json.charts[i].chartOptions.lineWidth = 2;
342 json.charts[i].non_zero = 0;
344 json.charts[i].default_curveType = 'function';
346 json.charts[i].group = 3;
350 // the category name, and other options, per type
351 switch(json.charts[i].type) {
353 json.charts[i].category = "System";
354 json.charts[i].categoryPriority = 10;
355 json.charts[i].glyphicon = "glyphicon-dashboard";
357 if(json.charts[i].id == "system.cpu" || json.charts[i].id == "system.ram") {
358 json.charts[i].chartOptions.vAxis.minValue = 0;
359 json.charts[i].chartOptions.vAxis.maxValue = 100;
362 json.charts[i].chartOptions.vAxis.minValue = -0.1;
363 json.charts[i].chartOptions.vAxis.maxValue = 0.1;
368 json.charts[i].category = "Network";
369 json.charts[i].categoryPriority = 20;
370 json.charts[i].glyphicon = "glyphicon-transfer";
372 // disable IFB and net.lo devices by default
373 if((json.charts[i].id.substring(json.charts[i].id.length - 4, json.charts[i].id.length) == "-ifb")
374 || json.charts[i].id == "net.lo")
375 json.charts[i].enabled = false;
379 json.charts[i].category = "Quality of Service";
380 json.charts[i].categoryPriority = 30;
381 json.charts[i].glyphicon = "glyphicon-random";
385 json.charts[i].category = "IP Virtual Server";
386 json.charts[i].categoryPriority = 40;
387 json.charts[i].glyphicon = "glyphicon-sort";
391 json.charts[i].category = "Netfilter";
392 json.charts[i].categoryPriority = 50;
393 json.charts[i].glyphicon = "glyphicon-cloud";
397 json.charts[i].category = "IPv4";
398 json.charts[i].categoryPriority = 60;
399 json.charts[i].glyphicon = "glyphicon-globe";
403 json.charts[i].category = "Memory";
404 json.charts[i].categoryPriority = 70;
405 json.charts[i].glyphicon = "glyphicon-dashboard";
409 json.charts[i].category = "CPU";
410 json.charts[i].categoryPriority = 80;
411 json.charts[i].glyphicon = "glyphicon-dashboard";
413 if(json.charts[i].id.substring(0, 7) == "cpu.cpu") {
414 json.charts[i].chartOptions.vAxis.minValue = 0;
415 json.charts[i].chartOptions.vAxis.maxValue = 100;
420 json.charts[i].category = "Disks";
421 json.charts[i].categoryPriority = 90;
422 json.charts[i].glyphicon = "glyphicon-hdd";
426 json.charts[i].category = "NFS Server";
427 json.charts[i].categoryPriority = 100;
428 json.charts[i].glyphicon = "glyphicon-hdd";
432 json.charts[i].category = "UPS";
433 json.charts[i].categoryPriority = 110;
434 json.charts[i].glyphicon = "glyphicon-dashboard";
438 json.charts[i].category = "NetData";
439 json.charts[i].categoryPriority = 3000;
440 json.charts[i].glyphicon = "glyphicon-thumbs-up";
444 json.charts[i].category = "Apps";
445 json.charts[i].categoryPriority = 4000;
446 json.charts[i].glyphicon = "glyphicon-tasks";
450 json.charts[i].category = "Squid";
451 json.charts[i].categoryPriority = 5000;
452 json.charts[i].glyphicon = "glyphicon-link";
456 json.charts[i].category = "Examples";
457 json.charts[i].categoryPriority = 9000;
458 json.charts[i].glyphicon = "glyphicon-search";
462 json.charts[i].category = json.charts[i].type;
463 json.charts[i].categoryPriority = 1000;
464 json.charts[i].glyphicon = "glyphicon-search";
469 if(typeof doNext == "function") doNext(json);
472 if(typeof doNext == "function") doNext();
476 // jquery visible plugin
480 * Copyright 2012, Digital Fusion
481 * Licensed under the MIT license.
482 * http://teamdf.com/jquery-plugins/license/
484 * @author Sam Sehnert
485 * @desc A small plugin that checks whether elements are within
486 * the user visible viewport of a web browser.
487 * only accounts for vertical position, not horizontal.
489 $.fn.visible = function(partial){
493 viewTop = $w.scrollTop(),
494 viewBottom = viewTop + $w.height(),
495 _top = $t.offset().top,
496 _bottom = _top + $t.height(),
497 compareTop = partial === true ? _bottom : _top,
498 compareBottom = partial === true ? _top : _bottom;
500 return ((compareBottom <= viewBottom) && (compareTop >= viewTop));