1 var page_is_visible = 1;
3 var TARGET_THUMB_GRAPH_WIDTH = 500; // thumb charts width will range from 0.5 to 1.5 of that
4 var MINIMUM_THUMB_GRAPH_WIDTH = 400; // thumb chart will generally try to be wider than that
5 var TARGET_THUMB_GRAPH_HEIGHT = 160; // the height of the thumb charts
6 var TARGET_GROUP_GRAPH_HEIGHT = 160;
8 var THUMBS_MAX_TIME_TO_SHOW = 240; // how much time the thumb charts will present?
9 var THUMBS_POINTS_DIVISOR = 3;
10 var THUMBS_STACKED_POINTS_DIVISOR = 4;
12 var GROUPS_MAX_TIME_TO_SHOW = 600; // how much time the group charts will present?
13 var GROUPS_POINTS_DIVISOR = 2;
14 var GROUPS_STACKED_POINTS_DIVISOR = 3;
16 var MAINCHART_MIN_TIME_TO_SHOW = 1200; // how much time the main chart will present by default?
17 var MAINCHART_POINTS_DIVISOR = 2; // how much detailed will the main chart be by default? 1 = finest, higher is faster
18 var MAINCHART_STACKED_POINTS_DIVISOR = 3; // how much detailed will the main chart be by default? 1 = finest, higher is faster
20 var MAINCHART_CONTROL_HEIGHT = 75; // how tall the control chart will be
21 var MAINCHART_CONTROL_DIVISOR = 5; // how much detailed will the control chart be? 1 = finest, higher is faster
22 var MAINCHART_INITIAL_SELECTOR= 20; // 1/20th of the width, this overrides MAINCHART_MIN_TIME_TO_SHOW
24 var CHARTS_REFRESH_LOOP = 50; // delay between chart refreshes
25 var CHARTS_REFRESH_IDLE = 500; // delay between chart refreshes when no chart was ready for refresh the last time
26 var CHARTS_CHECK_NO_FOCUS = 500; // delay to check for visibility when the page has no focus
27 var CHARTS_SCROLL_IDLE = 100; // delay to wait after a page scroll
31 var resize_request = false;
33 function setPresentationNormal(ui) {
34 THUMBS_POINTS_DIVISOR = 3;
35 THUMBS_STACKED_POINTS_DIVISOR = Math.round(THUMBS_POINTS_DIVISOR * 1.5);
36 GROUPS_POINTS_DIVISOR = 2;
37 GROUPS_STACKED_POINTS_DIVISOR = Math.round(GROUPS_POINTS_DIVISOR * 1.5);
38 MAINCHART_POINTS_DIVISOR = 2;
39 MAINCHART_STACKED_POINTS_DIVISOR = Math.round(MAINCHART_POINTS_DIVISOR * 1.5);
41 CHARTS_REFRESH_LOOP = 50;
42 CHARTS_SCROLL_IDLE = 50;
43 resize_request = true;
44 if(ui) $('#presentation_normal').trigger('click');
47 function setPresentationSpeedy(ui) {
48 THUMBS_POINTS_DIVISOR = 10;
49 THUMBS_STACKED_POINTS_DIVISOR = Math.round(THUMBS_POINTS_DIVISOR * 1.5);
50 GROUPS_POINTS_DIVISOR = 8;
51 GROUPS_STACKED_POINTS_DIVISOR = Math.round(GROUPS_POINTS_DIVISOR * 1.5);
52 MAINCHART_POINTS_DIVISOR = 5;
53 MAINCHART_STACKED_POINTS_DIVISOR = Math.round(MAINCHART_POINTS_DIVISOR * 1.5);
55 CHARTS_REFRESH_LOOP = 50;
56 CHARTS_SCROLL_IDLE = 100;
57 resize_request = true;
58 if(ui) $('#presentation_speedy').trigger('click');
61 function setPresentationDetailed(ui) {
62 THUMBS_POINTS_DIVISOR = 1;
63 THUMBS_STACKED_POINTS_DIVISOR = 1;
64 GROUPS_POINTS_DIVISOR = 1;
65 GROUPS_STACKED_POINTS_DIVISOR = 1;
66 MAINCHART_POINTS_DIVISOR = 1;
67 MAINCHART_STACKED_POINTS_DIVISOR = 1;
69 CHARTS_REFRESH_LOOP = 50;
70 CHARTS_SCROLL_IDLE = 50;
71 resize_request = true;
72 if(ui) $('#presentation_detailed').trigger('click');
77 userAgent = navigator.userAgent;
78 return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1;
82 // do stuff with ie-users
83 CHARTS_REFRESH_LOOP=250;
84 CHARTS_SCROLL_IDLE=500;
89 var MODE_GROUP_THUMBS = 3;
90 var mode; // one of the MODE_* values
92 var allCharts = new Array();
95 // html for the main menu
97 var categoriesmainmenu = "";
98 var familiesmainmenu = "";
99 var chartsmainmenu = "";
102 // ------------------------------------------------------------------------
103 // common HTML generation
105 function thumbChartActions(i, c, nogroup) {
107 if(!nogroup) name = c.family;
109 var refinfo = "the chart is drawing ";
110 if(c.group == 1) refinfo += "every single point collected (" + c.update_every + "s each).";
111 else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";
113 var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"" + refinfo + "\">"
114 + "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"
116 + "<div class=\"btn-group btn-group\"><button type=\"button\" class=\"btn btn-default disabled\"><small> " + name + "</small></button>";
120 var ingroup_detail = 0;
122 $.each(allCharts, function(i, d) {
123 if(d.family == c.family) {
125 if(d.isdetail) ingroup_detail++;
130 if(ingroup_detail) hidden = ", including " + ingroup_detail + " charts not shown now";
132 html += "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Show all " + ingroup + " charts in group '" + c.family + "'" + hidden + "\" class=\"btn btn-default\" onclick=\"initGroupGraphs('" + c.family +"');\"><span class=\"glyphicon glyphicon-th-large\"></span></button>";
135 html += "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"show chart '" + c.name + "' in fullscreen\" class=\"btn btn-default\" onclick=\"initMainChartIndex(" + i +");\"><span class=\"glyphicon glyphicon-resize-full\"></span></button>"
136 + "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"set options for chart '" + c.name + "'\" class=\"btn btn-default disabled\" onclick=\"alert('Not implemented yet!');\"><span class=\"glyphicon glyphicon-cog\"></span></button>"
137 + "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"ignore chart '" + c.name + "'\" class=\"btn btn-default\" onclick=\"disableChart(" + i + ");\"><span class=\"glyphicon glyphicon-trash\"></span></button>"
143 function groupChartActions(i, c) {
146 var refinfo = "the chart is drawing ";
147 if(c.group == 1) refinfo += "every single point collected (" + c.update_every + "s each).";
148 else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";
150 var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" data-placement=\"left\" title=\"" + refinfo + "\">"
151 + "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"
154 html += "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"left\" title=\"show chart '" + c.name + "' in fullscreen\" class=\"btn btn-default\" onclick=\"initMainChartIndex(" + i +");\"><span class=\"glyphicon glyphicon-resize-full\"></span></button>"
155 + "<button type=\"button\" data-toggle=\"tooltip\" data-placement=\"left\" title=\"ignore chart '" + c.name + "'\" class=\"btn btn-default\" onclick=\"disableChart(" + i + ");\"><span class=\"glyphicon glyphicon-trash\"></span></button>"
161 function mylog(txt) {
163 $('#logline').html(txt);
166 function chartssort(a, b) {
167 if(a.priority == b.priority) {
168 if(a.name < b.name) return -1;
170 else if(a.priority < b.priority) return -1;
176 // ------------------------------------------------------------------------
177 // MAINGRAPH = fullscreen view of 1 graph
179 // copy the chart c to mainchart
180 // switch to main graphs screen
181 function initMainChart(c) {
182 if(mainchart) cleanThisChart(mainchart);
184 mainchart = $.extend(true, {}, c);
185 mainchart.enabled = true;
186 mainchart.refreshCount = 0;
187 mainchart.last_updated = 0;
188 mainchart.chartOptions.explorer = null;
189 mainchart.chart = null;
191 mainchart.before = 0;
194 mainchart.chartOptions.width = screenWidth();
195 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
196 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
198 mainchart.div = 'maingraph';
199 mainchart.max_time_to_show = (mainchart.last_entry_t - mainchart.first_entry_t) / ( MAINCHART_INITIAL_SELECTOR * mainchart.update_every );
200 if(mainchart.max_time_to_show < MAINCHART_MIN_TIME_TO_SHOW) mainchart.max_time_to_show = MAINCHART_MIN_TIME_TO_SHOW;
201 calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, mainchart.max_time_to_show, 0, ENABLE_CURVE);
203 // copy it to the hidden chart
204 mainchart.hiddenchart = $.extend(true, {}, mainchart);
205 mainchart.hiddenchart.chartOptions.height = MAINCHART_CONTROL_HEIGHT;
206 mainchart.hiddenchart.div = 'maingraph_control';
207 mainchart.hiddenchart.non_zero = 0;
209 // initialize the div
210 showChartIsLoading(mainchart.div, mainchart.name, mainchart.chartOptions.width, mainchart.chartOptions.height);
211 document.getElementById(mainchart.hiddenchart.div).innerHTML = "<table><tr><td align=\"center\" width=\"" + mainchart.hiddenchart.chartOptions.width + "\" height=\"" + mainchart.hiddenchart.chartOptions.height + "\" style=\"vertical-align:middle\"><h4><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>";
212 //showChartIsLoading(mainchart.hiddenchart.div, mainchart.hiddenchart.name, mainchart.hiddenchart.chartOptions.width, mainchart.hiddenchart.chartOptions.height);
214 // set the radio buttons
215 setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
216 setMainChartMax('normal');
218 $('#group' + mainchart.group).trigger('click');
219 setMainChartGroup(mainchart.group, 'no-refresh');
224 function refreshHiddenChart(doNext) {
225 if(refresh_mode == REFRESH_PAUSED && mainchart.hiddenchart.last_updated != 0) {
226 if(typeof doNext == "function") doNext();
230 // is it too soon for a refresh?
231 var now = Date.now();
232 if((now - mainchart.hiddenchart.last_updated) < (mainchart.update_every * 10 * 1000) || (now - mainchart.hiddenchart.last_updated) < (mainchart.hiddenchart.group * mainchart.hiddenchart.update_every * 1000)) {
233 if(typeof doNext == "function") doNext();
237 if(mainchart.dashboard && mainchart.hiddenchart.refreshCount > 50) {
238 mainchart.dashboard.clear();
239 mainchart.control_wrapper.clear();
240 mainchart.hidden_wrapper.clear();
242 mainchart.dashboard = null;
243 mainchart.control_wrapper = null;
244 mainchart.hidden_wrapper = null;
245 mainchart.hiddenchart.last_updated = 0;
248 if(!mainchart.dashboard) {
249 var controlopts = $.extend(true, {}, mainchart.chartOptions, {
251 height: mainchart.hiddenchart.chartOptions.height,
252 chartArea: {'width': '98%'},
253 hAxis: {'baselineColor': 'none', viewWindowMode: 'maximized', gridlines: { count: 0 } },
254 vAxis: {'title': null, gridlines: { count: 0 } },
257 mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
258 mainchart.control_wrapper = new google.visualization.ControlWrapper({
259 controlType: 'ChartRangeFilter',
260 containerId: 'maingraph_control',
262 filterColumnIndex: 0,
264 chartType: mainchart.chartType,
265 chartOptions: controlopts,
266 minRangeSize: (mainchart.max_time_to_show * 1000) / MAINCHART_POINTS_DIVISOR,
270 mainchart.hidden_wrapper = new google.visualization.ChartWrapper({
271 chartType: mainchart.chartType,
272 containerId: 'maingraph_hidden',
274 isStacked: mainchart.chartOptions.isStacked,
275 width: mainchart.hiddenchart.chartOptions.width,
276 height: mainchart.hiddenchart.chartOptions.height,
277 //chartArea: {'height': '80%', 'width': '100%'},
278 //hAxis: {'slantedText': false},
279 //legend: {'position': 'none'}
283 mainchart.hiddenchart.refreshCount = 0;
286 // load the data for the control and the hidden wrappers
287 // calculate the group and points to show for the control chart
288 calculateChartPointsToShow(mainchart.hiddenchart, MAINCHART_CONTROL_DIVISOR, 0, -1, ENABLE_CURVE);
291 url: generateChartURL(mainchart.hiddenchart),
295 .done(function(jsondata) {
296 if(!jsondata || jsondata.length == 0) return;
298 mainchart.control_data = new google.visualization.DataTable(jsondata);
300 if(mainchart.hiddenchart.last_updated == 0) {
301 google.visualization.events.addListener(mainchart.control_wrapper, 'ready', mainchartControlReadyEvent);
302 mainchart.dashboard.bind(mainchart.control_wrapper, mainchart.hidden_wrapper);
304 if(refresh_mode != REFRESH_PAUSED) {
305 // console.log('mainchart.points_to_show: ' + mainchart.points_to_show + ', mainchart.group: ' + mainchart.group + ', mainchart.update_every: ' + mainchart.update_every);
307 var start = now - (mainchart.points_to_show * mainchart.group * mainchart.update_every * 1000);
309 var min = MAINCHART_MIN_TIME_TO_SHOW * 1000;
310 if(end - start < min) start = end - min;
312 mainchart.control_wrapper.setState({range: {
313 start: new Date(start),
321 mainchart.dashboard.draw(mainchart.control_data);
322 mainchart.hiddenchart.last_updated = Date.now();
323 mainchart.hiddenchart.refreshCount++;
326 if(typeof doNext == "function") doNext();
330 function mainchartControlReadyEvent() {
331 google.visualization.events.addListener(mainchart.control_wrapper, 'statechange', mainchartControlStateHandler);
335 function mainchartControlStateHandler() {
336 // setMainChartPlay('pause');
338 var state = mainchart.control_wrapper.getState();
339 mainchart.after = Math.round(state.range.start.getTime() / 1000);
340 mainchart.before = Math.round(state.range.end.getTime() / 1000);
342 calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, mainchart.before - mainchart.after, 0, ENABLE_CURVE);
343 //mylog('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
345 $('#group' + mainchart.group).trigger('click');
346 mainchart.last_updated = 0;
348 if(refresh_mode != REFRESH_PAUSED) pauseGraphs();
351 function initMainChartIndex(i) {
352 if(mode == MODE_GROUP_THUMBS)
353 initMainChart(groupCharts[i]);
355 else if(mode == MODE_THUMBS)
356 initMainChart(allCharts[i]);
359 initMainChart(allCharts[i]);
362 function initMainChartIndexOfMyCharts(i) {
363 initMainChart(allCharts[i]);
366 var last_main_chart_max='normal';
367 function setMainChartMax(m) {
368 if(!mainchart) return;
371 if(last_main_chart_max == 'maximized') m = 'normal';
372 else m = 'maximized';
375 if(m == "maximized") {
376 mainchart.chartOptions.theme = 'maximized';
377 //mainchart.chartOptions.axisTitlesPosition = 'in';
378 //mainchart.chartOptions.legend = {position: 'none'};
379 mainchart.chartOptions.hAxis.title = null;
380 mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';
381 mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';
382 mainchart.chartOptions.chartArea = {'width': '98%', 'height': '100%'};
385 mainchart.chartOptions.hAxis.title = null;
386 mainchart.chartOptions.theme = null;
387 mainchart.chartOptions.hAxis.viewWindowMode = null;
388 mainchart.chartOptions.vAxis.viewWindowMode = null;
389 mainchart.chartOptions.chartArea = {'width': '80%', 'height': '90%'};
391 $('.mainchart_max_button').button(m);
392 last_main_chart_max = m;
393 mainchart.last_updated = 0;
396 function setMainChartGroup(g, norefresh) {
397 if(!mainchart) return;
401 if(!mainchart.before && !mainchart.after)
402 calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, mainchart.max_time_to_show, mainchart.group, ENABLE_CURVE);
404 calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, 0, mainchart.group, ENABLE_CURVE);
407 mainchart.last_updated = 0;
411 var last_main_chart_avg = null;
412 function setMainChartGroupMethod(g, norefresh) {
413 if(!mainchart) return;
416 if(last_main_chart_avg == 'max') g = 'average';
420 mainchart.group_method = g;
422 $('.mainchart_avg_button').button(g);
425 mainchart.last_updated = 0;
428 last_main_chart_avg = g;
431 function setMainChartPlay(p) {
432 if(!mainchart) return;
435 if(refresh_mode != REFRESH_ALWAYS) p = 'play';
440 //mainchart.chartOptions.explorer = null;
442 mainchart.before = 0;
443 calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, mainchart.max_time_to_show, 0, ENABLE_CURVE);
444 $('#group' + mainchart.group).trigger('click');
445 mainchart.last_updated = 0;
446 mainchart.hiddenchart.last_updated = 0;
450 //mainchart.chartOptions.explorer = {
451 // 'axis': 'horizontal',
454 //mainchart.last_updated = 0;
456 //if(!renderChart(mainchart, pauseGraphs))
461 function buttonGlobalPlayPause(p) {
462 if(mode == MODE_MAIN) {
468 if(refresh_mode != REFRESH_ALWAYS) p = 'play';
472 if(p == 'play') playGraphs();
477 // ------------------------------------------------------------------------
480 function screenWidth() {
481 return (($(window).width() * 0.95) - 50);
484 // calculate the proper width for the thumb charts
485 function thumbWidth() {
486 var cwidth = screenWidth();
487 var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
488 if(items < 1) items = 1;
490 if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
492 return Math.round(cwidth / items) - 1;
495 function groupChartSizes() {
496 var s = { width: screenWidth(), height: TARGET_GROUP_GRAPH_HEIGHT };
499 if(groupCharts) $.each(groupCharts, function(i, c) {
500 if(c.enabled) count++;
504 s.width = TARGET_GROUP_GRAPH_HEIGHT;
505 s.height = TARGET_GROUP_GRAPH_HEIGHT;
508 if(s.width < MINIMUM_THUMB_GRAPH_WIDTH) s.width = screenWidth();
509 s.height = ($(window).height() - 130) / count - 10;
512 if(s.height < TARGET_GROUP_GRAPH_HEIGHT)
513 s.height = TARGET_GROUP_GRAPH_HEIGHT;
519 // if the thumb charts need resize in their width, reset them
520 function resizeCharts() {
521 var width = screenWidth();
524 mainchart.chartOptions.width = width;
525 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
526 mainchart.last_updated = 0;
528 mainchart.hidden_wrapper.setOption('width', width);
529 mainchart.control_wrapper.setOption('ui.chartOptions.width', width);
530 mainchart.hiddenchart.chartOptions.width = width;
531 mainchart.hiddenchart.last_updated = 0;
534 width = thumbWidth();
535 $.each(allCharts, function(i, c) {
538 c.chartOptions.width = width;
539 calculateChartPointsToShow(c, c.chartOptions.isStacked?THUMBS_STACKED_POINTS_DIVISOR:THUMBS_POINTS_DIVISOR, THUMBS_MAX_TIME_TO_SHOW, -1, ENABLE_CURVE);
540 showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
541 document.getElementById(c.id + '_thumb_actions_div').innerHTML = thumbChartActions(i, c);
546 if(groupCharts) $.each(groupCharts, function(i, c) {
547 var sizes = groupChartSizes();
551 c.chartOptions.width = sizes.width;
552 c.chartOptions.height = sizes.height;
553 calculateChartPointsToShow(c, c.chartOptions.isStacked?GROUPS_STACKED_POINTS_DIVISOR:GROUPS_POINTS_DIVISOR, GROUPS_MAX_TIME_TO_SHOW, -1, ENABLE_CURVE);
554 showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
555 document.getElementById(c.id + '_group_actions_div').innerHTML = groupChartActions(i, c);
563 window.onresize = function(event) {
564 resize_request = true;
568 // ------------------------------------------------------------------------
569 // Core of the thread refreshing the charts
571 var REFRESH_PAUSED = 0;
572 var REFRESH_ALWAYS = 1;
574 var refresh_mode = REFRESH_PAUSED;
575 var last_refresh = 0;
576 function playGraphs() {
577 mylog('playGraphs()');
578 if(refresh_mode == REFRESH_ALWAYS) return;
580 //mylog('PlayGraphs()');
581 refresh_mode = REFRESH_ALWAYS;
582 $('.mainchart_play_button').button('play');
583 $('.global_play_button').button('play');
585 // check if the thread died due to a javascript error
586 var now = Date.now();
587 if((now - last_refresh) > 60000) {
588 // it died or never started
589 //mylog('It seems the refresh thread died. Restarting it.');
590 renderChartCallback();
594 function pauseGraphs() {
595 mylog('pauseGraphs()');
596 if(refresh_mode == REFRESH_PAUSED) return;
598 refresh_mode = REFRESH_PAUSED;
599 $('.mainchart_play_button').button('pause');
600 $('.global_play_button').button('pause');
604 function checkRefreshThread() {
605 if(interval == null) {
606 interval = setInterval(checkRefreshThread, 2000);
610 var now = Date.now();
611 if(now - last_refresh > 60000) {
612 mylog('Refresh thread died. Restarting it.');
613 renderChartCallback();
617 // refresh the proper chart
618 // this is an internal function.
619 // never call it directly, or new javascript threads will be spawn
621 function renderChartCallback() {
622 last_refresh = Date.now();
624 if(!page_is_visible) {
625 timeout = setTimeout(triggerRefresh, CHARTS_CHECK_NO_FOCUS);
630 mylog('renderChartCallback() resize_request is set');
633 resize_request = false;
634 // refresh_mode = REFRESH_ALWAYS;
637 if(last_user_scroll) {
638 var now = Date.now();
639 if((now - last_user_scroll) >= CHARTS_SCROLL_IDLE) {
640 last_user_scroll = 0;
641 mylog('Scrolling: resuming refresh...');
644 mylog('Scrolling: pausing refresh for ' + (CHARTS_SCROLL_IDLE - (now - last_user_scroll)) + ' ms...');
645 timeout = setTimeout(triggerRefresh, CHARTS_SCROLL_IDLE - (now - last_user_scroll));
650 if(refresh_mode == REFRESH_PAUSED) {
651 if(mode == MODE_MAIN && mainchart.last_updated == 0) {
656 if(mode != MODE_MAIN) {
657 timeout = setTimeout(triggerRefresh, CHARTS_REFRESH_IDLE);
662 if(mode == MODE_THUMBS) timeout = setTimeout(thumbChartsRefreshNext, CHARTS_REFRESH_LOOP);
663 else if(mode == MODE_GROUP_THUMBS) timeout = setTimeout(groupChartsRefreshNext, CHARTS_REFRESH_LOOP);
664 else if(mode == MODE_MAIN) timeout = setTimeout(mainChartRefresh, CHARTS_REFRESH_LOOP);
665 else timeout = setTimeout(triggerRefresh, CHARTS_REFRESH_IDLE);
668 // callback for refreshing the charts later
669 // this is an internal function.
670 // never call it directly, or new javascript threads will be spawn
671 function triggerRefresh() {
672 //mylog('triggerRefresh()');
674 if(!page_is_visible || (refresh_mode == REFRESH_PAUSED && mode != MODE_MAIN)) {
675 last_refresh = Date.now();
676 timeout = setTimeout(triggerRefresh, CHARTS_REFRESH_IDLE);
680 if(mode == MODE_THUMBS) timeout = setTimeout(renderChartCallback, CHARTS_REFRESH_IDLE);
681 else if(mode == MODE_GROUP_THUMBS) timeout = setTimeout(renderChartCallback, CHARTS_REFRESH_IDLE);
682 else if(mode == MODE_MAIN) timeout = setTimeout(renderChartCallback, CHARTS_REFRESH_IDLE);
683 else timeout = setTimeout(triggerRefresh, CHARTS_REFRESH_IDLE);
686 // refresh the main chart
687 // make sure we don't loose the refreshing thread
688 function mainChartRefresh() {
689 //mylog('mainChartRefresh()');
691 if(mode != MODE_MAIN || !mainchart) {
696 if(refresh_mode == REFRESH_PAUSED && mainchart.last_updated != 0) {
697 hiddenChartRefresh();
701 if(!renderChart(mainchart, hiddenChartRefresh))
702 hiddenChartRefresh();
705 function hiddenChartRefresh() {
706 refreshHiddenChart(triggerRefresh);
709 function roundRobinRenderChart(charts, startat) {
710 var refreshed = false;
712 // find a chart to refresh
713 var all = charts.length;
714 var cur = startat + 1;
717 for(count = 0; count < all ; count++, cur++) {
718 if(cur >= all) cur = 0;
720 if(charts[cur].enabled) {
721 refreshed = renderChart(charts[cur], renderChartCallback);
723 mylog('Refreshed: ' + charts[cur].name);
729 if(!refreshed) triggerRefresh();
733 // refresh the thumb charts
734 // make sure we don't loose the refreshing thread
735 var last_thumb_updated = 0;
736 function thumbChartsRefreshNext() {
737 //mylog('thumbChartsRefreshNext()');
739 if(allCharts.length == 0 || mode != MODE_THUMBS) {
744 last_thumb_updated = roundRobinRenderChart(allCharts, last_thumb_updated);
747 // refresh the group charts
748 // make sure we don't loose the refreshing thread
749 var last_group_updated = 0;
750 function groupChartsRefreshNext() {
751 //mylog('groupChartsRefreshNext()');
753 if(!groupCharts || groupCharts.length == 0 || mode != MODE_GROUP_THUMBS) {
754 //mylog('cannot refresh charts');
759 last_group_updated = roundRobinRenderChart(groupCharts, last_group_updated);
763 // ------------------------------------------------------------------------
764 // switch the screen between views
765 // these should be called only from initXXXX()
767 function disableChart(i) {
768 mylog('disableChart(' + i + ')');
773 if(mode == MODE_GROUP_THUMBS && groupCharts) {
774 $.each(groupCharts, function(i, c) {
775 if(c.enabled) count++;
778 if(i < groupCharts.length) chart = groupCharts[i];
780 else if(mode == MODE_THUMBS) {
781 $.each(allCharts, function(i, c) {
782 if(c.enabled) count++;
785 if(i < allCharts.length) chart = allCharts[i];
791 alert('Cannot close the last chart shown.');
796 mylog("request to disable chart " + chart.name);
797 chart.disablethisplease = true;
798 resize_request = true;
801 mylog("no chart to disable");
804 function cleanThisChart(chart, emptydivs) {
805 //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');
807 if(chart.dashboard) {
808 chart.dashboard.clear();
809 chart.dashboard = null;
811 if(chart.control_wrapper) {
812 chart.control_wrapper.clear();
813 chart.control_wrapper = null;
816 if(chart.hidden_wrapper) {
817 chart.hidden_wrapper.clear();
818 chart.hidden_wrapper = null;
821 chart.control_data = null;
824 if(chart.chart) chart.chart.clearChart();
828 var div = document.getElementById(chart.div);
830 div.style.display = 'none';
834 div = document.getElementById(chart.div + "_parent");
836 div.style.display = 'none';
841 //mylog("chart " + chart.name + " cleaned with option " + emptydivs);
844 // cleanup the previously shown charts
845 function cleanupCharts() {
846 // mylog('cleanupCharts()');
848 if(mode != MODE_MAIN && mainchart) {
849 if(mainchart.chart) cleanThisChart(mainchart);
853 if(mode != MODE_GROUP_THUMBS && groupCharts) {
857 // cleanup the disabled charts
858 $.each(allCharts, function(i, c) {
859 if(c.disablethisplease && c.enabled) {
860 cleanThisChart(c, 'emptydivs');
861 c.disablethisplease = false;
863 resize_request = true;
864 mylog("removed thumb chart " + c.name + " removed");
868 if(groupCharts) $.each(groupCharts, function(i, c) {
869 if(c.disablethisplease && c.enabled) {
870 cleanThisChart(c, 'emptydivs');
871 c.disablethisplease = false;
873 resize_request = true;
874 mylog("removed group chart " + c.name + " removed");
878 // we never cleanup the main chart
881 function updateUI() {
882 $('[data-toggle="tooltip"]').tooltip({'container': 'body', 'html': true});
884 $('[data-spy="scroll"]').each(function () {
885 var $spy = $(this).scrollspy('refresh')
889 var thumbsScrollPosition = null;
890 function switchToMainGraph() {
891 //mylog('switchToMainGraph()');
893 if(!mainchart) return;
895 if(!groupCharts) thumbsScrollPosition = window.pageYOffset;
897 document.getElementById('maingraph_container').style.display = 'block';
898 document.getElementById('thumbgraphs_container').style.display = 'none';
899 document.getElementById('groupgraphs_container').style.display = 'none';
900 document.getElementById('splash_container').style.display = 'none';
902 document.getElementById("main_menu_div").innerHTML = "<ul class=\"nav navbar-nav\"><li><a href=\"javascript:switchToThumbGraphs();\"><span class=\"glyphicon glyphicon-circle-arrow-left\"></span> Back to Dashboard</a></li><li class=\"active\"><a href=\"#\">" + mainchart.name + "</a></li>" + familiesmainmenu + chartsmainmenu + "</ul>" ;
904 window.scrollTo(0, 0);
911 function switchToThumbGraphs() {
912 //mylog('switchToThumbGraphs()');
914 document.getElementById('maingraph_container').style.display = 'none';
915 document.getElementById('thumbgraphs_container').style.display = 'block';
916 document.getElementById('groupgraphs_container').style.display = 'none';
917 document.getElementById('splash_container').style.display = 'none';
919 document.getElementById("main_menu_div").innerHTML = mainmenu;
921 if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);
929 function switchToGroupGraphs() {
930 //mylog('switchToGroupGraphs()');
932 if(!groupCharts) return;
934 if(!mainchart) thumbsScrollPosition = window.pageYOffset;
936 document.getElementById('maingraph_container').style.display = 'none';
937 document.getElementById('thumbgraphs_container').style.display = 'none';
938 document.getElementById('groupgraphs_container').style.display = 'block';
939 document.getElementById('splash_container').style.display = 'none';
941 document.getElementById("main_menu_div").innerHTML = "<ul class=\"nav navbar-nav\"><li><a href=\"javascript:switchToThumbGraphs();\"><span class=\"glyphicon glyphicon-circle-arrow-left\"></span> Back to Dashboard</a></li><li class=\"active\"><a href=\"#\">" + groupCharts[0].family + "</a></li>" + familiesmainmenu + chartsmainmenu + "</ul>";
943 window.scrollTo(0, 0);
945 mode = MODE_GROUP_THUMBS;
951 // ------------------------------------------------------------------------
954 var groupCharts = null;
955 function initGroupGraphs(group) {
958 if(groupCharts) clearGroupGraphs();
959 groupCharts = new Array();
962 $.each(allCharts, function(i, c) {
963 if(c.family == group) {
964 groupCharts[count] = [];
965 groupCharts[count] = $.extend(true, {}, c);
966 groupCharts[count].div += "_group";
967 groupCharts[count].enabled = true;
968 groupCharts[count].chart = null;
969 groupCharts[count].last_updated = 0;
973 groupCharts.sort(chartssort);
975 var sizes = groupChartSizes();
978 $.each(groupCharts, function(i, c) {
979 c.chartOptions.width = sizes.width;
980 c.chartOptions.height = sizes.height;
981 c.chartOptions.chartArea.width = '85%';
982 c.chartOptions.chartArea.height = '90%';
983 c.chartOptions.hAxis.textPosition = 'in';
984 c.chartOptions.hAxis.viewWindowMode = 'maximized';
985 c.chartOptions.hAxis.textStyle = { "fontSize": 9 };
986 c.chartOptions.vAxis.textStyle = { "fontSize": 9 };
987 c.chartOptions.fontSize = 11;
988 c.chartOptions.titlePosition = 'in';
989 c.chartOptions.tooltip = { "textStyle": { "fontSize": 9 } };
990 c.chartOptions.legend = { "textStyle": { "fontSize": 9 } };
992 calculateChartPointsToShow(c, c.chartOptions.isStacked?GROUPS_STACKED_POINTS_DIVISOR:GROUPS_POINTS_DIVISOR, GROUPS_MAX_TIME_TO_SHOW, -1, ENABLE_CURVE);
994 groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td width='" + sizes.width + "'><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div></td><td id=\"" + c.id + "_group_actions_div\" align=\"center\">" + groupChartActions(i, c) + "</td></tr><tr><td width='15'></td></tr></table></div>";
995 //groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div>";
999 document.getElementById("groupgraphs").innerHTML = groupbody;
1000 switchToGroupGraphs();
1003 function clearGroupGraphs() {
1004 if(groupCharts && groupCharts.length) {
1005 $.each(groupCharts, function(i, c) {
1006 cleanThisChart(c, 'emptydivs');
1012 document.getElementById("groupgraphs").innerHTML = "";
1016 // ------------------------------------------------------------------------
1017 // Global entry point
1018 // initialize the thumb charts
1020 var last_user_scroll = 0;
1022 // load the charts from the server
1023 // generate html for the thumbgraphs to support them
1024 function initCharts() {
1025 setPresentationNormal(1);
1027 var width = thumbWidth();
1028 var height = TARGET_THUMB_GRAPH_HEIGHT;
1030 window.onscroll = function (e) {
1031 last_user_scroll = Date.now();
1032 mylog('Scrolling: detected');
1035 loadCharts(null, function(all) {
1036 allCharts = all.charts;
1038 if(allCharts == null || allCharts.length == 0) {
1039 alert("Cannot load data from server.");
1043 var thumbsContainer = document.getElementById("thumbgraphs");
1044 if(!thumbsContainer) {
1045 alert("Cannot find the thumbsContainer");
1049 allCharts.sort(chartssort);
1051 document.getElementById('hostname_id').innerHTML = all.hostname;
1052 document.title = all.hostname;
1054 // create an array for grouping all same-type graphs together
1056 var categories = new Array();
1057 var families = new Array();
1058 var chartslist = new Array();
1059 $.each(allCharts, function(i, c) {
1062 chartslist.push({name: c.name, type: c.type, id: i});
1064 dimensions += c.dimensions.length;
1065 c.chartOptions.width = width;
1066 c.chartOptions.height = height;
1068 // calculate how many point to show for each chart
1069 //c.points_to_show = Math.round(c.entries / c.group) - 1;
1070 // show max 10 mins of data
1071 //if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;
1072 calculateChartPointsToShow(c, c.chartOptions.isStacked?THUMBS_STACKED_POINTS_DIVISOR:THUMBS_POINTS_DIVISOR, THUMBS_MAX_TIME_TO_SHOW, -1, ENABLE_CURVE);
1075 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 id=\"" + c.id + "_thumb_actions_div\" align=\"center\">"
1076 + thumbChartActions(i, c)
1077 + "</td></tr><tr><td height='15'></td></tr></table></div>";
1079 // find the categories object for this type
1080 for(j = 0; j < categories.length ;j++) {
1081 if(categories[j].name == c.type) {
1082 categories[j].html += h;
1083 categories[j].count++;
1088 if(j == categories.length)
1089 categories.push({name: c.type, title: c.category, description: '', priority: c.categoryPriority, count: 1, glyphicon: c.glyphicon, html: h});
1092 // find the families object for this type
1093 for(j = 0; j < families.length ;j++) {
1094 if(families[j].name == c.family) {
1095 families[j].count++;
1100 if(j == families.length)
1101 families.push({name: c.family, count: 1});
1104 document.getElementById('server_summary_id').innerHTML = "<small>NetData server at <b>" + all.hostname + "</b> is maintaining <b>" + allCharts.length + "</b> charts, having <b>" + dimensions + "</b> dimensions (by default with <b>" + all.history + "</b> entries each), which are updated every <b>" + all.update_every + "s</b>, using a total of <b>" + (Math.round(all.memory * 10 / 1024 / 1024) / 10) + " MB</b> for the round robin database.</small>";
1106 $.each(categories, function(i, a) {
1107 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>";
1110 function categoriessort(a, b) {
1111 if(a.priority < b.priority) return -1;
1114 categories.sort(categoriessort);
1116 function familiessort(a, b) {
1117 if(a.name < b.name) return -1;
1120 families.sort(familiessort);
1122 function chartslistsort(a, b) {
1123 if(a.name < b.name) return -1;
1126 chartslist.sort(chartslistsort);
1128 // combine all the htmls into one
1129 var allcategories = "<table width=\"100%\">";
1130 mainmenu = '<ul class="nav navbar-nav">';
1132 categoriesmainmenu = '<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class=\"glyphicon glyphicon-fire\"></span> Dashboard Sections <b class="caret"></b></a><ul class="dropdown-menu">';
1133 $.each(categories, function(i, a) {
1134 allcategories += a.html;
1135 categoriesmainmenu += "<li><a href=\"#" + a.name + "\">" + a.title + "</a></li>";
1137 categoriesmainmenu += "</ul></li>";
1138 allcategories += "</table>";
1140 familiesmainmenu = '<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class=\"glyphicon glyphicon-th-large\"></span> Chart Families <b class="caret"></b></a><ul class="dropdown-menu">';
1141 $.each(families, function(i, a) {
1142 familiesmainmenu += "<li><a href=\"javascript:initGroupGraphs('" + a.name + "');\">" + a.name + " <span class=\"badge pull-right\">" + a.count + "</span></a></li>";
1144 familiesmainmenu += "</ul></li>";
1146 chartsmainmenu = '<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class=\"glyphicon glyphicon-resize-full\"></span> All Charts <b class="caret"></b></a><ul class="dropdown-menu">';
1147 $.each(chartslist, function(i, a) {
1148 chartsmainmenu += "<li><a href=\"javascript:initMainChartIndexOfMyCharts('" + a.id + "');\">" + a.name + "</a></li>";
1150 chartsmainmenu += "</ul></li>";
1152 mainmenu += categoriesmainmenu;
1153 mainmenu += familiesmainmenu;
1154 mainmenu += chartsmainmenu;
1155 mainmenu += '<li role="presentation" class="disabled" style="display: none;"><a href="#" id="logline"></a></li></ul>';
1157 thumbsContainer.innerHTML = allcategories;
1158 switchToThumbGraphs();
1159 checkRefreshThread();
1163 $(window).blur(function() {
1164 page_is_visible = 0;
1165 mylog('Lost Focus!');
1168 $(window).focus(function() {
1169 page_is_visible = 1;
1170 mylog('Focus restored!');
1173 // Set a callback to run when the Google Visualization API is loaded.
1174 google.setOnLoadCallback(initCharts);