]> arthur.barton.de Git - netdata.git/commitdiff
minor code cleanups; updated the dashboard to fix inline charts
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Mon, 30 Nov 2015 23:36:34 +0000 (01:36 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Mon, 30 Nov 2015 23:36:34 +0000 (01:36 +0200)
src/daemon.c
src/daemon.h
src/main.c
src/main.h
src/popen.c
src/web_client.c
web/Makefile.am
web/dashboard.html
web/dashboard.js
web/lib/visible.js [new file with mode: 0755]

index d73a3a46c38876ae54e47182ac6f8a6a46d07963..52884e6cd6adcfa9e4fee30808ae424158d9c44e 100755 (executable)
 #include "main.h"
 #include "daemon.h"
 
-#define BACKTRACE_SIZE 4096
-
-void print_backtrace()
-{
-       void *buffer[BACKTRACE_SIZE];
-       int nptrs;
-
-       nptrs = backtrace(buffer, BACKTRACE_SIZE);
-       fprintf(stderr, "\n\nSTACK TRACE (%d addresses):\n\n", nptrs);
-       backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
-       fprintf(stderr, "\n\n");
-}
-
 void sig_handler(int signo)
 {
        switch(signo) {
@@ -51,7 +38,6 @@ void sig_handler(int signo)
                case SIGXCPU:
                case SIGXFSZ:
                        info("Death signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno));
-                       print_backtrace();
                        signal(signo, SIG_DFL);
                        break;
 
@@ -63,18 +49,13 @@ void sig_handler(int signo)
                case SIGUSR1:
                case SIGUSR2:
                        info("Signaled exit (signal %d). Errno: %d (%s)", signo, errno, strerror(errno));
-                       print_backtrace();
                        signal(SIGPIPE, SIG_IGN);
                        signal(SIGTERM, SIG_IGN);
                        signal(SIGQUIT, SIG_IGN);
                        signal(SIGHUP,  SIG_IGN);
                        signal(SIGINT,  SIG_IGN);
                        signal(SIGCHLD, SIG_IGN);
-                       kill_childs();
-                       rrdset_free_all();
-                       //unlink("/var/run/netdata.pid");
-                       info("NetData exiting. Bye bye...");
-                       exit(1);
+                       netdata_cleanup_and_exit(1);
                        break;
 
                case SIGPIPE:
@@ -263,7 +244,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
        // close all files
        if(close_all_files) {
                int i;
-               for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
+               for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
                        if(
                                ((access_fd && i != *access_fd) || !access_fd)
                                && i != dev_null
index 9f8694f9580a44581b5cd5a6afe598e33e276a94..77186daae2756b397b7abd33bc88d61b0d9b8ae4 100755 (executable)
@@ -9,4 +9,6 @@ extern int become_user(const char *username);
 
 extern int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp);
 
+extern void netdata_cleanup_and_exit(int i);
+
 #endif /* NETDATA_DAEMON_H */
index 328d4ac4ea1933c3bdd298ff93587d13a863ff8c..7288d073af39f19dcc9eb9d65c259ca47387fa45 100755 (executable)
 
 #include "main.h"
 
+int netdata_exit = 0;
+
+void netdata_cleanup_and_exit(int ret)
+{
+       kill_childs();
+       rrdset_free_all();
+       //unlink("/var/run/netdata.pid");
+       info("NetData exiting. Bye bye...");
+       exit(ret);
+}
+
 struct netdata_static_thread {
        char *name;
 
@@ -445,7 +456,17 @@ int main(int argc, char **argv)
        }
 
        // for future use - the main thread
-       while(1) sleep(60);
+       while(1) {
+               if(netdata_exit != 0) {
+                       netdata_exit++;
+
+                       if(netdata_exit > 5) {
+                               netdata_cleanup_and_exit(0);
+                               exit(0);
+                       }
+               }
+               sleep(2);
+       }
 
        exit(0);
 }
index d6b3107102be9a6f4a1b7e044cfc7a1f664d3f51..6a90efd9d42f6f9e47915af081963b4da4fa4a2b 100755 (executable)
@@ -1,7 +1,10 @@
 #ifndef NETDATA_MAIN_H
 #define NETDATA_MAIN_H 1
 
+extern int netdata_exit;
+
 extern void kill_childs(void);
 extern int killpid(pid_t pid, int signal);
+extern void netdata_cleanup_and_exit(int ret);
 
 #endif /* NETDATA_MAIN_H */
index 58dc1f549e519317b391ebaa2c2251972443280a..9449c64f42d6ced1c7950be8d25d94bd7e4c18b7 100755 (executable)
@@ -78,7 +78,7 @@ FILE *mypopen(const char *command, pid_t *pidptr)
 
        // close all files
        int i;
-       for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
+       for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
                if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
 
        // move the pipe to stdout
index d05ef9ba31daa025065e028be7ce22515a179704..b38cff50941cff29cfcdcfe48b731e30a2cd5739 100755 (executable)
@@ -34,6 +34,8 @@
 int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
 int web_enable_gzip = 1;
 
+extern int netdata_exit;
+
 struct web_client *web_clients = NULL;
 unsigned long long web_clients_count = 0;
 
@@ -975,7 +977,7 @@ void web_client_process(struct web_client *w) {
                //if(strstr(w->response.data->buffer, "X-DataSource-Auth"))
                //      datasource_type = DATASOURCE_GOOGLE_JSON;
 
-               char *buf = w->response.data->buffer;
+               char *buf = (char *)buffer_tostring(w->response.data);
                char *tok = strsep(&buf, " \r\n");
                char *url = NULL;
                char *pointer_to_free = NULL; // keep url_decode() allocated buffer
@@ -1007,6 +1009,15 @@ void web_client_process(struct web_client *w) {
                                datasource_type = DATASOURCE_JSON;
                                code = web_client_api_request(w, url);
                        }
+#ifdef WEB_EXIT
+                       else if(strcmp(tok, "exit") == 0) {
+                               netdata_exit = 1;
+                               code = 200;
+                               w->response.data->contenttype = CT_TEXT_PLAIN;
+                               buffer_flush(w->response.data);
+                               buffer_strcat(w->response.data, "will do");
+                       }
+#endif
                        else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
                                // the client is requesting rrd data
                                datasource_type = DATASOURCE_JSON;
index b20279f8b9d4784c07546784e162753d54f55e2c..3c0003a9cffd9c76bfacb1b5dc2841808eaf52f4 100644 (file)
@@ -25,4 +25,5 @@ dist_weblib_DATA = \
         lib/jquery.sparkline.min.js \
         lib/morris.min.js \
         lib/raphael-min.js \
+        lib/visible.js \
         $(NULL)
index 2823214a24aa8a273693efbef81b1fb2609d7c78..4c8842b2d5b620e8b030a560e2f416f408b44fb0 100755 (executable)
@@ -19,7 +19,7 @@ This is a template for building custom dashboards. To build a dashboard you just
                data-width="600"
                data-height="200"
                data-after="-600"
-               &lt;/div>
+               >&lt;/div>
 &lt;/body>
 &lt;script type="text/javascript" src="http://netdata.server:19999/dashboard.js"></script>
 &lt;/html>
@@ -47,15 +47,15 @@ This is a template for building custom dashboards. To build a dashboard you just
                System CPU - Stacked Area Chart
                </th>
        </tr>
-       <tr><td colspan="3" align="center">&nbsp;</td></tr>
-       <tr><th colspan="3" align="center"><hr>Peity Charts</th></tr>
-       <tr><td colspan="3" align="center">
+       <tr><td colspan="3">&nbsp;</td></tr>
+       <tr><th colspan="3"><hr>Peity Charts</th></tr>
+       <tr><td colspan="3">
                Peity charts do not support 'NULL' values, so the charts cannot indicate that values are missing.
                Peity charts cannot have multiple dimensions on the charts - so netdata will use 'min2max' to show
                the total of all dimensions.
                </td></tr>
        <tr>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.processes"
                                data-chart-library="peity"
                                data-width="600"
@@ -64,7 +64,7 @@ This is a template for building custom dashboards. To build a dashboard you just
                                data-dt-element-name="time11"
                                </div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.ipv4"
                                data-chart-library="peity"
                                data-width="600"
@@ -73,7 +73,7 @@ This is a template for building custom dashboards. To build a dashboard you just
                                data-dt-element-name="time12"
                                </div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.cpu"
                                data-chart-library="peity"
                                data-width="600"
@@ -88,67 +88,64 @@ This is a template for building custom dashboards. To build a dashboard you just
                <td>rendered in <span id="time12">X</span> ms</td>
                <td>rendered in <span id="time13">X</span> ms</td>
        </tr>
-       <tr><td colspan="3" align="center">&nbsp;</td></tr>
-       <tr><th colspan="3" align="center"><hr>Sparkline Charts</th></tr>
-       <tr><td colspan="3" align="center">
+       <tr><td colspan="3">&nbsp;</td></tr>
+       <tr><th colspan="3"><hr>Sparkline Charts</th></tr>
+       <tr><td colspan="3">
                Sparkline charts support 'NULL' values, so the charts can indicate that values are missing.
                Sparkline charts stretch the values to show the variations between values in more detail.
                They also have mouse-hover support.
                <br/>
                Sparklines are fantastic. You can inline charts in text. For example this
-                       <div    style="display: inline; position: relative;"
-                                       data-netdata="system.cpu"
+                       <div    data-netdata="system.cpu"
                                        data-chart-library="sparkline"
                                        data-width="60"
-                                       data-height="15"
+                                       data-height="20"
                                        data-after="-30"
-                                       </div> is my current cpu usage,
+                                       ></div> is my current cpu usage,
                        <br/>
                        while this
-                       <div    style="display: inline; position: relative;"
-                                       data-netdata="netdata.net"
+                       <div    data-netdata="netdata.net"
                                        data-dimensions="out"
                                        data-chart-library="sparkline"
                                        data-width="60"
-                                       data-height="15"
+                                       data-height="20"
                                        data-after="-30"
-                                       </div> is the bandwidth my netdata server is currently transmitting and this
+                                       ></div> is the bandwidth my netdata server is currently transmitting and this
 
-                       <div    style="display: inline; position: relative;"
-                                       data-netdata="netdata.requests"
+                       <div    data-netdata="netdata.requests"
                                        data-chart-library="sparkline"
-                                       data-width="60"
-                                       data-height="15"
-                                       data-after="-30"
-                                       </div> is the requests/sec it serves.
+                                       data-width="360"
+                                       data-height="20"
+                                       data-after="-180"
+                                       ></div> is the requests/sec it serves.
                </td></tr>
        <tr>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.processes"
                                data-chart-library="sparkline"
                                data-width="600"
                                data-height="30"
                                data-after="-600"
                                data-dt-element-name="time21"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.ipv4"
                                data-chart-library="sparkline"
                                data-width="600"
                                data-height="30"
                                data-after="-600"
                                data-dt-element-name="time22"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.cpu"
                                data-chart-library="sparkline"
                                data-width="600"
                                data-height="30"
                                data-after="-600"
                                data-dt-element-name="time23"
-                               </div>
+                               ></div>
                </td>
        </tr>
        <tr>
@@ -156,40 +153,40 @@ This is a template for building custom dashboards. To build a dashboard you just
                <td>rendered in <span id="time22">X</span> ms</td>
                <td>rendered in <span id="time23">X</span> ms</td>
        </tr>
-       <tr><td colspan="3" align="center">&nbsp;</td></tr>
-       <tr><th colspan="3" align="center"><hr>Dygraph Charts</th></tr>
-       <tr><td colspan="3" align="center">
+       <tr><td colspan="3">&nbsp;</td></tr>
+       <tr><th colspan="3"><hr>Dygraph Charts</th></tr>
+       <tr><td colspan="3">
                The fastest charting engine that can chart complete charts (not just sparklines).
                The charts are zoomable (drag their contents to zoom-in, double click to zoom-out).
                For the moment zooming is just on the presentation layer (the data do not become more detailed when you zoom).
                </td></tr>
        <tr>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.processes"
                                data-chart-library="dygraph"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time31"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.ipv4"
                                data-chart-library="dygraph"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time32"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.cpu"
                                data-chart-library="dygraph"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time33"
-                               </div>
+                               ></div>
                </td>
        </tr>
        <tr>
@@ -197,39 +194,39 @@ This is a template for building custom dashboards. To build a dashboard you just
                <td>rendered in <span id="time32">X</span> ms</td>
                <td>rendered in <span id="time33">X</span> ms</td>
        </tr>
-       <tr><td colspan="3" align="center">&nbsp;</td></tr>
-       <tr><th colspan="3" align="center"><hr>Google Charts</th></tr>
-       <tr><td colspan="3" align="center">
+       <tr><td colspan="3">&nbsp;</td></tr>
+       <tr><th colspan="3"><hr>Google Charts</th></tr>
+       <tr><td colspan="3">
                NetData was originaly developed with Google Charts.
                NetData is a complete Google Visualization API provider.
                </td></tr>
        <tr>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.processes"
                                data-chart-library="google"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time51"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.ipv4"
                                data-chart-library="google"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time52"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.cpu"
                                data-chart-library="google"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time53"
-                               </div>
+                               ></div>
                </td>
        </tr>
        <tr>
@@ -237,39 +234,39 @@ This is a template for building custom dashboards. To build a dashboard you just
                <td>rendered in <span id="time52">X</span> ms</td>
                <td>rendered in <span id="time53">X</span> ms</td>
        </tr>
-       <tr><td colspan="3" align="center">&nbsp;</td></tr>
-       <tr><th colspan="3" align="center"><hr>Morris Charts</th></tr>
-       <tr><td colspan="3" align="center">
+       <tr><td colspan="3">&nbsp;</td></tr>
+       <tr><th colspan="3"><hr>Morris Charts</th></tr>
+       <tr><td colspan="3">
                Unfortunatelly, Morris Charts are veeeeeeeeeeeeeeeery slow! We force them to lower their detail to get acceptable results.
                And they have issues with negative numbers in area charts...
                </td></tr>
        <tr>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.processes"
                                data-chart-library="morris"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time41"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.ipv4"
                                data-chart-library="morris"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time42"
-                               </div>
+                               ></div>
                </td>
-               <td width="600" align="center">
+               <td width="600">
                        <div data-netdata="system.cpu"
                                data-chart-library="morris"
                                data-width="600"
                                data-height="200"
                                data-after="-600"
                                data-dt-element-name="time43"
-                               </div>
+                               ></div>
                </td>
        </tr>
        <tr>
index 9f4945aff27968f07e246cf52f2ec3db7d02cea1..d99a53eb48bcad1ddd2e1ecebb555fda7cff3323 100755 (executable)
@@ -67,9 +67,9 @@
        NETDATA.morris_js    = NETDATA.serverDefault + 'lib/morris.min.js';
        NETDATA.morris_css   = NETDATA.serverDefault + 'css/morris.css';
        NETDATA.google_js    = 'https://www.google.com/jsapi';
-       NETDATA.colors  = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', '#DD4477',
-               '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', '#6633CC', '#E67300', '#8B0707',
-               '#329262', '#5574A6', '#3B3EAC' ];
+       NETDATA.colors  = [ '#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6',
+                                               '#DD4477', '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11',
+                                               '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC' ];
 
        // ----------------------------------------------------------------------------------------------------------------
        // the defaults for all charts
                method: 'average',                              // the grouping method
                before: 0,                                              // panning
                after: -600,                                    // panning
-               point_width: 1,                                 // the detail of the chart
+               pixels_per_point: 1,                                    // the detail of the chart
        }
 
-       NETDATA.all_url = 'all2.js';
-       NETDATA.idle_between_charts = 50;
-       NETDATA.idle_between_loops = 100;
-       NETDATA.debug = 1;
+       NETDATA.options = {
+               targets: null,
+               updated_dom: 1,
+               debug: 1,
 
-       if(NETDATA.debug) console.log('welcome to NETDATA');
+               current: {
+                       pixels_per_point: 1,
+                       idle_between_charts: 50,
+                       idle_between_loops: 100,
+                       debug: 1
+               }
+       }
+
+       if(NETDATA.options.debug) console.log('welcome to NETDATA');
 
 
        // ----------------------------------------------------------------------------------------------------------------
                NETDATA.errorLast.datetime = 0;
        }
 
-       NETDATA.messageInABox = function(div, width, height, message) {
-               div.innerHTML = '<table border="0"><tr><td width="' + width + '" height="' + height
-                       + '" valign="middle" align="center">'
+       NETDATA.chartContainer = function(element, width, height) {
+               self = $(element);
+               self.css('width', width)
+                       .css('height', height)
+                       .css('display', 'inline-block')
+                       .css('overflow', 'hidden');
+       }
+
+       NETDATA.messageInABox = function(element, width, height, message) {
+               NETDATA.chartContainer(element, width, height);
+               element.innerHTML = '<div style="overflow: hidden; border: 0px; background-color: lightgrey; width: ' + width + '; height: ' + height + ';"><small>'
                        + message
-                       + '</td></tr></table>';
+                       + '</small></div>';
        }
 
        // ----------------------------------------------------------------------------------------------------------------
                        callback();
        }
 
-       NETDATA.generateDataURL = function(args) {
+       NETDATA.generateChartDataURL = function(options) {
                // build the data URL
-               var url = args.host + args.url;
+               var url = options.host + options.url;
                url += "&points=";
-               url += args.points.toString();
+               url += options.points.toString();
                url += "&group=";
-               url += args.method;
+               url += options.method;
                url += "&after=";
-               url += args.after || "0";
+               url += options.after || "0";
                url += "&before=";
-               url += args.before || "0";
-               url += "&options=" + NETDATA.chartLibraries[args.library].options + '|';
-               url += (args.non_zero)?"nonzero":"";
-               url += "&format=" + NETDATA.chartLibraries[args.library].format;
+               url += options.before || "0";
+               url += "&options=" + NETDATA.chartLibraries[options.library].options + '|';
+               url += (options.non_zero)?"nonzero":"";
+               url += "&format=" + NETDATA.chartLibraries[options.library].format;
 
-               if(args.dimensions)
-                       url += "&dimensions=" + args.dimensions;
+               if(options.dimensions)
+                       url += "&dimensions=" + options.dimensions;
 
-               if(NETDATA.debug) console.log('generateDataURL(' + args + ') = ' + url );
+               if(NETDATA.options.debug) console.log('generateChartDataURL(' + options + ') = ' + url );
                return url;
        }
 
-       NETDATA.loadCharts = function(targets, index, callback) {
-               if(NETDATA.debug) console.log('loadCharts(<targets, ' + index + ')');
+       NETDATA.parseDomCharts = function(targets, index, callback) {
+               if(NETDATA.options.debug) console.log('parseDomCharts() working on ' + index);
 
                var target = targets.get(index);
-
                if(target == null) {
-                       console.log('loaded all charts');
-                       callback();
+                       if(NETDATA.options.debug) console.log('parseDomCharts(): all ' + (index - 1) + ' charts parsed.');
+                       if(typeof callback == 'function') callback();
                }
                else {
                        var self = $(target);
+                       if(!self.data('prepared')) {
+                               self.data('prepared', true);
 
-                       if(!self.data('loaded')) {
                                var id = self.data('netdata');
-
                                var host = self.data('host') || NETDATA.chartDefaults.host;
                                var width = self.data('width') || NETDATA.chartDefaults.width;
                                var height = self.data('height') || NETDATA.chartDefaults.height;
                                var method = self.data('method') || NETDATA.chartDefaults.method;
                                var after = self.data('after') || NETDATA.chartDefaults.after;
                                var before = self.data('before') || NETDATA.chartDefaults.before;
-                               var host = self.data('host') || NETDATA.chartDefaults.host;
                                var library = self.data('chart-library') || NETDATA.chartDefaults.library;
                                var dimensions = self.data('dimensions') || null;
 
+                               NETDATA.chartContainer(target, width, height);
+                               if(NETDATA.options.debug) console.log('parseDomCharts() parsing ' + id + ' of type ' + library);
+
                                if(typeof NETDATA.chartLibraries[library] == 'undefined') {
+                                       self.data('created', false)
+                                               .data('updated', 0)
+                                               .data('enabled', false);
+
                                        NETDATA.error(402, library);
                                        NETDATA.messageInABox(target, width, height, 'chart library "' + library + '" is not found');
-                                       self.data('enabled', false);
-                                       NETDATA.loadCharts(targets, ++index, callback);
+
+                                       NETDATA.parseDomCharts(targets, ++index, callback);
                                }
                                else {
                                        var url = host + "/api/v1/chart?chart=" + id;
                                                crossDomain: true
                                        })
                                        .done(function(chart) {
+                                               var pixels_per_point = self.data('point-width') || NETDATA.chartLibraries[library].pixels_per_point;
+                                               var points = self.data('points') || Math.round(width / pixels_per_point);
 
-                                               var point_width = self.data('point-width') || NETDATA.chartLibraries[library].pixels;
-                                               var points = self.data('points') || Math.round(width / point_width);
-
-                                               var url = NETDATA.generateDataURL({
+                                               var url = NETDATA.generateChartDataURL({
                                                        host: host,
                                                        url: chart.data_url,
                                                        dimensions: dimensions,
                                                // done processing of this DIV
                                                // store the processing result, in
                                                // 'data' sections in the DIV
-                                               self
-                                                       .data('chart', chart)
+                                               self.data('chart', chart)
                                                        .data('chart-url', url)
-                                                       .data('last-updated', 0)
                                                        .data('update-every', chart.update_every * 1000)
-                                                       .data('enabled', true);
+                                                       .data('created', false)
+                                                       .data('updated', 0)
+                                                       .data('enabled', true)
+                                                       .data('host', host)
+                                                       .data('width', width)
+                                                       .data('height', height)
+                                                       .data('method', method)
+                                                       .data('after', after)
+                                                       .data('before', before)
+                                                       .data('chart-library', library)
+                                                       .data('dimensions', dimensions)
+                                                       ;
+                                               
+                                               NETDATA.messageInABox(target, width, height, 'chart "' + id + '" is loading...');
                                        })
                                        .fail(function() {
+                                               self.data('created', false)
+                                                       .data('enabled', false);
+
                                                NETDATA.error(404, url);
                                                NETDATA.messageInABox(target, width, height, 'chart "' + id + '" not found on url "' + url + '"');
-                                               self.data('enabled', false);
                                        })
                                        .always(function() {
-                                               NETDATA.loadCharts(targets, ++index, callback);
+                                               self.data('updated', 0);
+                                               NETDATA.parseDomCharts(targets, ++index, callback);
                                        });
                                }
                        }
                }
        }
 
-       function netdataParsePageCharts() {
-               if(NETDATA.debug) console.log('processing web page defined charts');
+       NETDATA.domUpdated = function(callback) {
+               NETDATA.options.updated_dom = 0;
 
-               // targets
-               // a list of all DIVs containing netdata charts
-
-               var targets = $('div[data-netdata]')
-               .bind('create', function(event, data) {
-                       var self = $(this);
-                       var lib = self.data('chart-library') || 'dygraph';
-                       var method = lib + 'ChartCreate';
+               NETDATA.options.targets = $('div[data-netdata]') // .filter(':visible')
+                       .bind('create', function(event, data) {
+                               var self = $(this);
+                               try {
+                                       NETDATA.chartLibraries[self.data('chart-library')].create(this, data);
+                               }
+                               catch(err) {
+                                       NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be created as ' + self.data('chart-library'));
+                               }
+                       })
+                       .bind('update', function(event, data) {
+                               var self = $(this);
+                               try {
+                                       NETDATA.chartLibraries[self.data('chart-library')].update(this, data);
+                               }
+                               catch(err) {
+                                       NETDATA.messageInABox(this, self.data('width'), self.data('height'), 'chart "' + id + '" failed to be updated as ' + self.data('chart-library'));
+                               }
+                       });
 
-                       console.log('Calling ' + method + '()');
-                       NETDATA[method].apply(this, arguments);
-               })
-               .bind('update', function() {
-                       var self = $(this);
-                       var lib = self.data('chart-library') || 'dygraph';
-                       var method = lib + 'ChartUpdate';
+               if(NETDATA.options.debug)
+                       console.log('DOM updated - there are ' + NETDATA.options.targets.length + ' charts on page.');
 
-                       console.log('Calling ' + method + '()');
-                       NETDATA[method].apply(this, arguments);
-               });
+               NETDATA.parseDomCharts(NETDATA.options.targets, 0, callback);
+       }
 
-               NETDATA.loadCharts(targets, 0, function() {
+       NETDATA.init = function() {
+               NETDATA.domUpdated(function() {
                        // done processing all netdata DIVs in this page
                        // call the refresh handler
-                       netdataRefreshTargets(targets, 0);
-               });
-       }
 
-       // ----------------------------------------------------------------------------------------------------------------
-       // Charts Libraries Registration
-
-       NETDATA.chartLibraries = {};
-
-       NETDATA.registerChartLibrary = function(library, url, format, options, min_pixels_per_point) {
-               console.log("registering chart library: " + library);
-
-               NETDATA.chartLibraries[library] = {
-                       initialized: new Date().getTime(),
-                       url: url,
-                       format: format,
-                       options: options,
-                       pixels: min_pixels_per_point
-               };
-
-               console.log(NETDATA.chartLibraries);
+                       // FIXME
+                       NETDATA.chartRefresher(0);
+               });
        }
 
        // ----------------------------------------------------------------------------------------------------------------
        //var c = new chart();
        //c.color();
 
-       function netdataDownloadChartData(callback) {
-               var self = $(this);
-               var last = self.data('last-updated') || 0;
+       NETDATA.chartValuesDownloader = function(element, callback) {
+               var self = $(element);
+               var last = self.data('updated') || 0;
                var every = self.data('update-every') || 1;
 
                // check if this chart has to be refreshed now
                var now = new Date().getTime();
                if(last + every > now) {
-                       if(typeof callback == 'function')
-                               callback();
+                       console.log(self.data('netdata') + ' too soon - skipping.');
+                       if(typeof callback == 'function') callback();
+               }
+               else if(!self.visible(true)) {
+                       console.log(self.data('netdata') + ' is NOT visible.');
+                       if(typeof callback == 'function') callback();
                }
                else {
-                       var url = self.data('chart-url');
-
-                       if(NETDATA.debug) console.log('netdataDownloadChartData(): downloading ' + url);
-
+                       console.log(self.data('netdata') + ' is visible, downloading data...');
                        $.ajax( {
-                               url: url,
+                               url: self.data('chart-url'),
                                crossDomain: true
                        })
                        .then(function(data) {
-                               //var result = $.map(data.rows, function(item) {
-                                       // get from the 3rd column the 'v' member
-                                       //return item.c[3].v;
-                               //});
-
-                               // since we downloaded the data
-                               // update the last-updated time to prevent
-                               // another download too soon
-                               self.data('last-updated', new Date().getTime());
-
-                               // render it
-                               var created = self.data('created');
-                               self.trigger((created ? 'update' : 'create'), [data]).data('created', true)
-                       })
-                       .fail(function() {
-                               console.log('failed to download chart data');
-                       })
-                       .always(function() {
-                               var last = self.data('last-updated');
-                               var now = new Date().getTime();
-                               var dt = now - last;
-                               self.data('refresh-dt', dt);
+                               var started = new Date().getTime();
+
+                               if(self.data('created')) {
+                                       console.log('updating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
+                                       self.trigger('update', [data]);
+                                       // NETDATA.chartLibraries[self.data('chart-library')].update(element, data);
+                               }
+                               else {
+                                       console.log('creating ' + self.data('chart-library') + ' chart ' + self.data('netdata'));
+                                       self.trigger('create', [data]);
+                                       //NETDATA.chartLibraries[self.data('chart-library')].create(element, data);
+                                       self.data('created', true);
+                               }
 
+                               var ended = new Date().getTime();
+                               self.data('updated', ended);
+
+                               var dt = ended - started;
+
+                               self.data('refresh-dt', dt);
                                var element_name = self.data('dt-element-name') || null;
                                if(element_name) {
                                        var element = document.getElementById(element_name) || null;
                                                element.innerHTML = dt.toString();
                                        }
                                }
-
-                               if(typeof callback == 'function')
-                                       callback();
+                       })
+                       .fail(function() {
+                               NETDATA.messageInABox(element, width, height, 'chart "' + id + '" not found on url "' + url + '"');
+                       })
+                       .always(function() {
+                               if(typeof callback == 'function') callback();
                        });
                }
        };
 
-       function netdataRefreshTargets(targets, index) {
-               // if(NETDATA.debug) console.log('netdataRefreshTargets(<targets, ' + index + ')');
-
-               var target = targets.get(index);
-
-               if(target == null) {
-                       console.log('restart');
+       NETDATA.chartRefresher = function(index) {
+               // if(NETDATA.options.debug) console.log('NETDATA.chartRefresher(<targets, ' + index + ')');
 
-                       // finished, restart
-                       setTimeout(function() {
-                               netdataRefreshTargets(targets, 0);
-                       }, NETDATA.idle_between_loops);
+               if(NETDATA.options.updated_dom) {
+                       NETDATA.domUpdated(function() {
+                               NETDATA.chartRefresher(0);
+                       });
                }
                else {
-                       var self = $(target);
+                       var target = NETDATA.options.targets.get(index);
+                       if(target == null) {
+                               console.log('waiting to restart main loop...');
 
-                       if(!self.data('enabled')) {
-                               netdataRefreshTargets(targets, ++index);
+                               // finished, restart
+                               setTimeout(function() {
+                                       NETDATA.chartRefresher(0);
+                               }, NETDATA.options.current.idle_between_loops);
                        }
                        else {
-                               setTimeout(function() {
-                                       netdataDownloadChartData.call(target, function() {
-                                               netdataRefreshTargets(targets, ++index);
-                                       });
-                               }, NETDATA.idle_between_charts);
+                               var self = $(target);
+                               if(!self.data('enabled')) {
+                                       NETDATA.chartRefresher(++index);
+                               }
+                               else {
+                                       setTimeout(function() {
+                                               NETDATA.chartValuesDownloader(target, function() {
+                                                       NETDATA.chartRefresher(++index);
+                                               });
+                                       }, NETDATA.options.current.idle_between_charts);
+                               }
                        }
                }
        }
                if(typeof netdataStopPeity == 'undefined') {
                        $.getScript(NETDATA.peity_js)
                                .done(function() {
-                                       NETDATA.registerChartLibrary('peity', NETDATA.peity_js, 'ssvcomma', 'null2zero|flip|min2max', 2);
+                                       NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
                                })
                                .fail(function() {
                                        NETDATA.error(100, NETDATA.peity_js);
                        callback();
        };
 
-       NETDATA.peityChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.peityChartUpdate = function(element, data) {
+               var self = $(element);
                var instance = self.html(data).not('[data-created]');
                instance.change();
        }
 
-       NETDATA.peityChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.peityChartCreate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var instance = self.html(data).not('[data-created]');
                if(typeof netdataStopSparkline == 'undefined') {
                        $.getScript(NETDATA.sparkline_js)
                                .done(function() {
-                                       NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js, 'array', 'flip|min2max', 2);
+                                       NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
                                })
                                .fail(function() {
                                        NETDATA.error(100, NETDATA.sparkline_js);
                        callback();
        };
 
-       NETDATA.sparklineChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.sparklineChartUpdate = function(element, data) {
+               var self = $(element);
                var options = self.data('sparkline-options');
                self.sparkline(data, options);
        }
 
-       NETDATA.sparklineChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.sparklineChartCreate = function(element, data) {
+               var self = $(element);
                var chart = self.data('chart');
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                };
 
                var uuid = NETDATA.guid();
-               this.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
+               element.innerHTML = '<div style="display: inline-block; position: relative;" id="' + uuid + '"></div>';
                var div = document.getElementById(uuid);
 
                self.sparkline(data, options);
                if(typeof netdataStopDygraph == 'undefined') {
                        $.getScript(NETDATA.dygraph_js)
                                .done(function() {
-                                       NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js, 'json', 'ms|flip', 2);
+                                       NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
                                })
                                .fail(function() {
                                        NETDATA.error(100, NETDATA.dygraph_js);
                        callback();
        };
 
-       NETDATA.dygraphChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.dygraphChartUpdate = function(element, data) {
+               var self = $(element);
                var dygraph = self.data('dygraph-instance');
 
                if(typeof data.update_every != 'undefined')
                        console.log('not updating dygraphs');
        };
 
-       NETDATA.dygraphChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.dygraphChartCreate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var chart = self.data('chart');
 
                        $.getScript(NETDATA.morris_js)
                                .done(function() {
-                                       NETDATA.registerChartLibrary('morris', NETDATA.morris_js, 'json', 'objectrows|ms', 10);
+                                       NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
                                })
                                .fail(function() {
                                        NETDATA.error(100, NETDATA.morris_js);
                        callback();
        };
 
-       NETDATA.morrisChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.morrisChartUpdate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var morris = self.data('morris-instance');
                        console.log('not updating morris');
        };
 
-       NETDATA.morrisChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.morrisChartCreate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var chart = self.data('chart');
                if(typeof netdataStopRaphael == 'undefined') {
                        $.getScript(NETDATA.raphael_js)
                                .done(function() {
-                                       NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js, 'json', 'flip|min2max', 1);
+                                       NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
                                })
                                .fail(function() {
                                        NETDATA.error(100, NETDATA.raphael_js);
                        callback();
        };
 
-       NETDATA.raphaelChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.raphaelChartUpdate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
 
                })
        };
 
-       NETDATA.raphaelChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.raphaelChartCreate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
 
 
        NETDATA.googleInitialize = function(callback) {
                if(typeof netdataStopGoogleCharts == 'undefined' && typeof google != 'undefined') {
-                       NETDATA.registerChartLibrary('google', NETDATA.google_js, 'datatable', '', 3);
+                       NETDATA.registerChartLibrary('google', NETDATA.google_js);
                        if(typeof callback == "function")
                                callback();
                }
                        callback();
        };
 
-       NETDATA.googleChartUpdate = function(event, data) {
-               var self = $(this);
+       NETDATA.googleChartUpdate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var gchart = self.data('google-instance');
                gchart.draw(datatable, options);
        };
 
-       NETDATA.googleChartCreate = function(event, data) {
-               var self = $(this);
+       NETDATA.googleChartCreate = function(element, data) {
+               var self = $(element);
                var width = self.data('width') || NETDATA.chartDefaults.width;
                var height = self.data('height') || NETDATA.chartDefaults.height;
                var chart = self.data('chart');
                switch(chart.chart_type) {
                        case "area":
                                options.vAxis.viewWindowMode = 'maximized';
-                               gchart = new google.visualization.AreaChart(this);
+                               gchart = new google.visualization.AreaChart(element);
                                break;
 
                        case "stacked":
                                options.vAxis.viewWindowMode = 'maximized';
                                options.vAxis.minValue = null;
                                options.vAxis.maxValue = null;
-                               gchart = new google.visualization.AreaChart(this);
+                               gchart = new google.visualization.AreaChart(element);
                                break;
 
                        default:
                        case "line":
                                options.lineWidth = 2;
-                               gchart = new google.visualization.LineChart(this);
+                               gchart = new google.visualization.LineChart(element);
                                break;
                }
 
                .data('created', true);
        };
 
+       // ----------------------------------------------------------------------------------------------------------------
+       // Charts Libraries Registration
+
+       NETDATA.chartLibraries = {
+               "dygraph": {
+                       initialize: NETDATA.dygraphInitialize,
+                       create: NETDATA.dygraphChartCreate,
+                       update: NETDATA.dygraphChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'json',
+                       options: 'ms|flip',
+                       pixels_per_point: 2,
+                       detects_dimensions_on_update: false
+               },
+               "sparkline": {
+                       initialize: NETDATA.sparklineInitialize,
+                       create: NETDATA.sparklineChartCreate,
+                       update: NETDATA.sparklineChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'array',
+                       options: 'flip|min2max',
+                       pixels_per_point: 2,
+                       detects_dimensions_on_update: false
+               },
+               "peity": {
+                       initialize: NETDATA.peityInitialize,
+                       create: NETDATA.peityChartCreate,
+                       update: NETDATA.peityChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'ssvcomma',
+                       options: 'null2zero|flip|min2max',
+                       pixels_per_point: 2,
+                       detects_dimensions_on_update: false
+               },
+               "morris": {
+                       initialize: NETDATA.morrisInitialize,
+                       create: NETDATA.morrisChartCreate,
+                       update: NETDATA.morrisChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'json',
+                       options: 'objectrows|ms',
+                       pixels_per_point: 10,
+                       detects_dimensions_on_update: false
+               },
+               "google": {
+                       initialize: NETDATA.googleInitialize,
+                       create: NETDATA.googleChartCreate,
+                       update: NETDATA.googleChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'datatable',
+                       options: '',
+                       pixels_per_point: 2,
+                       detects_dimensions_on_update: true
+               },
+               "raphael": {
+                       initialize: NETDATA.raphaelInitialize,
+                       create: NETDATA.raphaelChartCreate,
+                       update: NETDATA.raphaelChartUpdate,
+                       initialized: false,
+                       enabled: true,
+                       format: 'json',
+                       options: '',
+                       pixels_per_point: 1,
+                       detects_dimensions_on_update: false
+               }
+       };
+
+       NETDATA.registerChartLibrary = function(library, url) {
+               console.log("registering chart library: " + library);
+
+               NETDATA.chartLibraries[library]
+                       .url = url
+                       .initialized = new Date().getTime();
+
+               console.log(NETDATA.chartLibraries);
+       }
+
        // ----------------------------------------------------------------------------------------------------------------
        // load all libraries and initialize
 
        NETDATA.errorReset();
 
        NETDATA._loadjQuery(function() {
-               NETDATA.raphaelInitialize(function() {
-                       NETDATA.morrisInitialize(function() {
-                               NETDATA.peityInitialize(function() {
-                                       NETDATA.sparklineInitialize(function() {
-                                               NETDATA.dygraphInitialize(function() {
-                                                       NETDATA.googleInitialize(function() {
-                                                               netdataParsePageCharts();
-                                                       }) // google
-                                               }) // dygraph.js
-                                       }) // sparkline.js
-                               }) // piety.js
-                       }) // morris.js
-               }) // raphael.js
+               $.getScript(NETDATA.serverDefault + 'lib/visible.js').then(function() {
+                       NETDATA.raphaelInitialize(function() {
+                               NETDATA.morrisInitialize(function() {
+                                       NETDATA.peityInitialize(function() {
+                                               NETDATA.sparklineInitialize(function() {
+                                                       NETDATA.dygraphInitialize(function() {
+                                                               NETDATA.googleInitialize(function() {
+                                                                       NETDATA.init();
+                                                               }) // google
+                                                       }) // dygraph.js
+                                               }) // sparkline.js
+                                       }) // piety.js
+                               }) // morris.js
+                       }) // raphael.js
+               })
        });
 
 })(window);
-
diff --git a/web/lib/visible.js b/web/lib/visible.js
new file mode 100755 (executable)
index 0000000..bfe1624
--- /dev/null
@@ -0,0 +1,26 @@
+(function($){
+
+       /**
+        * Copyright 2012, Digital Fusion
+        * Licensed under the MIT license.
+        * http://teamdf.com/jquery-plugins/license/
+        *
+        * @author Sam Sehnert
+        * @desc A small plugin that checks whether elements are within
+        *               the user visible viewport of a web browser.
+        *               only accounts for vertical position, not horizontal.
+        */
+       $.fn.visible = function(partial){
+
+           var $t                              = $(this),
+               $w                              = $(window),
+               viewTop                 = $w.scrollTop(),
+               viewBottom              = viewTop + $w.height(),
+               _top                    = $t.offset().top,
+               _bottom                 = _top + $t.height(),
+               compareTop              = partial === true ? _bottom : _top,
+               compareBottom   = partial === true ? _top : _bottom;
+
+               return ((compareBottom <= viewBottom) && (compareTop >= viewTop));
+    };
+})(jQuery);