]> arthur.barton.de Git - netdata.git/commitdiff
optimized for loading speed
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 24 Apr 2014 22:09:47 +0000 (01:09 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 24 Apr 2014 22:09:47 +0000 (01:09 +0300)
web/index.html
web/index.js [new file with mode: 0755]

index cc95189e6cf6931ed8493bc71664c2022bfcc3db..6d18eb214c73bab74cd7b131120184c706b5c08f 100644 (file)
  
        <title>NetData</title>
 
-       <!-- Google AJAX API -->
-       <script type="text/javascript" src="https://www.google.com/jsapi"></script>
-       <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
-
-       <!-- Bootstrap -->
+       <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
-       <!-- <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css"> -->
-       <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
        <link href="/file/theme.css" rel="stylesheet">
-
-       <!-- NetData -->
-       <script type="text/javascript" src="/file/netdata.js"></script>
-       <script type="text/javascript" src="/file/jquery.visible.js"></script>
-       <script type="text/javascript">
-       
-       // Set a callback to run when the Google Visualization API is loaded.
-       google.setOnLoadCallback(initCharts);
-       
-       var TARGET_THUMB_GRAPH_WIDTH = 500;             // thumb charts width will range from 0.5 to 1.5 of that
-       var MINIMUM_THUMB_GRAPH_WIDTH = 400;    // thumb chart will generally try to be wider than that
-       var TARGET_THUMB_GRAPH_HEIGHT = 220;    // the height of the thumb charts
-       var THUMBS_MAX_TIME_TO_SHOW = 600;              // how much time the thumb charts will present?
-
-       var MAINCHART_MAX_TIME_TO_SHOW = 600;   // how much time the main chart will present by default?
-       var MAINCHART_POINTS_DIVISOR = 10;              // how much detailed will the main chart be by default? 1 = finest, higher is faster
-       var MAINCHART_CONTROL_HEIGHT = 75;              // how tall the control chart will be
-       var MAINCHART_CONTROL_DIVISOR = 2;              // how much detailed will the control chart be? 1 = finest, higher is faster
-
-       var MODE_THUMBS = 1;
-       var MODE_MAIN = 2;
-       var MODE_GROUP_THUMBS = 3;
-       var mode; // one of the MODE_* values
-
-       var mycharts = new Array();
-       var mainchart;
-
-       // html for the main menu
-       var mainmenu = "";
-
-
-       // ------------------------------------------------------------------------
-       // common HTML generation
-
-       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>"; }
-
-       function showChartIsLoading(id, name, width, height) {
-               //mylog('adding loading chart html in div with id ' + id);
-               document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height);
-       }
-
-       function thumbChartActions(i, c, nogroup) {
-               var name = c.name;
-               if(!nogroup) name = c.group_tag;
-
-               var refinfo = "the chart is drawing ";
-               if(c.group == 1) refinfo += "every single point collected.";
-               else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";
-
-               var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" title=\"" + refinfo + "\">"
-               +               "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"
-               +       "</div>"
-               +       "<div class=\"btn-group btn-group\"><button type=\"button\" class=\"btn btn-default disabled\"><small>&nbsp;&nbsp; " + name + "</small></button>";
-
-               if(!nogroup) {
-                       var ingroup = 0;
-                       var ingroup_detail = 0;
-
-                       $.each(mycharts, function(i, d) {
-                               if(d.group_tag == c.group_tag) {
-                                       ingroup++;
-                                       if(d.isdetail) ingroup_detail++;
-                               }
-                       });
-
-                       var hidden = "";
-                       if(ingroup_detail) hidden = ", including " + ingroup_detail + " charts not shown now";
-
-                       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>";
-               }
-
-               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>"
-               +               "<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>"
-               +               "<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>"
-               +       "</div>";
-
-               return html;
-       }
-
-       function mylog(txt) {
-               console.log(txt);
-       }
-
-       function chartssort(a, b) {
-               if(a.userpriority < b.userpriority) return -1;
-               return 1;
-       }
-
-
-       // ------------------------------------------------------------------------
-       // MAINGRAPH = fullscreen view of 1 graph
-
-       function calculateChartGroup(c, divisor, maxtime, group) {
-               var before = c.before?c.before:new Date().getTime() / 1000;
-               var after = c.after?c.after:c.first_entry_t;
-
-               var dt = before - after;
-               if(dt > c.entries * c.update_every) dt = c.entries * c.update_every;
-
-               if(maxtime) dt = maxtime;
-
-               var data_points = Math.round(dt / c.update_every);
-               var screen_points = Math.round(c.chartOptions.width / divisor);
-               //mylog('screen = ' + screen_points + ', data = ' + data_points + ', divisor = ' + divisor);
-
-               if(group <= 0) {
-                       if(screen_points > data_points) {
-                               c.group = 1;
-                               c.points_to_show = data_points;
-                               //mylog("rendering at full detail");
-                       }
-                       else {
-                               c.group = Math.round(data_points / screen_points);
-
-                               if(group >= 0) {
-                                            if(c.group > 60) c.group = 60;
-                                       else if(c.group > 45) c.group = 45;
-                                       else if(c.group > 30) c.group = 30;
-                                       else if(c.group > 20) c.group = 20;
-                                       else if(c.group > 15) c.group = 15;
-                                       else if(c.group > 10) c.group = 10;
-                                       else if(c.group > 5) c.group = 5;
-                                       else if(c.group > 2) c.group = 2;
-                                       else c.group = 1;
-                               }
-
-                               c.points_to_show = Math.round(data_points / c.group);
-                               //mylog("rendering adaptive");
-                       }
-               }
-               else {
-                       c.group = group;
-                       c.points_to_show = Math.round(data_points / group);
-                       //mylog("rendering with given group");
-               }
-               //mylog('group = ' + c.group + ', points = ' + c.points_to_show);
-
-               if(mainchart.chartType == 'LineChart') {
-                       if(mainchart.group <= 2) mainchart.chartOptions.lineWidth = 1;
-                       else mainchart.chartOptions.lineWidth = 2;
-               }
-       }
-
-       // copy the chart c to mainchart
-       // switch to main graphs screen
-       function initMainChart(c) {
-               if(mainchart) cleanThisChart(mainchart);
-
-               mainchart = $.extend(true, {}, c);
-               mainchart.refreshCount = 0;
-               mainchart.last_updated = 0;
-               mainchart.chartOptions.explorer = null;
-               mainchart.chart = null;
-
-               mainchart.chartOptions.width = screenWidth();
-               mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
-               if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
-               //mainchart.chartOptions.chartArea = {'width': '80%'};
-
-               mainchart.div = 'maingraph';
-               calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
-
-               // copy it to the hidden chart
-               mainchart.hiddenchart = $.extend(true, {}, mainchart);
-               mainchart.hiddenchart.chartOptions.height = MAINCHART_CONTROL_HEIGHT;
-               mainchart.hiddenchart.div = 'maingraph_control';
-
-               // initialize the div
-               showChartIsLoading(mainchart.div, mainchart.name, mainchart.chartOptions.width, mainchart.chartOptions.height);
-
-               // set the radio buttons
-               setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
-               setMainChartMax('normal');
-
-               $('#group' + mainchart.group).trigger('click');
-               setMainChartGroup(mainchart.group, 'no-refresh');
-
-               switchToMainGraph();
-       }
-
-       function refreshHiddenChart(doNext) {
-               if(refresh_mode == REFRESH_PAUSED && mainchart.hiddenchart.last_updated != 0) {
-                       if(typeof doNext == "function") doNext();
-                       return;
-               }
-
-               // is it too soon for a refresh?
-               var now = new Date().getTime();
-               if((now - mainchart.hiddenchart.last_updated) < (mainchart.hiddenchart.group * mainchart.hiddenchart.update_every * 1000)) {
-                       if(typeof doNext == "function") doNext();
-                       return;
-               }
-
-               if(mainchart.dashboard && mainchart.hiddenchart.refreshCount > 50) {
-                       mainchart.dashboard.clear();
-                       mainchart.control_wrapper.clear();
-                       mainchart.hidden_wrapper.clear();
-
-                       mainchart.dashboard = null;
-                       mainchart.control_wrapper = null;
-                       mainchart.hidden_wrapper = null;
-                       mainchart.hiddenchart.last_updated = 0;
-               }
-
-               if(!mainchart.dashboard) {
-                       var controlopts = $.extend(true, {}, mainchart.chartOptions, {
-                               lineWidth: 1,
-                               height: mainchart.hiddenchart.chartOptions.height,
-                               chartArea: {'width': '98%'},
-                               hAxis: {'baselineColor': 'none'},
-                               vAxis: {'title': null},
-                       });
-
-                       mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
-                       mainchart.control_wrapper = new google.visualization.ControlWrapper({
-                               controlType: 'ChartRangeFilter',
-                               containerId: 'maingraph_control',
-                               options: {
-                                       filterColumnIndex: 0,
-                                       ui: {
-                                               chartType: mainchart.chartType,
-                                               chartOptions: controlopts,
-                                               minRangeSize: (MAINCHART_MAX_TIME_TO_SHOW * 1000 * mainchart.update_every) / MAINCHART_POINTS_DIVISOR,
-                                       }
-                               },
-                       });
-                       mainchart.hidden_wrapper = new google.visualization.ChartWrapper({
-                               chartType: mainchart.chartType,
-                               containerId: 'maingraph_hidden',
-                               options: {
-                                       isStacked: mainchart.chartOptions.isStacked,
-                                       width: mainchart.hiddenchart.chartOptions.width,
-                                       height: mainchart.hiddenchart.chartOptions.height,
-                                       //chartArea: {'height': '80%', 'width': '100%'},
-                                       //hAxis: {'slantedText': false},
-                                       //legend: {'position': 'none'}
-                               },
-                       });
-
-                       mainchart.hiddenchart.refreshCount = 0;
-               }
-
-               // load the data for the control and the hidden wrappers
-               // calculate the group and points to show for the control chart
-               calculateChartGroup(mainchart.hiddenchart, MAINCHART_CONTROL_DIVISOR, 0, -1);
-
-               $.ajax({
-                       url: generateChartURL(mainchart.hiddenchart),
-                       dataType:"json",
-                       cache: false
-               })
-               .done(function(jsondata) {
-                       if(!jsondata || jsondata.length == 0) return;
-
-                       mainchart.control_data = new google.visualization.DataTable(jsondata);
-
-                       if(mainchart.hiddenchart.last_updated == 0) {
-                               google.visualization.events.addListener(mainchart.control_wrapper, 'ready', mainchartControlReadyEvent);
-                               mainchart.dashboard.bind(mainchart.control_wrapper, mainchart.hidden_wrapper);
-                       }
-                       if(refresh_mode != REFRESH_PAUSED)
-                               mainchart.control_wrapper.setState({range: {
-                                       start: new Date((Math.round(new Date().getTime() / 1000) - MAINCHART_MAX_TIME_TO_SHOW) * 1000),
-                                       end: new Date()
-                               }});
-
-                       mainchart.dashboard.draw(mainchart.control_data);
-                       mainchart.hiddenchart.last_updated = new Date().getTime();
-                       mainchart.hiddenchart.refreshCount++;
-               })
-               .always(function() {
-                       if(typeof doNext == "function") doNext();
-               });
-       }
-
-       function mainchartControlReadyEvent() {
-               google.visualization.events.addListener(mainchart.control_wrapper, 'statechange', mainchartControlStateHandler);
-               //mylog(mainchart);
-       }
-
-       function mainchartControlStateHandler() {
-               // setMainChartPlay('pause');
-
-               var state = mainchart.control_wrapper.getState();
-               mainchart.after = Math.round(state.range.start.getTime() / 1000);
-               mainchart.before = Math.round(state.range.end.getTime() / 1000);
-
-               calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, 0);
-               //mylog('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
-
-               $('#group' + mainchart.group).trigger('click');
-               mainchart.last_updated = 0;
-
-               if(refresh_mode != REFRESH_PAUSED) pauseGraphs();
-       }
-
-       function initMainChartIndex(i) {
-               if(mode == MODE_GROUP_THUMBS) 
-                       initMainChart(group_charts[i]);
-
-               else if(mode == MODE_THUMBS)
-                       initMainChart(mycharts[i]);
-       }
-
-       var last_main_chart_max='normal';
-       function setMainChartMax(m) {
-               if(!mainchart) return;
-
-               if(m == 'toggle') {
-                       if(last_main_chart_max == 'maximized') m = 'normal';
-                       else m = 'maximized';
-               }
-
-               if(m == "maximized") {
-                       mainchart.chartOptions.theme = 'maximized';
-                       //mainchart.chartOptions.axisTitlesPosition = 'in';
-                       //mainchart.chartOptions.legend = {position: 'none'};
-                       //mainchart.chartOptions.hAxis.title = null;
-                       mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';
-                       mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';
-               }
-               else {
-                       mainchart.chartOptions.theme = null;
-                       mainchart.chartOptions.hAxis.viewWindowMode = null;
-                       mainchart.chartOptions.vAxis.viewWindowMode = null;
-               }
-               $('.mainchart_max_button').button(m);
-               last_main_chart_max = m;
-               mainchart.last_updated = 0;
-       }
-
-       function setMainChartGroup(g, norefresh) {
-               if(!mainchart) return;
-
-               mainchart.group = g;
-
-               if(!mainchart.before && !mainchart.after)
-                       calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, mainchart.group);
-               else
-                       calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, mainchart.group);
-
-               if(!norefresh) {
-                       mainchart.last_updated = 0;
-               }
-       }
-
-       var last_main_chart_avg = null;
-       function setMainChartGroupMethod(g, norefresh) {
-               if(!mainchart) return;
-
-               if(g == 'toggle') {
-                       if(last_main_chart_avg == 'max') g = 'average';
-                       else g = 'max';
-               }
-
-               mainchart.group_method = g;
-
-               $('.mainchart_avg_button').button(g);
-
-               if(!norefresh) {
-                       mainchart.last_updated = 0;
-               }
-
-               last_main_chart_avg = g;
-       }
-
-       function setMainChartPlay(p) {
-               if(!mainchart) return;
-
-               if(p == 'toggle') {
-                       if(refresh_mode != REFRESH_ALWAYS) p = 'play';
-                       else p = 'pause';
-               }
-
-               if(p == 'play') {
-                       //mainchart.chartOptions.explorer = null;
-                       mainchart.after = 0;
-                       mainchart.before = 0;
-                       calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
-                       $('#group' + mainchart.group).trigger('click');
-                       mainchart.last_updated = 0;
-                       mainchart.hiddenchart.last_updated = 0;
-                       playGraphs();
-               }
-               else {
-                       //mainchart.chartOptions.explorer = {
-                       //      'axis': 'horizontal',
-                       //      'maxZoomOut': 1,
-                       //};
-                       //mainchart.last_updated = 0;
-                       
-                       //if(!refreshChart(mainchart, pauseGraphs))
-                       pauseGraphs();
-               }
-       }
-
-
-       // ------------------------------------------------------------------------
-       // Chart resizing
-
-       function screenWidth() {
-               return (($(window).width() * 0.95) - 50);
-       }
-
-       // calculate the proper width for the thumb charts
-       function thumbWidth() {
-               var cwidth = screenWidth();
-               var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
-               if(items < 1) items = 1;
-
-               if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
-
-               return Math.round(cwidth / items) - 1;
-       }
-
-       function groupChartSizes() {
-               var s = { width: screenWidth() / 2, height: ($(window).height() - 130) / 3 - 10};
-               if(s.width < MINIMUM_THUMB_GRAPH_WIDTH * 1.5) s.width = screenWidth();
-
-               var count = 0;
-               if(group_charts) $.each(group_charts, function(i, c) {
-                       if(c.enabled) count++;
-               });
-
-               if(count == 0) {
-                       s.width = TARGET_THUMB_GRAPH_WIDTH;
-                       s.height = TARGET_THUMB_GRAPH_HEIGHT;
-               }
-               if(count < 4) {
-                       s.width = screenWidth();
-                       s.height = ($(window).height() - 130) / count - 10;
-               }
-               else if(count == 4) {
-                       s.height = ($(window).height() - 130) / 2 - 10;
-               }
-
-               if(s.height < TARGET_THUMB_GRAPH_HEIGHT * 1.5)
-                       s.height = TARGET_THUMB_GRAPH_HEIGHT * 1.5;
-
-               return s;
-       }
-
-       // resize all charts
-       // if the thumb charts need resize in their width, reset them
-       function resizeCharts() {
-               var width = screenWidth();
-
-               if(mainchart) {
-                       mainchart.chartOptions.width = width;
-                       mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
-                       mainchart.last_updated = 0;
-
-                       mainchart.hidden_wrapper.setOption('width', width);
-                       mainchart.control_wrapper.setOption('ui.chartOptions.width', width);
-                       mainchart.hiddenchart.chartOptions.width = width;
-                       mainchart.hiddenchart.last_updated = 0;
-               }
-
-               width = thumbWidth();
-               $.each(mycharts, function(i, c) {
-                       if(c.enabled && c.chartOptions.width != width) {
-                               cleanThisChart(c);
-                               c.chartOptions.width = width;
-                               showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
-                               c.last_updated = 0;
-                       }
-               });
-
-               if(group_charts) $.each(group_charts, function(i, c) {
-                       var sizes = groupChartSizes();
-
-                       if(c.enabled && (c.chartOptions.width != sizes.width || c.chartOptions.height != sizes.height)) {
-                               cleanThisChart(c);
-                               c.chartOptions.width = sizes.width;
-                               c.chartOptions.height = sizes.height;
-                               showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
-                               c.last_updated = 0;
-                       }
-               });
-       }
-
-       var resize_request = false;
-       window.onresize = function(event) {
-               resize_request = true;
-       };
-
-
-       // ------------------------------------------------------------------------
-       // Core of the thread refreshing the charts
-
-       var REFRESH_PAUSED = 0;
-       var REFRESH_ALWAYS = 1;
-
-       var refresh_mode = REFRESH_PAUSED;
-       var last_refresh = 0;
-       function playGraphs() {
-               if(refresh_mode == REFRESH_ALWAYS) return;
-
-               //mylog('PlayGraphs()');
-               refresh_mode = REFRESH_ALWAYS;
-               $('.mainchart_play_button').button('play');
-
-               // check if the thread died due to a javascript error
-               var now = new Date().getTime();
-               if((now - last_refresh) > 5000) {
-                       // it died or never started
-                       //mylog('It seems the refresh thread died. Restarting it.');
-                       chartsRefresh();
-               }
-       }
-
-       function pauseGraphs() {
-               if(refresh_mode == REFRESH_PAUSED) return;
-
-               //mylog('PauseGraphs()');
-               refresh_mode = REFRESH_PAUSED;
-               $('.mainchart_play_button').button('pause');
-       }
-
-       // refresh the proper chart
-       // this is an internal function.
-       // never call it directly, or new javascript threads will be spawn
-       var timeout;
-       function chartsRefresh() {
-               if(resize_request) {
-                       resizeCharts();
-                       resize_request = false;
-                       // refresh_mode = REFRESH_ALWAYS;
-               }
-
-               last_refresh = new Date().getTime();
-
-               if(refresh_mode == REFRESH_PAUSED) {
-                       if(mode == MODE_MAIN && mainchart.last_updated == 0)
-                               mainChartRefresh();
-                       else
-                               timeout = setTimeout(chartsRefresh, 100);
-
-                       return;
-               }
-
-                    if(mode == MODE_THUMBS)            thumbChartsRefresh();
-               else if(mode == MODE_GROUP_THUMBS)  groupChartsRefresh();
-               else if(mode == MODE_MAIN)              mainChartRefresh();
-               else                                    timeout = setTimeout(triggerRefresh, 100);
-       }
-
-       // callback for refreshing the charts later
-       // this is an internal function.
-       // never call it directly, or new javascript threads will be spawn
-       function triggerRefresh() {
-               //mylog('triggerRefresh()');
-
-               // cleanup has to take place when the charts are not refreshed
-               // since the refreshing thread is in this function, it means
-               // nothing is being refreshed.
-               cleanupCharts();
-
-                    if(mode == MODE_THUMBS)            timeout = setTimeout(chartsRefresh, 200);
-               else if(mode == MODE_GROUP_THUMBS)      timeout = setTimeout(chartsRefresh, 200);
-               else if(mode == MODE_MAIN)              timeout = setTimeout(chartsRefresh, 200);
-               else                                    timeout = setTimeout(triggerRefresh, 100);
-       }
-
-       // refresh the main chart
-       // make sure we don't loose the refreshing thread
-       function mainChartRefresh() {
-               //mylog('mainChartRefresh()');
-
-               if(mode != MODE_MAIN || !mainchart) {
-                       triggerRefresh();
-                       return;
-               }
-
-               if(!refreshChart(mainchart, hiddenChartRefresh))
-                       hiddenChartRefresh();
-       }
-
-       function hiddenChartRefresh() {
-               refreshHiddenChart(triggerRefresh);
-       }
-
-       function roundRobinRefresh(charts, startat) {
-               var refreshed = false;
-
-               // find a chart to refresh
-               var all = charts.length;
-               var cur = startat;
-               var count = 0;
-
-               for(count = 0; count < all ; count++, cur++) {
-                       if(cur >= all) cur = 0;
-
-                       if(charts[cur].enabled) {
-                               //mylog('going to refresh chart ' + charts[cur].name);
-                               refreshed = refreshChart(charts[cur], chartsRefresh);
-                               if(refreshed) break;
-                       }
-               }
-
-               if(!refreshed) triggerRefresh();
-               return cur;
-       }
-
-       // refresh the thumb charts
-       // make sure we don't loose the refreshing thread
-       var last_thumb_updated = 0;
-       function thumbChartsRefresh() {
-               //mylog('thumbChartsRefresh()');
-
-               if(mycharts.length == 0 || mode != MODE_THUMBS) {
-                       triggerRefresh();
-                       return;
-               }
-
-               last_thumb_updated = roundRobinRefresh(mycharts, last_thumb_updated);
-       }
-
-       // refresh the group charts
-       // make sure we don't loose the refreshing thread
-       var last_group_updated = 0;
-       function groupChartsRefresh() {
-               //mylog('groupChartsRefresh()');
-
-               if(!group_charts || group_charts.length == 0 || mode != MODE_GROUP_THUMBS) {
-                       //mylog('cannot refresh charts');
-                       triggerRefresh();
-                       return;
-               }
-
-               last_group_updated = roundRobinRefresh(group_charts, last_group_updated);
-       }
-
-
-       // ------------------------------------------------------------------------
-       // switch the screen between views
-       // these should be called only from initXXXX()
-
-       function disableChart(i) {
-               //mylog('disableChart(' + i + ')');
-
-               var chart = null;
-
-               var count = 0;
-               if(mode == MODE_GROUP_THUMBS && group_charts) {
-                       $.each(group_charts, function(i, c) {
-                               if(c.enabled) count++;
-                       });
-
-                       if(i < group_charts.length) chart = group_charts[i];
-               }
-               else if(mode == MODE_THUMBS) {
-                       $.each(mycharts, function(i, c) {
-                               if(c.enabled) count++;
-                       });
-
-                       if(i < mycharts.length) chart = mycharts[i];
-               }
-
-               if(!chart) return;
-
-               if(count <= 1) {
-                       alert('Cannot close the last chart shown.');
-                       return;
-               }
-
-               if(chart) {
-                       //mylog("disabling chart " + chart.name);
-                       chart.disablethisplease = true;
-               }
-       }
-
-       function cleanThisChart(chart, emptydivs) {
-               //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');
-
-               if(chart.dashboard) {
-                       chart.dashboard.clear();
-                       chart.dashboard = null;
-
-                       if(chart.control_wrapper) {
-                               chart.control_wrapper.clear();
-                               chart.control_wrapper = null;
-                       }
-
-                       if(chart.hidden_wrapper) {
-                               chart.hidden_wrapper.clear();
-                               chart.hidden_wrapper = null;
-                       }
-
-                       chart.control_data = null;
-               }
-
-               if(chart.chart) chart.chart.clearChart();
-               chart.chart = null;
-
-               if(emptydivs) {
-                       var div = document.getElementById(chart.div);
-                       if(div) {
-                               div.style.display = 'none';
-                               div.innerHTML = "";
-                       }
-
-                       div = document.getElementById(chart.div + "_parent");
-                       if(div) {
-                               div.style.display = 'none';
-                               div.innerHTML = "";
-                       }
-               }
-
-               //mylog("chart " + chart.name + " cleaned with option " + emptydivs);
-       }
-
-       // cleanup the previously shown charts
-       function cleanupCharts() {
-               //mylog('cleanupCharts()');
-
-               if(mode != MODE_MAIN && mainchart) {
-                       if(mainchart.chart) cleanThisChart(mainchart);
-                       mainchart = null;
-               }
-
-               if(mode != MODE_GROUP_THUMBS && group_charts) {
-                       clearGroupGraphs();
-               }
-
-               // cleanup the disabled charts
-               $.each(mycharts, function(i, c) {
-                       if(c.disablethisplease && c.enabled) {
-                               cleanThisChart(c, 'emptydivs');
-                               c.disablethisplease = false;
-                               c.enabled = false;
-                               resize_request = true;
-                               //mylog("disabled chart " + c.name + " removed");
-                       }
-               });
-
-               if(group_charts) $.each(group_charts, function(i, c) {
-                       if(c.disablethisplease && c.enabled) {
-                               cleanThisChart(c, 'emptydivs');
-                               c.disablethisplease = false;
-                               c.enabled = false;
-                               resize_request = true;
-                               //mylog("disabled chart " + c.name + " removed");
-                       }
-               });
-
-               // we never cleanup the thumb charts
-       }
-
-       function updateUI() {
-               $('[data-toggle="tooltip"]').tooltip({'placement': 'top', 'container': 'body', 'html': true});
-
-               $('[data-spy="scroll"]').each(function () {
-                       var $spy = $(this).scrollspy('refresh')
-               })
-       }
-
-       var thumbsScrollPosition = null;
-       function switchToMainGraph() {
-               //mylog('switchToMainGraph()');
-
-               if(!mainchart) return;
-
-               if(!group_charts) thumbsScrollPosition = window.pageYOffset;
-
-               document.getElementById('maingraph_container').style.display = 'block';
-               document.getElementById('thumbgraphs_container').style.display = 'none';
-               document.getElementById('groupgraphs_container').style.display = 'none';
-
-               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>";
-
-               window.scrollTo(0, 0);
-
-               mode = MODE_MAIN;
-               playGraphs();
-               updateUI();
-       }
-
-       function switchToThumbGraphs() {
-               //mylog('switchToThumbGraphs()');
-
-               document.getElementById('maingraph_container').style.display = 'none';
-               document.getElementById('thumbgraphs_container').style.display = 'block';
-               document.getElementById('groupgraphs_container').style.display = 'none';
-
-               document.getElementById("main_menu_div").innerHTML = mainmenu;
-
-               if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);
-
-               // switch mode
-               mode = MODE_THUMBS;
-               playGraphs();
-               updateUI();
-       }
-
-       function switchToGroupGraphs() {
-               //mylog('switchToGroupGraphs()');
-
-               if(!group_charts) return;
-
-               if(!mainchart) thumbsScrollPosition = window.pageYOffset;
-
-               document.getElementById('maingraph_container').style.display = 'none';
-               document.getElementById('thumbgraphs_container').style.display = 'none';
-               document.getElementById('groupgraphs_container').style.display = 'block';
-
-               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>";
-
-               window.scrollTo(0, 0);
-
-               mode = MODE_GROUP_THUMBS;
-               playGraphs();
-               updateUI();
-       }
-
-
-       // ------------------------------------------------------------------------
-       // Group Charts
-
-       var group_charts = null;
-       function initGroupGraphs(group) {
-               var count = 0;
-               
-               if(group_charts) clearGroupGraphs();
-               group_charts = new Array();
-
-               var groupbody = "";
-               $.each(mycharts, function(i, c) {
-                       if(c.group_tag == group) {
-                               group_charts[count] = [];
-                               group_charts[count] = $.extend(true, {}, c);
-                               group_charts[count].div += "_group";
-                               group_charts[count].enabled = true;
-                               group_charts[count].chart = null;
-                               group_charts[count].last_updated = 0;
-                               count++;
-                       }
-               });
-               group_charts.sort(chartssort);
-
-               var sizes = groupChartSizes();
-
-               var groupbody = "";
-               $.each(group_charts, function(i, c) {
-                       c.chartOptions.width = sizes.width;
-                       c.chartOptions.height = sizes.height;
-
-                       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>";
-               });
-               groupbody += "";
-
-               document.getElementById("groupgraphs").innerHTML = groupbody;
-               switchToGroupGraphs();
-       }
-
-       function clearGroupGraphs() {
-               if(group_charts && group_charts.length) {
-                       $.each(group_charts, function(i, c) {
-                               cleanThisChart(c, 'emptydivs');
-                       });
-
-                       group_charts = null;
-               }
-
-               document.getElementById("groupgraphs").innerHTML = "";
-       }
-
-
-       // ------------------------------------------------------------------------
-       // Global entry point
-       // initialize the thumb charts
-
-       // load the charts from the server
-       // generate html for the thumbgraphs to support them
-       function initCharts() {
-               var width = thumbWidth();
-               var height = TARGET_THUMB_GRAPH_HEIGHT;
-
-               loadCharts(null, function(c) {
-                       mycharts = c;
-
-                       if(mycharts == null || mycharts.length == 0) {
-                               alert("Cannot load data from server.");
-                               return;
-                       }
-
-                       var thumbsContainer = document.getElementById("thumbgraphs");
-                       if(!thumbsContainer) {
-                               alert("Cannot find the thumbsContainer");
-                               return;
-                       }
-
-                       mycharts.sort(chartssort);
-
-                       document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;
-                       document.title = mycharts[0].hostname;
-
-                       // create an array for grouping all same-type graphs together
-                       var categories = new Array();
-                       $.each(mycharts, function(i, c) {
-                               c.chartOptions.width = width;
-                               c.chartOptions.height = height;
-
-                               // calculate how many point to show for each chart
-                               c.points_to_show = Math.round(c.entries / c.group) - 1;
-
-                               // show max 10 mins of data
-                               if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;
-
-                               if(c.enabled) {
-                                       var j;
-                                       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\">"
-                                       + thumbChartActions(i, c)
-                                       +       "</td></tr></table></div>";
-
-                                       // find the categories object for this type
-                                       for(j = 0; j < categories.length ;j++) {
-                                               if(categories[j].name == c.type) {
-                                                       categories[j].html += h;
-                                                       categories[j].count++;
-                                                       break;
-                                               }
-                                       }
-
-                                       if(j == categories.length) {
-                                               categories.push({name: c.type, title: c.category, description: '', priority: 0, count: 1, glyphicon: c.glyphicon, html: h});
-                                       }
-                               }
-                       });
-
-                       $.each(categories, function(i, a) {
-                                    if(a.name == "system") a.priority = 1;
-                               else if(a.name == "net") a.priority = 2;
-                               else if(a.name == "tc") a.priority = 3;
-                               else if(a.name == "conntrack") a.priority = 4;
-                               else if(a.name == "ipvs") a.priority = 5;
-                               else if(a.name == "ipv4") a.priority = 6;
-                               else if(a.name == "cpu") a.priority = 7;
-                               else if(a.name == "mem") a.priority = 8;
-                               else if(a.name == "disk") a.priority = 9;
-                               else a.priority = 99;
-
-                               a.html = "<tr><td id=\"" + a.name + "\"><ol class=\"breadcrumb graphs\"><li class=\"active\"><span class=\"glyphicon " + a.glyphicon + "\"></span> &nbsp; <a id=\"" + a.name + "\" href=\"#" + a.name + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";
-                       });
-
-                       function categoriessort(a, b) {
-                               if(a.priority < b.priority) return -1;
-                               return 1;
-                       }
-                       categories.sort(categoriessort);
-                       
-                       // combine all the htmls into one
-                       var allcategories = "<table width=\"100%\">";
-                       mainmenu = "<ul class=\"nav navbar-nav\"><li><a href=\"#\">Home</a></li>";
-                       $.each(categories, function(i, a) {
-                               allcategories += a.html;
-                               mainmenu += "<li><a href=\"#" + a.name + "\">" + a.title + "</a></li>";
-                       });
-                       allcategories += "</table>";
-                       mainmenu += "</ul>";
-
-                       thumbsContainer.innerHTML = allcategories;
-                       switchToThumbGraphs();
-               });
-       }
-
-       </script>
 </head>
 
 <body role="document" data-spy="scroll" data-target="#main_menu_div">
                                                                                        <span class="glyphicon glyphicon-signal"></span>
                                                                                </button>
                                                                        </div>
-<!--                                                                   <div class="btn-group btn-group" data-toggle="buttons">
-                                                                               <label class="btn btn-primary" data-toggle="tooltip" title="show the MAX point among all points grouped">
-                                                                                       <input type="radio" name="groupmethod" id="groupmax" onChange="setMainChartGroupMethod('max');">
-                                                                                       <span class="glyphicon glyphicon-signal"></span>
-                                                                               </label>
-                                                                               <label class="btn btn-primary" data-toggle="tooltip" title="show the AVERAGE of all points grouped">
-                                                                                       <input type="radio" name="groupmethod" id="groupaverage" onChange="setMainChartGroupMethod('average');">
-                                                                                       <span class="glyphicon glyphicon-align-justify"></span>
-                                                                               </label>
-                                                                       </div>
--->                                                                    <div class="btn-group btn-group" data-toggle="buttons" >
+                                                                       <div class="btn-group btn-group" data-toggle="buttons" >
                                                                                <label class="btn btn-primary" data-toggle="tooltip" title="do not group points, show the raw data">
                                                                                        <input type="radio" name="group" id="group1" onChange="setMainChartGroup(1);">1
                                                                                </label>
                                                                                        <span class="glyphicon glyphicon-fullscreen"></span>
                                                                                </button>
                                                                        </div>
-<!--                                                                   <div class="btn-group btn-group" data-toggle="buttons" >
-                                                                               <label class="btn btn-primary" data-toggle="tooltip" title="NORMAL chart size">
-                                                                                       <input type="radio" name="chartmax" id="chartnormal" onChange="setMainChartMax('normal');">
-                                                                                       <span class="glyphicon glyphicon-resize-small"></span>
-                                                                               </label>
-                                                                               <label class="btn btn-primary" data-toggle="tooltip" title="MAXIMIZED chart size">
-                                                                                       <input type="radio" name="chartmax" id="chartmax" onChange="setMainChartMax('maximized');">
-                                                                                       <span class="glyphicon glyphicon-fullscreen"></span>
-                                                                               </label>
-                                                                       </div>
--->                                                            </form>
+                                                               </form>
                                                        </div>
                                                        </td></tr>
                                        </table>
                                <br/><br/>
                                <span class="glyphicon glyphicon-off"></span>
                                <br/><br/>
-                               loading charts
+                               loading cosmos
                                <br/><br/>
                                <span class="label label-default">Please wait...</span>
                                </h1>
     (c) 2014 Costa Tsaousis <a href="mailto:costa@tsaousis.gr">costa@tsaousis.gr</a>
        </div>
 
+       <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+       <script type='text/javascript'>
+               document.getElementById('splash').height = $(window).height();
+       </script>
+
+       <!-- Bootstrap -->
+       <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+
+       <!-- Google AJAX API -->
+       <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+
+       <!-- NetData -->
+       <script type="text/javascript" src="/file/netdata.js"></script>
+       <script type="text/javascript" src="/file/index.js"></script>
+
        <script type='text/javascript'>
                google.load('visualization', '1.1', {packages: ['controls']});
 
                $(document).ready(function(){
-                       document.getElementById('splash').height = $(window).height();
 
                        $(document).on('click','.navbar-collapse.in',function(e) {
                                if( $(e.target).is('a') ) {
                                        $(this).collapse('hide');
                                }
                        });
-                       
+
                        $('body').scrollspy({ target: '#main_menu_div' })
                });
-
        </script>
 </html>
diff --git a/web/index.js b/web/index.js
new file mode 100755 (executable)
index 0000000..5f15ab4
--- /dev/null
@@ -0,0 +1,935 @@
+var TARGET_THUMB_GRAPH_WIDTH = 500;            // thumb charts width will range from 0.5 to 1.5 of that\r
+var MINIMUM_THUMB_GRAPH_WIDTH = 400;   // thumb chart will generally try to be wider than that\r
+var TARGET_THUMB_GRAPH_HEIGHT = 220;   // the height of the thumb charts\r
+\r
+var THUMBS_MAX_TIME_TO_SHOW = 600;             // how much time the thumb charts will present?\r
+var THUMBS_POINTS_DIVISOR = 4;\r
+var THUMBS_STACKED_POINTS_DIVISOR = 10;\r
+\r
+var GROUPS_MAX_TIME_TO_SHOW = 600;             // how much time the thumb charts will present?\r
+var GROUPS_POINTS_DIVISOR = 4;\r
+var GROUPS_STACKED_POINTS_DIVISOR = 10;\r
+\r
+var MAINCHART_MAX_TIME_TO_SHOW = 600;  // how much time the main chart will present by default?\r
+var MAINCHART_POINTS_DIVISOR = 10;             // how much detailed will the main chart be by default? 1 = finest, higher is faster\r
+var MAINCHART_STACKED_POINTS_DIVISOR = 20;             // how much detailed will the main chart be by default? 1 = finest, higher is faster\r
+\r
+var MAINCHART_CONTROL_HEIGHT = 75;             // how tall the control chart will be\r
+var MAINCHART_CONTROL_DIVISOR = 2;             // how much detailed will the control chart be? 1 = finest, higher is faster\r
+\r
+var MODE_THUMBS = 1;\r
+var MODE_MAIN = 2;\r
+var MODE_GROUP_THUMBS = 3;\r
+var mode; // one of the MODE_* values\r
+\r
+var mycharts = new Array();\r
+var mainchart;\r
+\r
+// html for the main menu\r
+var mainmenu = "";\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// common HTML generation\r
+\r
+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>"; }\r
+\r
+function showChartIsLoading(id, name, width, height) {\r
+       //mylog('adding loading chart html in div with id ' + id);\r
+       document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height);\r
+}\r
+\r
+function thumbChartActions(i, c, nogroup) {\r
+       var name = c.name;\r
+       if(!nogroup) name = c.group_tag;\r
+\r
+       var refinfo = "the chart is drawing ";\r
+       if(c.group == 1) refinfo += "every single point collected.";\r
+       else refinfo += ((c.group_method == "average")?"the average":"the max") + " value for every " + (c.group * c.update_every) + " seconds of data";\r
+\r
+       var html = "<div class=\"btn-group btn-group\" data-toggle=\"tooltip\" title=\"" + refinfo + "\">"\r
+       +               "<button type=\"button\" class=\"btn btn-default\" onclick=\"javascript: return;\"><span class=\"glyphicon glyphicon-info-sign\"></span></button>"\r
+       +       "</div>"\r
+       +       "<div class=\"btn-group btn-group\"><button type=\"button\" class=\"btn btn-default disabled\"><small>&nbsp;&nbsp; " + name + "</small></button>";\r
+\r
+       if(!nogroup) {\r
+               var ingroup = 0;\r
+               var ingroup_detail = 0;\r
+\r
+               $.each(mycharts, function(i, d) {\r
+                       if(d.group_tag == c.group_tag) {\r
+                               ingroup++;\r
+                               if(d.isdetail) ingroup_detail++;\r
+                       }\r
+               });\r
+\r
+               var hidden = "";\r
+               if(ingroup_detail) hidden = ", including " + ingroup_detail + " charts not shown now";\r
+\r
+               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>";\r
+       }\r
+\r
+       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>"\r
+       +               "<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>"\r
+       +               "<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>"\r
+       +       "</div>";\r
+\r
+       return html;\r
+}\r
+\r
+function mylog(txt) {\r
+       console.log(txt);\r
+}\r
+\r
+function chartssort(a, b) {\r
+       if(a.userpriority < b.userpriority) return -1;\r
+       return 1;\r
+}\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// MAINGRAPH = fullscreen view of 1 graph\r
+\r
+// copy the chart c to mainchart\r
+// switch to main graphs screen\r
+function initMainChart(c) {\r
+       if(mainchart) cleanThisChart(mainchart);\r
+\r
+       mainchart = $.extend(true, {}, c);\r
+       mainchart.refreshCount = 0;\r
+       mainchart.last_updated = 0;\r
+       mainchart.chartOptions.explorer = null;\r
+       mainchart.chart = null;\r
+\r
+       mainchart.chartOptions.width = screenWidth();\r
+       mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;\r
+       if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;\r
+       //mainchart.chartOptions.chartArea = {'width': '80%'};\r
+\r
+       mainchart.div = 'maingraph';\r
+       calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);\r
+\r
+       // copy it to the hidden chart\r
+       mainchart.hiddenchart = $.extend(true, {}, mainchart);\r
+       mainchart.hiddenchart.chartOptions.height = MAINCHART_CONTROL_HEIGHT;\r
+       mainchart.hiddenchart.div = 'maingraph_control';\r
+\r
+       // initialize the div\r
+       showChartIsLoading(mainchart.div, mainchart.name, mainchart.chartOptions.width, mainchart.chartOptions.height);\r
+\r
+       // set the radio buttons\r
+       setMainChartGroupMethod(mainchart.group_method, 'no-refresh');\r
+       setMainChartMax('normal');\r
+\r
+       $('#group' + mainchart.group).trigger('click');\r
+       setMainChartGroup(mainchart.group, 'no-refresh');\r
+\r
+       switchToMainGraph();\r
+}\r
+\r
+function refreshHiddenChart(doNext) {\r
+       if(refresh_mode == REFRESH_PAUSED && mainchart.hiddenchart.last_updated != 0) {\r
+               if(typeof doNext == "function") doNext();\r
+               return;\r
+       }\r
+\r
+       // is it too soon for a refresh?\r
+       var now = new Date().getTime();\r
+       if((now - mainchart.hiddenchart.last_updated) < (mainchart.hiddenchart.group * mainchart.hiddenchart.update_every * 1000)) {\r
+               if(typeof doNext == "function") doNext();\r
+               return;\r
+       }\r
+\r
+       if(mainchart.dashboard && mainchart.hiddenchart.refreshCount > 50) {\r
+               mainchart.dashboard.clear();\r
+               mainchart.control_wrapper.clear();\r
+               mainchart.hidden_wrapper.clear();\r
+\r
+               mainchart.dashboard = null;\r
+               mainchart.control_wrapper = null;\r
+               mainchart.hidden_wrapper = null;\r
+               mainchart.hiddenchart.last_updated = 0;\r
+       }\r
+\r
+       if(!mainchart.dashboard) {\r
+               var controlopts = $.extend(true, {}, mainchart.chartOptions, {\r
+                       lineWidth: 1,\r
+                       height: mainchart.hiddenchart.chartOptions.height,\r
+                       chartArea: {'width': '98%'},\r
+                       hAxis: {'baselineColor': 'none'},\r
+                       vAxis: {'title': null},\r
+               });\r
+\r
+               mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));\r
+               mainchart.control_wrapper = new google.visualization.ControlWrapper({\r
+                       controlType: 'ChartRangeFilter',\r
+                       containerId: 'maingraph_control',\r
+                       options: {\r
+                               filterColumnIndex: 0,\r
+                               ui: {\r
+                                       chartType: mainchart.chartType,\r
+                                       chartOptions: controlopts,\r
+                                       minRangeSize: (MAINCHART_MAX_TIME_TO_SHOW * 1000 * mainchart.update_every) / MAINCHART_POINTS_DIVISOR,\r
+                               }\r
+                       },\r
+               });\r
+               mainchart.hidden_wrapper = new google.visualization.ChartWrapper({\r
+                       chartType: mainchart.chartType,\r
+                       containerId: 'maingraph_hidden',\r
+                       options: {\r
+                               isStacked: mainchart.chartOptions.isStacked,\r
+                               width: mainchart.hiddenchart.chartOptions.width,\r
+                               height: mainchart.hiddenchart.chartOptions.height,\r
+                               //chartArea: {'height': '80%', 'width': '100%'},\r
+                               //hAxis: {'slantedText': false},\r
+                               //legend: {'position': 'none'}\r
+                       },\r
+               });\r
+\r
+               mainchart.hiddenchart.refreshCount = 0;\r
+       }\r
+\r
+       // load the data for the control and the hidden wrappers\r
+       // calculate the group and points to show for the control chart\r
+       calculateChartPointsToShow(mainchart.hiddenchart, MAINCHART_CONTROL_DIVISOR, 0, -1);\r
+\r
+       $.ajax({\r
+               url: generateChartURL(mainchart.hiddenchart),\r
+               dataType:"json",\r
+               cache: false\r
+       })\r
+       .done(function(jsondata) {\r
+               if(!jsondata || jsondata.length == 0) return;\r
+\r
+               mainchart.control_data = new google.visualization.DataTable(jsondata);\r
+\r
+               if(mainchart.hiddenchart.last_updated == 0) {\r
+                       google.visualization.events.addListener(mainchart.control_wrapper, 'ready', mainchartControlReadyEvent);\r
+                       mainchart.dashboard.bind(mainchart.control_wrapper, mainchart.hidden_wrapper);\r
+               }\r
+               if(refresh_mode != REFRESH_PAUSED)\r
+                       mainchart.control_wrapper.setState({range: {\r
+                               start: new Date((Math.round(new Date().getTime() / 1000) - MAINCHART_MAX_TIME_TO_SHOW) * 1000),\r
+                               end: new Date()\r
+                       }});\r
+\r
+               mainchart.dashboard.draw(mainchart.control_data);\r
+               mainchart.hiddenchart.last_updated = new Date().getTime();\r
+               mainchart.hiddenchart.refreshCount++;\r
+       })\r
+       .always(function() {\r
+               if(typeof doNext == "function") doNext();\r
+       });\r
+}\r
+\r
+function mainchartControlReadyEvent() {\r
+       google.visualization.events.addListener(mainchart.control_wrapper, 'statechange', mainchartControlStateHandler);\r
+       //mylog(mainchart);\r
+}\r
+\r
+function mainchartControlStateHandler() {\r
+       // setMainChartPlay('pause');\r
+\r
+       var state = mainchart.control_wrapper.getState();\r
+       mainchart.after = Math.round(state.range.start.getTime() / 1000);\r
+       mainchart.before = Math.round(state.range.end.getTime() / 1000);\r
+\r
+       calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, 0, 0);\r
+       //mylog('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));\r
+\r
+       $('#group' + mainchart.group).trigger('click');\r
+       mainchart.last_updated = 0;\r
+\r
+       if(refresh_mode != REFRESH_PAUSED) pauseGraphs();\r
+}\r
+\r
+function initMainChartIndex(i) {\r
+       if(mode == MODE_GROUP_THUMBS) \r
+               initMainChart(group_charts[i]);\r
+\r
+       else if(mode == MODE_THUMBS)\r
+               initMainChart(mycharts[i]);\r
+}\r
+\r
+var last_main_chart_max='normal';\r
+function setMainChartMax(m) {\r
+       if(!mainchart) return;\r
+\r
+       if(m == 'toggle') {\r
+               if(last_main_chart_max == 'maximized') m = 'normal';\r
+               else m = 'maximized';\r
+       }\r
+\r
+       if(m == "maximized") {\r
+               mainchart.chartOptions.theme = 'maximized';\r
+               //mainchart.chartOptions.axisTitlesPosition = 'in';\r
+               //mainchart.chartOptions.legend = {position: 'none'};\r
+               //mainchart.chartOptions.hAxis.title = null;\r
+               mainchart.chartOptions.hAxis.viewWindowMode = 'maximized';\r
+               mainchart.chartOptions.vAxis.viewWindowMode = 'maximized';\r
+       }\r
+       else {\r
+               mainchart.chartOptions.theme = null;\r
+               mainchart.chartOptions.hAxis.viewWindowMode = null;\r
+               mainchart.chartOptions.vAxis.viewWindowMode = null;\r
+       }\r
+       $('.mainchart_max_button').button(m);\r
+       last_main_chart_max = m;\r
+       mainchart.last_updated = 0;\r
+}\r
+\r
+function setMainChartGroup(g, norefresh) {\r
+       if(!mainchart) return;\r
+\r
+       mainchart.group = g;\r
+\r
+       if(!mainchart.before && !mainchart.after)\r
+               calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, mainchart.group);\r
+       else\r
+               calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, 0, mainchart.group);\r
+\r
+       if(!norefresh) {\r
+               mainchart.last_updated = 0;\r
+       }\r
+}\r
+\r
+var last_main_chart_avg = null;\r
+function setMainChartGroupMethod(g, norefresh) {\r
+       if(!mainchart) return;\r
+\r
+       if(g == 'toggle') {\r
+               if(last_main_chart_avg == 'max') g = 'average';\r
+               else g = 'max';\r
+       }\r
+\r
+       mainchart.group_method = g;\r
+\r
+       $('.mainchart_avg_button').button(g);\r
+\r
+       if(!norefresh) {\r
+               mainchart.last_updated = 0;\r
+       }\r
+\r
+       last_main_chart_avg = g;\r
+}\r
+\r
+function setMainChartPlay(p) {\r
+       if(!mainchart) return;\r
+\r
+       if(p == 'toggle') {\r
+               if(refresh_mode != REFRESH_ALWAYS) p = 'play';\r
+               else p = 'pause';\r
+       }\r
+\r
+       if(p == 'play') {\r
+               //mainchart.chartOptions.explorer = null;\r
+               mainchart.after = 0;\r
+               mainchart.before = 0;\r
+               calculateChartPointsToShow(mainchart, mainchart.chartOptions.isStacked?MAINCHART_STACKED_POINTS_DIVISOR:MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);\r
+               $('#group' + mainchart.group).trigger('click');\r
+               mainchart.last_updated = 0;\r
+               mainchart.hiddenchart.last_updated = 0;\r
+               playGraphs();\r
+       }\r
+       else {\r
+               //mainchart.chartOptions.explorer = {\r
+               //      'axis': 'horizontal',\r
+               //      'maxZoomOut': 1,\r
+               //};\r
+               //mainchart.last_updated = 0;\r
+               \r
+               //if(!refreshChart(mainchart, pauseGraphs))\r
+               pauseGraphs();\r
+       }\r
+}\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// Chart resizing\r
+\r
+function screenWidth() {\r
+       return (($(window).width() * 0.95) - 50);\r
+}\r
+\r
+// calculate the proper width for the thumb charts\r
+function thumbWidth() {\r
+       var cwidth = screenWidth();\r
+       var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);\r
+       if(items < 1) items = 1;\r
+\r
+       if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;\r
+\r
+       return Math.round(cwidth / items) - 1;\r
+}\r
+\r
+function groupChartSizes() {\r
+       var s = { width: screenWidth() / 2, height: ($(window).height() - 130) / 3 - 10};\r
+       if(s.width < MINIMUM_THUMB_GRAPH_WIDTH * 1.5) s.width = screenWidth();\r
+\r
+       var count = 0;\r
+       if(group_charts) $.each(group_charts, function(i, c) {\r
+               if(c.enabled) count++;\r
+       });\r
+\r
+       if(count == 0) {\r
+               s.width = TARGET_THUMB_GRAPH_WIDTH;\r
+               s.height = TARGET_THUMB_GRAPH_HEIGHT;\r
+       }\r
+       if(count < 4) {\r
+               s.width = screenWidth();\r
+               s.height = ($(window).height() - 130) / count - 10;\r
+       }\r
+       else if(count == 4) {\r
+               s.height = ($(window).height() - 130) / 2 - 10;\r
+       }\r
+\r
+       if(s.height < TARGET_THUMB_GRAPH_HEIGHT * 1.5)\r
+               s.height = TARGET_THUMB_GRAPH_HEIGHT * 1.5;\r
+\r
+       return s;\r
+}\r
+\r
+// resize all charts\r
+// if the thumb charts need resize in their width, reset them\r
+function resizeCharts() {\r
+       var width = screenWidth();\r
+\r
+       if(mainchart) {\r
+               mainchart.chartOptions.width = width;\r
+               mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;\r
+               mainchart.last_updated = 0;\r
+\r
+               mainchart.hidden_wrapper.setOption('width', width);\r
+               mainchart.control_wrapper.setOption('ui.chartOptions.width', width);\r
+               mainchart.hiddenchart.chartOptions.width = width;\r
+               mainchart.hiddenchart.last_updated = 0;\r
+       }\r
+\r
+       width = thumbWidth();\r
+       $.each(mycharts, function(i, c) {\r
+               if(c.enabled && c.chartOptions.width != width) {\r
+                       cleanThisChart(c);\r
+                       c.chartOptions.width = width;\r
+                       calculateChartPointsToShow(c, c.chartOptions.isStacked?THUMBS_STACKED_POINTS_DIVISOR:THUMBS_POINTS_DIVISOR, THUMBS_MAX_TIME_TO_SHOW, -1);\r
+                       showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);\r
+                       c.last_updated = 0;\r
+               }\r
+       });\r
+\r
+       if(group_charts) $.each(group_charts, function(i, c) {\r
+               var sizes = groupChartSizes();\r
+\r
+               if(c.enabled && (c.chartOptions.width != sizes.width || c.chartOptions.height != sizes.height)) {\r
+                       cleanThisChart(c);\r
+                       c.chartOptions.width = sizes.width;\r
+                       c.chartOptions.height = sizes.height;\r
+                       calculateChartPointsToShow(c, c.chartOptions.isStacked?GROUPS_STACKED_POINTS_DIVISOR:GROUPS_POINTS_DIVISOR, GROUPS_MAX_TIME_TO_SHOW, -1);\r
+                       showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);\r
+                       c.last_updated = 0;\r
+               }\r
+       });\r
+}\r
+\r
+var resize_request = false;\r
+window.onresize = function(event) {\r
+       resize_request = true;\r
+};\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// Core of the thread refreshing the charts\r
+\r
+var REFRESH_PAUSED = 0;\r
+var REFRESH_ALWAYS = 1;\r
+\r
+var refresh_mode = REFRESH_PAUSED;\r
+var last_refresh = 0;\r
+function playGraphs() {\r
+       if(refresh_mode == REFRESH_ALWAYS) return;\r
+\r
+       //mylog('PlayGraphs()');\r
+       refresh_mode = REFRESH_ALWAYS;\r
+       $('.mainchart_play_button').button('play');\r
+\r
+       // check if the thread died due to a javascript error\r
+       var now = new Date().getTime();\r
+       if((now - last_refresh) > 5000) {\r
+               // it died or never started\r
+               //mylog('It seems the refresh thread died. Restarting it.');\r
+               chartsRefresh();\r
+       }\r
+}\r
+\r
+function pauseGraphs() {\r
+       if(refresh_mode == REFRESH_PAUSED) return;\r
+\r
+       //mylog('PauseGraphs()');\r
+       refresh_mode = REFRESH_PAUSED;\r
+       $('.mainchart_play_button').button('pause');\r
+}\r
+\r
+var interval = null;\r
+function checkRefreshThread() {\r
+       if(interval == null) {\r
+               interval = setInterval(checkRefreshThread, 2000);\r
+               return;\r
+       }\r
+\r
+       var now = new Date().getTime();\r
+       if(now - last_refresh > 10000) {\r
+               mylog('Refresh thread died. Restarting it.');\r
+               chartsRefresh();\r
+       }\r
+}\r
+\r
+// refresh the proper chart\r
+// this is an internal function.\r
+// never call it directly, or new javascript threads will be spawn\r
+var timeout = null;\r
+function chartsRefresh() {\r
+       if(resize_request) {\r
+               resizeCharts();\r
+               resize_request = false;\r
+               // refresh_mode = REFRESH_ALWAYS;\r
+       }\r
+\r
+       last_refresh = new Date().getTime();\r
+\r
+       if(refresh_mode == REFRESH_PAUSED) {\r
+               if(mode == MODE_MAIN && mainchart.last_updated == 0) {\r
+                       mainChartRefresh();\r
+                       return;\r
+               }\r
+       }\r
+\r
+            if(mode == MODE_THUMBS)            thumbChartsRefresh();\r
+       else if(mode == MODE_GROUP_THUMBS)  groupChartsRefresh();\r
+       else if(mode == MODE_MAIN)              mainChartRefresh();\r
+       else                                    timeout = setTimeout(triggerRefresh, 100);\r
+}\r
+\r
+// callback for refreshing the charts later\r
+// this is an internal function.\r
+// never call it directly, or new javascript threads will be spawn\r
+function triggerRefresh() {\r
+       //mylog('triggerRefresh()');\r
+\r
+       // cleanup has to take place when the charts are not refreshed\r
+       // since the refreshing thread is in this function, it means\r
+       // nothing is being refreshed.\r
+       cleanupCharts();\r
+\r
+            if(mode == MODE_THUMBS)            timeout = setTimeout(chartsRefresh, 200);\r
+       else if(mode == MODE_GROUP_THUMBS)      timeout = setTimeout(chartsRefresh, 200);\r
+       else if(mode == MODE_MAIN)              timeout = setTimeout(chartsRefresh, 200);\r
+       else                                    timeout = setTimeout(triggerRefresh, 100);\r
+}\r
+\r
+// refresh the main chart\r
+// make sure we don't loose the refreshing thread\r
+function mainChartRefresh() {\r
+       //mylog('mainChartRefresh()');\r
+\r
+       if(mode != MODE_MAIN || !mainchart) {\r
+               triggerRefresh();\r
+               return;\r
+       }\r
+\r
+       if(!refreshChart(mainchart, hiddenChartRefresh))\r
+               hiddenChartRefresh();\r
+}\r
+\r
+function hiddenChartRefresh() {\r
+       refreshHiddenChart(triggerRefresh);\r
+}\r
+\r
+function roundRobinRefresh(charts, startat) {\r
+       var refreshed = false;\r
+\r
+       // find a chart to refresh\r
+       var all = charts.length;\r
+       var cur = startat;\r
+       var count = 0;\r
+\r
+       for(count = 0; count < all ; count++, cur++) {\r
+               if(cur >= all) cur = 0;\r
+\r
+               if(charts[cur].enabled) {\r
+                       //mylog('going to refresh chart ' + charts[cur].name);\r
+                       refreshed = refreshChart(charts[cur], chartsRefresh);\r
+                       if(refreshed) break;\r
+               }\r
+       }\r
+\r
+       if(!refreshed) triggerRefresh();\r
+       return cur;\r
+}\r
+\r
+// refresh the thumb charts\r
+// make sure we don't loose the refreshing thread\r
+var last_thumb_updated = 0;\r
+function thumbChartsRefresh() {\r
+       //mylog('thumbChartsRefresh()');\r
+\r
+       if(mycharts.length == 0 || mode != MODE_THUMBS) {\r
+               triggerRefresh();\r
+               return;\r
+       }\r
+\r
+       last_thumb_updated = roundRobinRefresh(mycharts, last_thumb_updated);\r
+}\r
+\r
+// refresh the group charts\r
+// make sure we don't loose the refreshing thread\r
+var last_group_updated = 0;\r
+function groupChartsRefresh() {\r
+       //mylog('groupChartsRefresh()');\r
+\r
+       if(!group_charts || group_charts.length == 0 || mode != MODE_GROUP_THUMBS) {\r
+               //mylog('cannot refresh charts');\r
+               triggerRefresh();\r
+               return;\r
+       }\r
+\r
+       last_group_updated = roundRobinRefresh(group_charts, last_group_updated);\r
+}\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// switch the screen between views\r
+// these should be called only from initXXXX()\r
+\r
+function disableChart(i) {\r
+       //mylog('disableChart(' + i + ')');\r
+\r
+       var chart = null;\r
+\r
+       var count = 0;\r
+       if(mode == MODE_GROUP_THUMBS && group_charts) {\r
+               $.each(group_charts, function(i, c) {\r
+                       if(c.enabled) count++;\r
+               });\r
+\r
+               if(i < group_charts.length) chart = group_charts[i];\r
+       }\r
+       else if(mode == MODE_THUMBS) {\r
+               $.each(mycharts, function(i, c) {\r
+                       if(c.enabled) count++;\r
+               });\r
+\r
+               if(i < mycharts.length) chart = mycharts[i];\r
+       }\r
+\r
+       if(!chart) return;\r
+\r
+       if(count <= 1) {\r
+               alert('Cannot close the last chart shown.');\r
+               return;\r
+       }\r
+\r
+       if(chart) {\r
+               //mylog("disabling chart " + chart.name);\r
+               chart.disablethisplease = true;\r
+       }\r
+}\r
+\r
+function cleanThisChart(chart, emptydivs) {\r
+       //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');\r
+\r
+       if(chart.dashboard) {\r
+               chart.dashboard.clear();\r
+               chart.dashboard = null;\r
+\r
+               if(chart.control_wrapper) {\r
+                       chart.control_wrapper.clear();\r
+                       chart.control_wrapper = null;\r
+               }\r
+\r
+               if(chart.hidden_wrapper) {\r
+                       chart.hidden_wrapper.clear();\r
+                       chart.hidden_wrapper = null;\r
+               }\r
+\r
+               chart.control_data = null;\r
+       }\r
+\r
+       if(chart.chart) chart.chart.clearChart();\r
+       chart.chart = null;\r
+\r
+       if(emptydivs) {\r
+               var div = document.getElementById(chart.div);\r
+               if(div) {\r
+                       div.style.display = 'none';\r
+                       div.innerHTML = "";\r
+               }\r
+\r
+               div = document.getElementById(chart.div + "_parent");\r
+               if(div) {\r
+                       div.style.display = 'none';\r
+                       div.innerHTML = "";\r
+               }\r
+       }\r
+\r
+       //mylog("chart " + chart.name + " cleaned with option " + emptydivs);\r
+}\r
+\r
+// cleanup the previously shown charts\r
+function cleanupCharts() {\r
+       //mylog('cleanupCharts()');\r
+\r
+       if(mode != MODE_MAIN && mainchart) {\r
+               if(mainchart.chart) cleanThisChart(mainchart);\r
+               mainchart = null;\r
+       }\r
+\r
+       if(mode != MODE_GROUP_THUMBS && group_charts) {\r
+               clearGroupGraphs();\r
+       }\r
+\r
+       // cleanup the disabled charts\r
+       $.each(mycharts, function(i, c) {\r
+               if(c.disablethisplease && c.enabled) {\r
+                       cleanThisChart(c, 'emptydivs');\r
+                       c.disablethisplease = false;\r
+                       c.enabled = false;\r
+                       resize_request = true;\r
+                       //mylog("disabled chart " + c.name + " removed");\r
+               }\r
+       });\r
+\r
+       if(group_charts) $.each(group_charts, function(i, c) {\r
+               if(c.disablethisplease && c.enabled) {\r
+                       cleanThisChart(c, 'emptydivs');\r
+                       c.disablethisplease = false;\r
+                       c.enabled = false;\r
+                       resize_request = true;\r
+                       //mylog("disabled chart " + c.name + " removed");\r
+               }\r
+       });\r
+\r
+       // we never cleanup the thumb charts\r
+}\r
+\r
+function updateUI() {\r
+       $('[data-toggle="tooltip"]').tooltip({'placement': 'top', 'container': 'body', 'html': true});\r
+\r
+       $('[data-spy="scroll"]').each(function () {\r
+               var $spy = $(this).scrollspy('refresh')\r
+       })\r
+}\r
+\r
+var thumbsScrollPosition = null;\r
+function switchToMainGraph() {\r
+       //mylog('switchToMainGraph()');\r
+\r
+       if(!mainchart) return;\r
+\r
+       if(!group_charts) thumbsScrollPosition = window.pageYOffset;\r
+\r
+       document.getElementById('maingraph_container').style.display = 'block';\r
+       document.getElementById('thumbgraphs_container').style.display = 'none';\r
+       document.getElementById('groupgraphs_container').style.display = 'none';\r
+\r
+       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>";\r
+\r
+       window.scrollTo(0, 0);\r
+\r
+       mode = MODE_MAIN;\r
+       playGraphs();\r
+       updateUI();\r
+}\r
+\r
+function switchToThumbGraphs() {\r
+       //mylog('switchToThumbGraphs()');\r
+\r
+       document.getElementById('maingraph_container').style.display = 'none';\r
+       document.getElementById('thumbgraphs_container').style.display = 'block';\r
+       document.getElementById('groupgraphs_container').style.display = 'none';\r
+\r
+       document.getElementById("main_menu_div").innerHTML = mainmenu;\r
+\r
+       if(thumbsScrollPosition) window.scrollTo(0, thumbsScrollPosition);\r
+\r
+       // switch mode\r
+       mode = MODE_THUMBS;\r
+       playGraphs();\r
+       updateUI();\r
+}\r
+\r
+function switchToGroupGraphs() {\r
+       //mylog('switchToGroupGraphs()');\r
+\r
+       if(!group_charts) return;\r
+\r
+       if(!mainchart) thumbsScrollPosition = window.pageYOffset;\r
+\r
+       document.getElementById('maingraph_container').style.display = 'none';\r
+       document.getElementById('thumbgraphs_container').style.display = 'none';\r
+       document.getElementById('groupgraphs_container').style.display = 'block';\r
+\r
+       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>";\r
+\r
+       window.scrollTo(0, 0);\r
+\r
+       mode = MODE_GROUP_THUMBS;\r
+       playGraphs();\r
+       updateUI();\r
+}\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// Group Charts\r
+\r
+var group_charts = null;\r
+function initGroupGraphs(group) {\r
+       var count = 0;\r
+       \r
+       if(group_charts) clearGroupGraphs();\r
+       group_charts = new Array();\r
+\r
+       var groupbody = "";\r
+       $.each(mycharts, function(i, c) {\r
+               if(c.group_tag == group) {\r
+                       group_charts[count] = [];\r
+                       group_charts[count] = $.extend(true, {}, c);\r
+                       group_charts[count].div += "_group";\r
+                       group_charts[count].enabled = true;\r
+                       group_charts[count].chart = null;\r
+                       group_charts[count].last_updated = 0;\r
+                       count++;\r
+               }\r
+       });\r
+       group_charts.sort(chartssort);\r
+\r
+       var sizes = groupChartSizes();\r
+\r
+       var groupbody = "";\r
+       $.each(group_charts, function(i, c) {\r
+               c.chartOptions.width = sizes.width;\r
+               c.chartOptions.height = sizes.height;\r
+\r
+               calculateChartPointsToShow(c, c.chartOptions.isStacked?GROUPS_STACKED_POINTS_DIVISOR:GROUPS_POINTS_DIVISOR, GROUPS_MAX_TIME_TO_SHOW, -1);\r
+\r
+               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>";\r
+       });\r
+       groupbody += "";\r
+\r
+       document.getElementById("groupgraphs").innerHTML = groupbody;\r
+       switchToGroupGraphs();\r
+}\r
+\r
+function clearGroupGraphs() {\r
+       if(group_charts && group_charts.length) {\r
+               $.each(group_charts, function(i, c) {\r
+                       cleanThisChart(c, 'emptydivs');\r
+               });\r
+\r
+               group_charts = null;\r
+       }\r
+\r
+       document.getElementById("groupgraphs").innerHTML = "";\r
+}\r
+\r
+\r
+// ------------------------------------------------------------------------\r
+// Global entry point\r
+// initialize the thumb charts\r
+\r
+// load the charts from the server\r
+// generate html for the thumbgraphs to support them\r
+function initCharts() {\r
+       var width = thumbWidth();\r
+       var height = TARGET_THUMB_GRAPH_HEIGHT;\r
+\r
+       loadCharts(null, function(c) {\r
+               mycharts = c;\r
+\r
+               if(mycharts == null || mycharts.length == 0) {\r
+                       alert("Cannot load data from server.");\r
+                       return;\r
+               }\r
+\r
+               var thumbsContainer = document.getElementById("thumbgraphs");\r
+               if(!thumbsContainer) {\r
+                       alert("Cannot find the thumbsContainer");\r
+                       return;\r
+               }\r
+\r
+               mycharts.sort(chartssort);\r
+\r
+               document.getElementById('hostname_id').innerHTML = mycharts[0].hostname;\r
+               document.title = mycharts[0].hostname;\r
+\r
+               // create an array for grouping all same-type graphs together\r
+               var categories = new Array();\r
+               $.each(mycharts, function(i, c) {\r
+                       c.chartOptions.width = width;\r
+                       c.chartOptions.height = height;\r
+\r
+                       // calculate how many point to show for each chart\r
+                       //c.points_to_show = Math.round(c.entries / c.group) - 1;\r
+                       // show max 10 mins of data\r
+                       //if(c.points_to_show * c.group > THUMBS_MAX_TIME_TO_SHOW) c.points_to_show = THUMBS_MAX_TIME_TO_SHOW / c.group;\r
+                       calculateChartPointsToShow(c, c.chartOptions.isStacked?THUMBS_STACKED_POINTS_DIVISOR:THUMBS_POINTS_DIVISOR, THUMBS_MAX_TIME_TO_SHOW, -1);\r
+\r
+                       if(c.enabled) {\r
+                               var j;\r
+                               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\">"\r
+                               + thumbChartActions(i, c)\r
+                               +       "</td></tr></table></div>";\r
+\r
+                               // find the categories object for this type\r
+                               for(j = 0; j < categories.length ;j++) {\r
+                                       if(categories[j].name == c.type) {\r
+                                               categories[j].html += h;\r
+                                               categories[j].count++;\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if(j == categories.length) {\r
+                                       categories.push({name: c.type, title: c.category, description: '', priority: 0, count: 1, glyphicon: c.glyphicon, html: h});\r
+                               }\r
+                       }\r
+               });\r
+\r
+               $.each(categories, function(i, a) {\r
+                            if(a.name == "system") a.priority = 1;\r
+                       else if(a.name == "net") a.priority = 2;\r
+                       else if(a.name == "tc") a.priority = 3;\r
+                       else if(a.name == "conntrack") a.priority = 4;\r
+                       else if(a.name == "ipvs") a.priority = 5;\r
+                       else if(a.name == "ipv4") a.priority = 6;\r
+                       else if(a.name == "cpu") a.priority = 7;\r
+                       else if(a.name == "mem") a.priority = 8;\r
+                       else if(a.name == "disk") a.priority = 9;\r
+                       else a.priority = 99;\r
+\r
+                       a.html = "<tr><td id=\"" + a.name + "\"><ol class=\"breadcrumb graphs\"><li class=\"active\"><span class=\"glyphicon " + a.glyphicon + "\"></span> &nbsp; <a id=\"" + a.name + "\" href=\"#" + a.name + "\"><b>" + a.title + "</b> " + a.description + " </a></li></ol></td></tr><tr><td><div class=\"thumbgraphs\">" + a.html + "</td></tr>";\r
+               });\r
+\r
+               function categoriessort(a, b) {\r
+                       if(a.priority < b.priority) return -1;\r
+                       return 1;\r
+               }\r
+               categories.sort(categoriessort);\r
+               \r
+               // combine all the htmls into one\r
+               var allcategories = "<table width=\"100%\">";\r
+               mainmenu = "<ul class=\"nav navbar-nav\"><li><a href=\"#\">Home</a></li>";\r
+               $.each(categories, function(i, a) {\r
+                       allcategories += a.html;\r
+                       mainmenu += "<li><a href=\"#" + a.name + "\">" + a.title + "</a></li>";\r
+               });\r
+               allcategories += "</table>";\r
+               mainmenu += "</ul>";\r
+\r
+               thumbsContainer.innerHTML = allcategories;\r
+               switchToThumbGraphs();\r
+               checkRefreshThread();\r
+       });\r
+}\r
+\r
+// Set a callback to run when the Google Visualization API is loaded.\r
+google.setOnLoadCallback(initCharts);\r
+\r