@cryptotaxi247 / netdata-1 / commits / 810f14d02

added support for empty charts; now the javascript tracks colors per dimension to assign the same color on any instance of the chart; various optimizations; nonzero option is now properly supported

Costa Tsaousis (ktsaou) committed Dec 16, 2015 at 04:32 UTC 810f14d024d8926d823f52c84e9ea0eab4f665f7
4 files changed +438 -209
src/rrd2json.c
+68 -16
@@ -425,8 +425,34 @@ void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
425 }
426 }
427
428 +uint32_t rrdr_check_options(RRDR *r, uint32_t options)
429 +{
430 + if(options & RRDR_OPTION_NONZERO) {
431 + long c, i;
432 + RRDDIM *rd;
433 +
434 + // find how many dimensions are not zero
435 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
436 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
437 + if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
438 + i++;
439 + }
440 +
441 + // if with nonzero we get i = 0
442 + // but c != 0, then disable nonzero
443 + // to show all dimensions
444 + if(!i) options &= ~RRDR_OPTION_NONZERO;
445 + }
446 +
447 + return options;
448 +}
449 +
450 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
451 {
452 + int rows = rrdr_rows(r);
453 + long c, i;
454 + RRDDIM *rd;
455 +
456 //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
457 char kq[2] = "", // key quote
458 sq[2] = ""; // string quote
@@ -441,13 +467,15 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
467 }
468
469 buffer_sprintf(wb, "{\n"
470 + " %sapi%s: 1,\n"
471 " %sid%s: %s%s%s,\n"
472 " %sname%s: %s%s%s,\n"
473 " %sview_update_every%s: %d,\n"
474 " %supdate_every%s: %d,\n"
448 - " %sfirst_entry_t%s: %u, \n"
449 - " %slast_entry_t%s: %u, \n"
475 + " %sfirst_entry_t%s: %u,\n"
476 + " %slast_entry_t%s: %u,\n"
477 " %smin%s: "
478 + , kq, kq
479 , kq, kq, sq, r->st->id, sq
480 , kq, kq, sq, r->st->name, sq
481 , kq, kq, r->update_every
@@ -467,10 +495,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
495 , kq, kq, r->after
496 , kq, kq);
497
470 -
471 - long c, i;
472 - RRDDIM *rd;
473 - for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
498 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
499 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
500 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
501
@@ -480,11 +505,18 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
505 buffer_strcat(wb, sq);
506 i++;
507 }
508 + if(!i) {
509 + rows = 0;
510 + buffer_strcat(wb, sq);
511 + buffer_strcat(wb, "no data");
512 + buffer_strcat(wb, sq);
513 + }
514 +
515 buffer_sprintf(wb, "],\n"
516 " %sdimension_ids%s: ["
517 , kq, kq);
518
487 - for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
519 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
520 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
521 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
522
@@ -494,11 +526,18 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
526 buffer_strcat(wb, sq);
527 i++;
528 }
529 + if(!i) {
530 + rows = 0;
531 + buffer_strcat(wb, sq);
532 + buffer_strcat(wb, "no data");
533 + buffer_strcat(wb, sq);
534 + }
535 +
536 buffer_sprintf(wb, "],\n"
537 " %slatest_values%s: ["
538 , kq, kq);
539
501 - for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
540 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
541 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
542 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
543
@@ -512,12 +551,18 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
551 else
552 buffer_rrd_value(wb, unpack_storage_number(n));
553 }
554 + if(!i) {
555 + rows = 0;
556 + buffer_strcat(wb, "null");
557 + }
558 +
559 buffer_sprintf(wb, "],\n"
560 " %sresult_latest_values%s: ["
561 , kq, kq);
562
519 - if(rrdr_rows(r)) {
520 - for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
563 + i = 0;
564 + if(rows) {
565 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
566 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
567 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
568
@@ -533,12 +578,17 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t opti
578 buffer_rrd_value(wb, cn[c]);
579 }
580 }
581 + if(!i) {
582 + rows = 0;
583 + buffer_strcat(wb, "null");
584 + }
585 +
586 buffer_sprintf(wb, "],\n"
587 " %sdimensions%s: %d,\n"
588 " %spoints%s: %d,\n"
589 " %sformat%s: %s"
590 , kq, kq, i
541 - , kq, kq, rrdr_rows(r)
591 + , kq, kq, rows
592 , kq, kq, sq
593 );
594
@@ -661,7 +711,7 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
711 RRDDIM *rd;
712
713 // print the header lines
664 - for(c = 0, i = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
714 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
715 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
716 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
717
@@ -747,7 +797,7 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
797 }
798
799 // for each dimension
750 - for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
800 + for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
801 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
802 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
803
@@ -786,7 +836,7 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
836 RRDDIM *d;
837
838 // print the csv header
789 - for(c = 0, i = 0, d = r->st->dimensions; d ;c++, d = d->next) {
839 + for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
840 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
841 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
842
@@ -835,7 +885,7 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
885 }
886
887 // for each dimension
838 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
888 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
889 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
890 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
891
@@ -884,7 +934,7 @@ static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix,
934 int all_null = 1, init = 1;
935
936 // for each dimension
887 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
937 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
938 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
939 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
940
@@ -1333,6 +1383,8 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
1383 return 500;
1384 }
1385
1386 + options = rrdr_check_options(r, options);
1387 +
1388 if(dimensions)
1389 rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1390
web/dashboard.html
+11
@@ -326,6 +326,17 @@ Sparklines using dygraphs
326 <br/>
327 <small>rendered in <span id="time208">X</span> ms</small>
328 </div>
329 +<div style="width: 33%; display: inline-block;">
330 + <div data-netdata="net.gstag0"
331 + data-chart-library="dygraph"
332 + data-width="100%"
333 + data-height="200"
334 + data-after="-300"
335 + data-dt-element-name="time209"
336 + ></div>
337 + <br/>
338 + <small>rendered in <span id="time209">X</span> ms</small>
339 +</div>
340
341
342
web/dashboard.js
+358 -192
@@ -5,6 +5,8 @@
5 // var netdataNoPeitys = true; // do not use peity
6 // var netdataNoGoogleCharts = true; // do not use google
7 // var netdataNoMorris = true; // do not use morris
8 +// var netdataNoEasyPieChart = true; // do not use easy pie chart
9 +// var netdataNoBootstrap = true; // do not load bootstrap
10 // var netdataDontStart = true; // do not start the thread to process the charts
11 //
12 // You can also set the default netdata server, using the following.
@@ -13,7 +15,7 @@
15 // var netdataServer = "http://yourhost:19999"; // set your NetData server
16
17 //(function(window, document, undefined) {
16 - // fix IE bug with console
18 + // fix IE issue with console
19 if(!window.console){ window.console = {log: function(){} }; }
20
21 // global namespace
@@ -161,15 +163,17 @@
163
164 idle_between_charts: 100, // ms - how much time to wait between chart updates
165
164 - fast_render_timeframe: 100, // ms - render continously until this time of continious
166 + fast_render_timeframe: 200, // ms - render continously until this time of continious
167 // rendering has been reached
168 // this setting is used to make it render e.g. 10
169 // charts at once, sleep idle_between_charts time
170 // and continue for another 10 charts.
171
170 - idle_between_loops: 200, // ms - if all charts have been updated, wait this
172 + idle_between_loops: 500, // ms - if all charts have been updated, wait this
173 // time before starting again.
174
175 + idle_parallel_loops: 100, // ms - the time between parallel refresher updates
176 +
177 idle_lost_focus: 500, // ms - when the window does not have focus, check
178 // if focus has been regained, every this time
179
@@ -193,6 +197,8 @@
197
198 destroy_on_hide: false, // destroy charts when they are not visible
199
200 + eliminate_zero_dimensions: true, // do not show dimensions with just zeros
201 +
202 color_fill_opacity: {
203 line: 1.0,
204 area: 0.2,
@@ -223,6 +229,7 @@
229
230 window.onscroll = function(event) {
231 NETDATA.options.last_page_scroll = new Date().getTime();
232 + if(NETDATA.options.targets === null) return;
233
234 // when the user scrolls he sees that we have
235 // hidden all the not-visible charts
@@ -453,6 +460,8 @@
460 library: null, // object - the chart library used
461
462 colors: null,
463 + colors_assigned: {},
464 + colors_available: null,
465
466 element: element, // the element already created by the user
467 element_message: null,
@@ -889,7 +898,7 @@
898 }
899
900 chartState.prototype.legendFormatValue = function(value) {
892 - if(value === null) return '-';
901 + if(value === null || value === 'undefined') return '-';
902 if(typeof value !== 'number') return value;
903
904 var abs = Math.abs(value);
@@ -915,7 +924,7 @@
924
925 chartState.prototype.legendSetDate = function(ms) {
926 if(typeof ms !== 'number') {
918 - this.legendUndefined();
927 + this.legendShowUndefined();
928 return;
929 }
930
@@ -931,7 +940,7 @@
940 this.element_legend_childs.title_units.innerHTML = this.chart.units;
941 }
942
934 - chartState.prototype.legendUndefined = function() {
943 + chartState.prototype.legendShowUndefined = function() {
944 if(this.element_legend_childs.title_date)
945 this.element_legend_childs.title_date.innerHTML = '&nbsp;';
946
@@ -959,7 +968,7 @@
968 if(this.selected) return;
969
970 if(this.current.data === null || this.element_legend_childs.series === null) {
962 - this.legendUndefined();
971 + this.legendShowUndefined();
972 return;
973 }
974
@@ -968,7 +977,7 @@
977 show_undefined = false;
978
979 if(show_undefined)
971 - this.legendUndefined();
980 + this.legendShowUndefined();
981 else
982 this.legendSetDate(this.current.data.before * 1000);
983
@@ -991,28 +1000,51 @@
1000 this.legendShowLatestValues();
1001 }
1002
1003 + // this should be called just ONCE per dimension per chart
1004 + chartState.prototype._chartDimensionColor = function(label) {
1005 + if(this.colors === null)
1006 + this.chartColors();
1007 +
1008 + if(typeof this.colors_assigned[label] === 'undefined') {
1009 + if(this.colors_available.length === 0) {
1010 + for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1011 + this.colors_available.push(NETDATA.colors[i]);
1012 + }
1013 +
1014 + this.colors_assigned[label] = this.colors_available.shift();
1015 + if(this.debug) this.log('label "' + label + '" got color "' + this.colors_assigned[label]);
1016 + }
1017 + else {
1018 + if(this.debug) this.log('label "' + label + '" already has color "' + this.colors_assigned[label] + '"');
1019 + }
1020 +
1021 + this.colors.push(this.colors_assigned[label]);
1022 + return this.colors_assigned[label];
1023 + }
1024 +
1025 chartState.prototype.chartColors = function() {
1026 if(this.colors !== null) return this.colors;
1027
997 - this.colors = $(this.element).data('colors');
998 - if(typeof this.colors === 'undefined' || this.colors === null)
999 - this.colors = NETDATA.colors;
1000 - else {
1001 - // console.log(this.colors);
1002 - var s = this.colors;
1003 - if(typeof s === 'string') s = s.split(' ');
1028 + this.colors = new Array();
1029
1005 - this.colors = new Array();
1006 - var self = this;
1007 - $.each(s, function(i, c) {
1008 - self.colors.push(c);
1009 - });
1030 + if(this.colors_available === null) {
1031 + this.colors_available = new Array();
1032
1011 - // push the default colors too
1012 - var self = this;
1013 - $.each(NETDATA.colors, function(i, c) {
1014 - self.colors.push(c);
1015 - });
1033 + var c = $(this.element).data('colors');
1034 + if(typeof c !== 'undefined' && c !== null) {
1035 + if(typeof c !== 'string') {
1036 + this.log('invalid color given: ' + c + ' (give a space separated list of colors)');
1037 + }
1038 + else {
1039 + c = c.split(' ');
1040 + for(var i = 0, len = c.length; i < len ; i++)
1041 + this.colors_available.push(c[i]);
1042 + }
1043 + }
1044 +
1045 + // push all the standard colors too
1046 + for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1047 + this.colors_available.push(NETDATA.colors[i]);
1048 }
1049
1050 return this.colors;
@@ -1030,31 +1062,47 @@
1062 // this.log('the chart does not have any data - requesting legend update');
1063 needed = true;
1064 }
1065 + else if(typeof this.element_legend_childs.series.labels_key === 'undefined') {
1066 + needed = true;
1067 + }
1068 else {
1034 - // this.log('checking existing legend');
1035 - var labels = this.current.data.dimension_names;
1036 - var i = labels.length;
1037 - while(i--) {
1038 - var name = labels[i];
1039 - if(typeof this.element_legend_childs.series[name] === 'undefined') {
1040 - // this.log('legend is incosistent - missing dimension:' + name);
1041 - needed = true;
1042 - break;
1043 - }
1044 - else if(Math.abs(this.current.data.last_entry_t - this.current.data.before) <= this.current.data.view_update_every) {
1045 - // this.log('setting legend of ' + name + ' to ' + this.current.data.latest_values[i]);
1046 - this.legendSetLabelValue(name, this.current.data.latest_values[i]);
1047 - }
1069 + var labels = this.current.data.dimension_names.toString();
1070 + if(labels !== this.element_legend_childs.series.labels_key) {
1071 + needed = true;
1072 + if(this.debug) this.log('NEW LABELS: "' + labels + '" NOT EQUAL OLD LABELS: "' + this.element_legend_childs.series.labels_key + '"');
1073 }
1074 }
1075
1051 - if(!needed) return;
1076 + if(!needed) {
1077 + // make sure there are colors available
1078 + if(this.colors === null) this.colors = NETDATA.colors;
1079 +
1080 + // do we have to update the current values?
1081 + // we do this, only when the visible chart is current
1082 + if(Math.abs(this.current.data.last_entry_t - this.current.data.before) <= this.current.data.view_update_every) {
1083 + if(this.debug) this.log('chart in running... updating values on legend...');
1084 + var labels = this.current.data.dimension_names;
1085 + var i = labels.length;
1086 + while(i--)
1087 + this.legendSetLabelValue(labels[i], this.current.data.latest_values[i]);
1088 + }
1089 + return;
1090 + }
1091 + if(this.colors === null) {
1092 + // this is the first time we update the chart
1093 + // let's assign colors to all dimensions
1094 + if(this.library.track_colors() === true)
1095 + for(var dim in this.chart.dimensions)
1096 + this._chartDimensionColor(this.chart.dimensions[dim].name);
1097 + }
1098 + // we will re-generate the colors for the chart
1099 + this.colors = null;
1100
1101 if(this.debug) this.log('updating Legend DOM');
1102
1103 self = $(this.element);
1104 var genLabel = function(state, parent, name, count) {
1057 - var c = count % state.chartColors().length;
1105 + var color = state._chartDimensionColor(name);
1106
1107 var user_element = null;
1108 var user_id = self.data('show-value-of-' + name + '-at') || null;
@@ -1078,7 +1126,7 @@
1126 label.name.title = name;
1127 label.value.title = name;
1128
1081 - var rgb = NETDATA.colorHex2Rgb(state.chartColors()[c]);
1129 + var rgb = NETDATA.colorHex2Rgb(color);
1130 label.name.innerHTML = '<table class="netdata-legend-name-table-'
1131 + state.chart.chart_type
1132 + '" style="background-color: '
@@ -1088,8 +1136,8 @@
1136 var text = document.createTextNode(' ' + name);
1137 label.name.appendChild(text);
1138
1091 - label.name.style.color = state.chartColors()[c];
1092 - label.value.style.color = state.chartColors()[c];
1139 + label.name.style.color = color;
1140 + label.value.style.color = color;
1141
1142 if(count > 0)
1143 parent.appendChild(document.createElement('br'));
@@ -1154,16 +1202,21 @@
1202 }
1203
1204 if(this.current.data) {
1157 - var me = this;
1158 - $.each(me.current.data.dimension_names, function(i, d) {
1159 - genLabel(me, content, d, i);
1160 - });
1205 + this.element_legend_childs.series.labels_key = this.current.data.dimension_names.toString();
1206 + if(this.debug) this.log('SET DATA LABELS: "' + this.element_legend_childs.series.labels_key + '"');
1207 +
1208 + for(var i = 0, len = this.current.data.dimension_names.length; i < len ;i++) {
1209 + genLabel(this, content, this.current.data.dimension_names[i], i);
1210 + }
1211 }
1212 else {
1163 - var me = this;
1164 - $.each(me.chart.dimensions, function(i, d) {
1165 - genLabel(me, content, d.name, i);
1166 - });
1213 + var tmp = new Array();
1214 + for(var dim in this.chart.dimensions) {
1215 + tmp.push(this.chart.dimensions[dim].name);
1216 + genLabel(this, content, this.chart.dimensions[dim].name, i);
1217 + }
1218 + this.element_legend_childs.series.labels_key = tmp.toString();
1219 + if(this.debug) this.log('SET DEFAULT LABELS: "' + this.element_legend_childs.series.labels_key + '"');
1220 }
1221
1222 // create a hidden div to be used for hidding
@@ -1291,6 +1344,9 @@
1344 this.current.url += "&options=" + this.library.options();
1345 this.current.url += '|jsonwrap';
1346
1347 + if(NETDATA.options.current.eliminate_zero_dimensions === true)
1348 + this.current.url += '|nonzero';
1349 +
1350 if(after)
1351 this.current.url += "&after=" + after.toString();
1352
@@ -1306,8 +1362,10 @@
1362 chartState.prototype.updateChartWithData = function(data) {
1363 if(this.debug) this.log('got data from netdata server');
1364 this.current.data = data;
1365 + this.updates_counter++;
1366
1310 - var started = this.tm.last_updated = new Date().getTime();
1367 + var started = new Date().getTime();
1368 + this.tm.last_updated = started;
1369
1370 // if the result is JSON, find the latest update-every
1371 if(typeof data === 'object') {
@@ -1332,8 +1390,6 @@
1390 data.state = this;
1391 }
1392
1335 - this.updates_counter++;
1336 -
1393 if(this.debug) {
1394 this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
1395
@@ -1347,6 +1403,11 @@
1403 this.log('STATUS: points : ' + (this.current.points).toString() + ', min step: ' + (this._minPanOrZoomStep() / 1000).toString());
1404 }
1405
1406 + if(data.points === 0) {
1407 + this.noData();
1408 + return;
1409 + }
1410 +
1411 // this may force the chart to be re-created
1412 this.resizeChart();
1413
@@ -1403,8 +1464,12 @@
1464 // forced to be updated with global PanAndZoom
1465 if(NETDATA.globalPanAndZoom.isActive())
1466 this.current.last_autorefreshed = 0;
1406 - else
1407 - this.current.last_autorefreshed = now;
1467 + else {
1468 + //if(NETDATA.options.current.parallel_refresher === true)
1469 + // this.current.last_autorefreshed = Math.round(now / 1000) * 1000;
1470 + //else
1471 + this.current.last_autorefreshed = now;
1472 + }
1473
1474 this.refresh_dt_ms = now - started;
1475 NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
@@ -1429,9 +1494,16 @@
1494 }
1495
1496 if(this.library.initialized === false) {
1432 - var self = this;
1433 - this.library.initialize(function() { self.updateChart(callback); });
1434 - return;
1497 + if(this.library.enabled === true) {
1498 + var self = this;
1499 + this.library.initialize(function() { self.updateChart(callback); });
1500 + return;
1501 + }
1502 + else {
1503 + this.error('chart library "' + this.library_name + '" is not available.');
1504 + if(typeof callback === 'function') callback();
1505 + return false;
1506 + }
1507 }
1508
1509 this.clearSelection();
@@ -1462,6 +1534,8 @@
1534 }
1535
1536 chartState.prototype.destroyChart = function() {
1537 + if(this.debug === true) this.log('destroying chart');
1538 +
1539 this.current.last_autorefreshed = new Date().getTime();
1540
1541 if(this.element_message !== null) {
@@ -1528,6 +1602,8 @@
1602
1603 chartState.prototype.unhideChart = function() {
1604 if(typeof this.___isHidden___ !== 'undefined' && this.enabled === true) {
1605 + if(this.debug === true) this.log('unhiding chart');
1606 +
1607 this.element_message.style.display = 'none';
1608 if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
1609 if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
@@ -1548,6 +1624,7 @@
1624 if(NETDATA.options.current.destroy_on_hide === true)
1625 this.destroyChart();
1626
1627 + if(this.debug === true) this.log('hiding chart');
1628 this.element_message.style.display = 'inline-block';
1629 if(this.element_chart !== null) this.element_chart.style.display = 'none';
1630 if(this.element_legend !== null) this.element_legend.style.display = 'none';
@@ -1561,6 +1638,8 @@
1638
1639 chartState.prototype.hideLoading = function() {
1640 if(typeof this.___showsLoading___ !== 'undefined' && this.enabled === true) {
1641 + if(this.debug === true) this.log('hide loading...');
1642 +
1643 this.element_message.style.display = 'none';
1644 if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
1645 if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
@@ -1573,6 +1652,8 @@
1652
1653 chartState.prototype.showLoading = function() {
1654 if(typeof this.___showsLoading___ === 'undefined' && this.tm.last_created === 0 && this.enabled === true) {
1655 + if(this.debug === true) this.log('show loading...');
1656 +
1657 this.element_message.style.display = 'none';
1658 if(this.element_chart !== null) this.element_chart.style.display = 'none';
1659 if(this.element_legend !== null) this.element_legend.style.display = 'none';
@@ -1586,8 +1667,10 @@
1667
1668 chartState.prototype.isVisible = function() {
1669 // this.log('last_visible_check: ' + this.tm.last_visible_check + ', last_page_scroll: ' + NETDATA.options.last_page_scroll);
1589 - if(this.tm.last_visible_check > NETDATA.options.last_page_scroll)
1670 + if(this.tm.last_visible_check > NETDATA.options.last_page_scroll) {
1671 + if(this.debug === true) this.log('isVisible: ' + this.___isVisible___);
1672 return this.___isVisible___;
1673 + }
1674
1675 this.tm.last_visible_check = new Date().getTime();
1676
@@ -1609,12 +1692,14 @@
1692 // the chart is too far
1693 this.___isVisible___ = false;
1694 if(this.tm.last_created !== 0) this.hideChart();
1695 + if(this.debug === true) this.log('isVisible: ' + this.___isVisible___);
1696 return this.___isVisible___;
1697 }
1698 else {
1699 // the chart is inside or very close
1700 this.___isVisible___ = true;
1701 this.unhideChart();
1702 + if(this.debug === true) this.log('isVisible: ' + this.___isVisible___);
1703 return this.___isVisible___;
1704 }
1705 }
@@ -1757,13 +1842,20 @@
1842 $(this.element).css('min-width', NETDATA.chartDefaults.min_width);
1843 }
1844
1845 + chartState.prototype.noData = function() {
1846 + if(this.tm.last_created === 0) {
1847 + this.createChartDOM();
1848 + this.tm.last_created = new Date().getTime();
1849 + }
1850 +
1851 + this.current.last_autorefreshed = new Date().getTime();
1852 + this.current.view_update_every = 30 * 1000;
1853 + }
1854 +
1855 // show a message in the chart
1856 chartState.prototype.message = function(type, msg) {
1857 this.hideChart();
1858 this.element_message.innerHTML = msg;
1764 -
1765 - // reset the creation datetime
1766 - // since we overwrote the whole element
1859 if(this.debug) this.log(msg);
1860 }
1861
@@ -1941,10 +2033,12 @@
2033
2034 // ----------------------------------------------------------------------------------------------------------------
2035
2036 + // this is purely sequencial charts refresher
2037 + // it is meant to be autonomous
2038 NETDATA.chartRefresherNoParallel = function(index) {
2039 if(NETDATA.options.debug.mail_loop) console.log('NETDATA.chartRefresherNoParallel(' + index + ')');
2040
1947 - if(NETDATA.options.updated_dom) {
2041 + if(NETDATA.options.updated_dom === true) {
2042 // the dom has been updated
2043 // get the dom parts again
2044 NETDATA.parseDom(NETDATA.chartRefresher);
@@ -1981,8 +2075,14 @@
2075 }
2076 }
2077
1984 - NETDATA.chartRefresher_sequencial = function() {
1985 - if(NETDATA.options.updated_dom) {
2078 + // this is part of the parallel refresher
2079 + // its cause is to refresh sequencially all the charts
2080 + // that depend on chart library initialization
2081 + // it will call the parallel refresher back
2082 + // as soon as it sees a chart that its chart library
2083 + // is initialized
2084 + NETDATA.chartRefresher_unitialized = function() {
2085 + if(NETDATA.options.updated_dom === true) {
2086 // the dom has been updated
2087 // get the dom parts again
2088 NETDATA.parseDom(NETDATA.chartRefresher);
@@ -1993,18 +2093,28 @@
2093 NETDATA.chartRefresher();
2094 else {
2095 var state = NETDATA.options.sequencial.pop();
1996 - if(state.library.initialized)
2096 + if(state.library.initialized === true)
2097 NETDATA.chartRefresher();
2098 else
1999 - state.autoRefresh(NETDATA.chartRefresher_sequencial);
2099 + state.autoRefresh(NETDATA.chartRefresher_unitialized);
2100 }
2101 }
2102
2103 + NETDATA.chartRefresherWaitTime = function() {
2104 + return NETDATA.options.current.idle_parallel_loops;
2105 + }
2106 +
2107 + // the default refresher
2108 + // it will create 2 sets of charts:
2109 + // - the ones that can be refreshed in parallel
2110 + // - the ones that depend on something else
2111 + // the first set will be executed in parallel
2112 + // the second will be given to NETDATA.chartRefresher_unitialized()
2113 NETDATA.chartRefresher = function() {
2004 - if(NETDATA.options.pause) {
2114 + if(NETDATA.options.pause === true) {
2115 // console.log('auto-refresher is paused');
2116 setTimeout(NETDATA.chartRefresher,
2007 - NETDATA.options.current.idle_between_loops);
2117 + NETDATA.chartRefresherWaitTime());
2118 return;
2119 }
2120
@@ -2013,50 +2123,60 @@
2123 NETDATA.options.pause = true;
2124 NETDATA.options.pauseCallback();
2125 NETDATA.chartRefresher();
2126 + return;
2127 }
2128
2018 - if(!NETDATA.options.current.parallel_refresher) {
2129 + if(NETDATA.options.current.parallel_refresher === false) {
2130 NETDATA.chartRefresherNoParallel(0);
2131 return;
2132 }
2133
2023 - if(NETDATA.options.updated_dom) {
2134 + if(NETDATA.options.updated_dom === true) {
2135 // the dom has been updated
2136 // get the dom parts again
2137 NETDATA.parseDom(NETDATA.chartRefresher);
2138 return;
2139 }
2140
2030 - NETDATA.options.parallel = new Array();
2031 - NETDATA.options.sequencial = new Array();
2032 -
2141 + var parallel = new Array();
2142 var targets = NETDATA.options.targets;
2143 var len = targets.length;
2144 while(len--) {
2145 + if(!targets[len].isVisible()) continue;
2146 +
2147 var state = targets[len];
2148 + if(state.library.initialized === false) {
2149 + if(state.library.enabled === true) {
2150 + state.library.initialize(NETDATA.chartRefresher);
2151 + return;
2152 + }
2153 + else {
2154 + state.error('chart library "' + state.library_name + '" is not enabled.');
2155 + state.enabled = false;
2156 + }
2157 + }
2158
2038 - if(!state.library.initialized)
2039 - NETDATA.options.sequencial.push(state);
2040 - else
2041 - NETDATA.options.parallel.push(state);
2159 + parallel.unshift(state);
2160 }
2161
2044 - if(NETDATA.options.parallel.length > 0) {
2045 - NETDATA.options.parallel_jobs = NETDATA.options.parallel.length;
2162 + if(parallel.length > 0) {
2163 + var parallel_jobs = parallel.length;
2164
2047 - $(NETDATA.options.parallel).each(function() {
2165 + // this will execute the jobs in parallel
2166 + $(parallel).each(function() {
2167 this.autoRefresh(function() {
2049 - NETDATA.options.parallel_jobs--;
2050 - if(NETDATA.options.parallel_jobs === 0) {
2051 - setTimeout(NETDATA.chartRefresher_sequencial,
2052 - NETDATA.options.current.idle_between_charts);
2168 + parallel_jobs--;
2169 +
2170 + if(parallel_jobs === 0) {
2171 + setTimeout(NETDATA.chartRefresher,
2172 + NETDATA.chartRefresherWaitTime());
2173 }
2174 });
2175 })
2176 }
2177 else {
2058 - setTimeout(NETDATA.chartRefresher_sequencial,
2059 - NETDATA.options.current.idle_between_charts);
2178 + setTimeout(NETDATA.chartRefresher,
2179 + NETDATA.chartRefresherWaitTime());
2180 }
2181 }
2182
@@ -2114,16 +2234,17 @@
2234 cache: true,
2235 dataType: "script"
2236 })
2117 - .done(function() {
2118 - NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
2119 - })
2120 - .fail(function() {
2121 - NETDATA.error(100, NETDATA.peity_js);
2122 - })
2123 - .always(function() {
2124 - if(typeof callback === "function")
2125 - callback();
2126 - })
2237 + .done(function() {
2238 + NETDATA.registerChartLibrary('peity', NETDATA.peity_js);
2239 + })
2240 + .fail(function() {
2241 + NETDATA.chartLibraries.peity.enabled = false;
2242 + NETDATA.error(100, NETDATA.peity_js);
2243 + })
2244 + .always(function() {
2245 + if(typeof callback === "function")
2246 + callback();
2247 + });
2248 }
2249 else {
2250 NETDATA.chartLibraries.peity.enabled = false;
@@ -2133,19 +2254,33 @@
2254 };
2255
2256 NETDATA.peityChartUpdate = function(state, data) {
2136 - $(state.peity_instance).html(data.result);
2137 - // $(state.element_chart).change() does not accept options
2138 - // to pass width and height
2139 - //$(state.peity_instance).change();
2140 - $(state.peity_instance).peity('line', { width: state.chartWidth(), height: state.chartHeight() });
2257 + state.peity_instance.innerHTML = data.result;
2258 +
2259 + if(state.peity_options.stroke !== state.chartColors()[0]) {
2260 + state.peity_options.stroke = state.chartColors()[0];
2261 + if(state.chart.chart_type === 'line')
2262 + state.peity_options.fill = '#FFF';
2263 + else
2264 + state.peity_options.fill = NETDATA.colorLuminance(state.chartColors()[0], NETDATA.chartDefaults.fill_luminance);
2265 + }
2266 +
2267 + $(state.peity_instance).peity('line', state.peity_options);
2268 }
2269
2270 NETDATA.peityChartCreate = function(state, data) {
2271 state.peity_instance = document.createElement('div');
2272 state.element_chart.appendChild(state.peity_instance);
2273
2147 - $(state.peity_instance).html(data.result);
2148 - $(state.peity_instance).peity('line', { width: state.chartWidth(), height: state.chartHeight() });
2274 + var self = $(state.element);
2275 + state.peity_options = {
2276 + stroke: '#000',
2277 + strokeWidth: self.data('peity-strokewidth') || 1,
2278 + width: state.chartWidth(),
2279 + height: state.chartHeight(),
2280 + fill: '#000'
2281 + };
2282 +
2283 + NETDATA.peityChartUpdate(state, data);
2284 }
2285
2286 // ----------------------------------------------------------------------------------------------------------------
@@ -2158,16 +2293,17 @@
2293 cache: true,
2294 dataType: "script"
2295 })
2161 - .done(function() {
2162 - NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
2163 - })
2164 - .fail(function() {
2165 - NETDATA.error(100, NETDATA.sparkline_js);
2166 - })
2167 - .always(function() {
2168 - if(typeof callback === "function")
2169 - callback();
2170 - })
2296 + .done(function() {
2297 + NETDATA.registerChartLibrary('sparkline', NETDATA.sparkline_js);
2298 + })
2299 + .fail(function() {
2300 + NETDATA.chartLibraries.sparkline.enabled = false;
2301 + NETDATA.error(100, NETDATA.sparkline_js);
2302 + })
2303 + .always(function() {
2304 + if(typeof callback === "function")
2305 + callback();
2306 + });
2307 }
2308 else {
2309 NETDATA.chartLibraries.sparkline.enabled = false;
@@ -2300,7 +2436,7 @@
2436 state.dygraph_instance.setSelection(r);
2437 else {
2438 state.dygraph_instance.clearSelection();
2303 - state.legendUndefined();
2439 + state.legendShowUndefined();
2440 }
2441 }
2442
@@ -2320,15 +2456,18 @@
2456 cache: true,
2457 dataType: "script"
2458 })
2323 - .done(function() {
2324 - NETDATA.dygraph.smooth = true;
2325 - smoothPlotter.smoothing = 0.3;
2326 - })
2327 - .always(function() {
2328 - if(typeof callback === "function")
2329 - callback();
2330 - })
2331 - };
2459 + .done(function() {
2460 + NETDATA.dygraph.smooth = true;
2461 + smoothPlotter.smoothing = 0.3;
2462 + })
2463 + .fail(function() {
2464 + NETDATA.dygraph.smooth = false;
2465 + })
2466 + .always(function() {
2467 + if(typeof callback === "function")
2468 + callback();
2469 + });
2470 + }
2471
2472 NETDATA.dygraphInitialize = function(callback) {
2473 if(typeof netdataNoDygraphs === 'undefined' || !netdataNoDygraphs) {
@@ -2337,15 +2476,19 @@
2476 cache: true,
2477 dataType: "script"
2478 })
2340 - .done(function() {
2341 - NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
2479 + .done(function() {
2480 + NETDATA.registerChartLibrary('dygraph', NETDATA.dygraph_js);
2481 + })
2482 + .fail(function() {
2483 + NETDATA.chartLibraries.dygraph.enabled = false;
2484 + NETDATA.error(100, NETDATA.dygraph_js);
2485 + })
2486 + .always(function() {
2487 + if(NETDATA.chartLibraries.dygraph.enabled === true)
2488 NETDATA.dygraphSmoothInitialize(callback);
2343 - })
2344 - .fail(function() {
2345 - NETDATA.error(100, NETDATA.dygraph_js);
2346 - if(typeof callback === "function")
2347 - callback();
2348 - })
2489 + else if(typeof callback === "function")
2490 + callback();
2491 + });
2492 }
2493 else {
2494 NETDATA.chartLibraries.dygraph.enabled = false;
@@ -2369,6 +2512,7 @@
2512 if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartUpdate() loose update');
2513 dygraph.updateOptions({
2514 file: data.result.data,
2515 + colors: state.chartColors(),
2516 labels: data.result.labels,
2517 labelsDivWidth: state.chartWidth() - 70
2518 });
@@ -2377,6 +2521,7 @@
2521 if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartUpdate() strict update');
2522 dygraph.updateOptions({
2523 file: data.result.data,
2524 + colors: state.chartColors(),
2525 labels: data.result.labels,
2526 labelsDivWidth: state.chartWidth() - 70,
2527 dateWindow: null,
@@ -2406,9 +2551,6 @@
2551 var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state))?3:4;
2552
2553
2409 - //if(state.id == 'system.cpu')
2410 - // console.log(data);
2411 -
2554 state.dygraph_options = {
2555 colors: self.data('dygraph-colors') || state.chartColors(),
2556
@@ -2420,7 +2562,6 @@
2562 title: self.data('dygraph-title') || state.chart.title,
2563 titleHeight: self.data('dygraph-titleheight') || 19,
2564
2423 -// legend: self.data('dygraph-legend') || NETDATA.chartLibraries.dygraph.legend(state)?'always':'never', // 'onmouseover',
2565 legend: self.data('dygraph-legend') || 'always', // 'onmouseover',
2566 labels: data.result.labels,
2567 labelsDiv: self.data('dygraph-labelsdiv') || state.element_legend_childs.hidden,
@@ -2657,7 +2798,7 @@
2798
2799 // http://dygraphs.com/gallery/interaction-api.js
2800 var normal = (event.detail) ? event.detail * -1 : event.wheelDelta / 40;
2660 - var percentage = normal / 25;
2801 + var percentage = normal / 10;
2802
2803 var before_old = state.current.before_ms;
2804 var after_old = state.current.after_ms;
@@ -2709,8 +2850,7 @@
2850 state.dygraph_options.rightGap = 0;
2851 }
2852
2712 - if(smooth === true && typeof smoothPlotter === 'function')
2713 - state.dygraph_options.plotter = smoothPlotter;
2853 + if(smooth === true) state.dygraph_options.plotter = smoothPlotter;
2854
2855 state.dygraph_instance = new Dygraph(state.element_chart,
2856 data.result.data, state.dygraph_options);
@@ -2745,16 +2885,17 @@
2885 cache: true,
2886 dataType: "script"
2887 })
2748 - .done(function() {
2749 - NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
2750 - })
2751 - .fail(function() {
2752 - NETDATA.error(100, NETDATA.morris_js);
2753 - })
2754 - .always(function() {
2755 - if(typeof callback === "function")
2756 - callback();
2757 - })
2888 + .done(function() {
2889 + NETDATA.registerChartLibrary('morris', NETDATA.morris_js);
2890 + })
2891 + .fail(function() {
2892 + NETDATA.chartLibraries.morris.enabled = false;
2893 + NETDATA.error(100, NETDATA.morris_js);
2894 + })
2895 + .always(function() {
2896 + if(typeof callback === "function")
2897 + callback();
2898 + });
2899 }
2900 }
2901 else {
@@ -2800,22 +2941,23 @@
2941 // raphael
2942
2943 NETDATA.raphaelInitialize = function(callback) {
2803 - if(typeof netdataStopRaphael === 'undefined') {
2944 + if(typeof netdataStopRaphael === 'undefined' || !netdataStopRaphael) {
2945 $.ajax({
2946 url: NETDATA.raphael_js,
2947 cache: true,
2948 dataType: "script"
2949 })
2809 - .done(function() {
2810 - NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
2811 - })
2812 - .fail(function() {
2813 - NETDATA.error(100, NETDATA.raphael_js);
2814 - })
2815 - .always(function() {
2816 - if(typeof callback === "function")
2817 - callback();
2818 - })
2950 + .done(function() {
2951 + NETDATA.registerChartLibrary('raphael', NETDATA.raphael_js);
2952 + })
2953 + .fail(function() {
2954 + NETDATA.chartLibraries.raphael.enabled = false;
2955 + NETDATA.error(100, NETDATA.raphael_js);
2956 + })
2957 + .always(function() {
2958 + if(typeof callback === "function")
2959 + callback();
2960 + });
2961 }
2962 else {
2963 NETDATA.chartLibraries.raphael.enabled = false;
@@ -2848,19 +2990,19 @@
2990 cache: true,
2991 dataType: "script"
2992 })
2851 - .done(function() {
2852 - NETDATA.registerChartLibrary('google', NETDATA.google_js);
2853 -
2854 - google.load('visualization', '1.1', {
2855 - 'packages': ['corechart', 'controls'],
2856 - 'callback': callback
2857 - });
2858 - })
2859 - .fail(function() {
2860 - NETDATA.error(100, NETDATA.google_js);
2861 - if(typeof callback === "function")
2862 - callback();
2863 - })
2993 + .done(function() {
2994 + NETDATA.registerChartLibrary('google', NETDATA.google_js);
2995 + google.load('visualization', '1.1', {
2996 + 'packages': ['corechart', 'controls'],
2997 + 'callback': callback
2998 + });
2999 + })
3000 + .fail(function() {
3001 + NETDATA.chartLibraries.google.enabled = false;
3002 + NETDATA.error(100, NETDATA.google_js);
3003 + if(typeof callback === "function")
3004 + callback();
3005 + });
3006 }
3007 else {
3008 NETDATA.chartLibraries.google.enabled = false;
@@ -2966,7 +3108,7 @@
3108 // easy-pie-chart
3109
3110 NETDATA.easypiechartInitialize = function(callback) {
2969 - if(typeof netdataStopEasypiechart === 'undefined') {
3111 + if(typeof netdataNoEasyPieChart === 'undefined' || !netdataNoEasyPieChart) {
3112 $.ajax({
3113 url: NETDATA.easypiechart_js,
3114 cache: true,
@@ -3041,6 +3183,7 @@
3183 },
3184 autoresize: function(state) { return true; },
3185 max_updates_to_recreate: function(state) { return 5000; },
3186 + track_colors: function(state) { return true; },
3187 pixels_per_point: function(state) {
3188 if(!this.isSparkline(state))
3189 return 3;
@@ -3072,6 +3215,7 @@
3215 legend: function(state) { return null; },
3216 autoresize: function(state) { return false; },
3217 max_updates_to_recreate: function(state) { return 5000; },
3218 + track_colors: function(state) { return false; },
3219 pixels_per_point: function(state) { return 3; }
3220 },
3221 "peity": {
@@ -3087,6 +3231,7 @@
3231 legend: function(state) { return null; },
3232 autoresize: function(state) { return false; },
3233 max_updates_to_recreate: function(state) { return 5000; },
3234 + track_colors: function(state) { return false; },
3235 pixels_per_point: function(state) { return 3; }
3236 },
3237 "morris": {
@@ -3102,6 +3247,7 @@
3247 legend: function(state) { return null; },
3248 autoresize: function(state) { return false; },
3249 max_updates_to_recreate: function(state) { return 50; },
3250 + track_colors: function(state) { return false; },
3251 pixels_per_point: function(state) { return 15; }
3252 },
3253 "google": {
@@ -3117,6 +3263,7 @@
3263 legend: function(state) { return null; },
3264 autoresize: function(state) { return false; },
3265 max_updates_to_recreate: function(state) { return 300; },
3266 + track_colors: function(state) { return false; },
3267 pixels_per_point: function(state) { return 4; }
3268 },
3269 "raphael": {
@@ -3132,6 +3279,7 @@
3279 legend: function(state) { return null; },
3280 autoresize: function(state) { return false; },
3281 max_updates_to_recreate: function(state) { return 5000; },
3282 + track_colors: function(state) { return false; },
3283 pixels_per_point: function(state) { return 3; }
3284 },
3285 "easypiechart": {
@@ -3147,6 +3295,7 @@
3295 legend: function(state) { return null; },
3296 autoresize: function(state) { return false; },
3297 max_updates_to_recreate: function(state) { return 5000; },
3298 + track_colors: function(state) { return false; },
3299 pixels_per_point: function(state) { return 3; }
3300 }
3301 };
@@ -3169,8 +3318,12 @@
3318 isAlreadyLoaded: function() {
3319 if(typeof $().emulateTransitionEnd == 'function')
3320 return true;
3172 - else
3173 - return false;
3321 + else {
3322 + if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
3323 + return true;
3324 + else
3325 + return false;
3326 + }
3327 }
3328 },
3329 {
@@ -3180,9 +3333,19 @@
3333 ];
3334
3335 NETDATA.requiredCSS = [
3183 - NETDATA.serverDefault + 'css/bootstrap.min.css',
3184 - //NETDATA.serverDefault + 'css/bootstrap-theme.min.css',
3185 - NETDATA.dashboard_css
3336 + {
3337 + url: NETDATA.serverDefault + 'css/bootstrap.min.css',
3338 + isAlreadyLoaded: function() {
3339 + if(typeof netdataNoBootstrap !== 'undefined' && netdataNoBootstrap)
3340 + return true;
3341 + else
3342 + return false;
3343 + }
3344 + },
3345 + {
3346 + url: NETDATA.dashboard_css,
3347 + isAlreadyLoaded: function() { return false; }
3348 + }
3349 ];
3350
3351 NETDATA.loadRequiredJs = function(index, callback) {
@@ -3216,25 +3379,28 @@
3379 if(index >= NETDATA.requiredCSS.length)
3380 return;
3381
3219 - if(NETDATA.options.debug.main_loop) console.log('loading ' + NETDATA.requiredCSS[index]);
3220 - NETDATA._loadCSS(NETDATA.requiredCSS[index]);
3382 + if(NETDATA.requiredCSS[index].isAlreadyLoaded()) {
3383 + NETDATA.loadRequiredCSS(++index);
3384 + return;
3385 + }
3386 +
3387 + if(NETDATA.options.debug.main_loop) console.log('loading ' + NETDATA.requiredCSS[index].url);
3388 + NETDATA._loadCSS(NETDATA.requiredCSS[index].url);
3389 NETDATA.loadRequiredCSS(++index);
3390 }
3391
3392 NETDATA.errorReset();
3393 NETDATA.loadRequiredCSS(0);
3394 +
3395 NETDATA._loadjQuery(function() {
3396 NETDATA.loadRequiredJs(0, function() {
3228 - //NETDATA.chartRegistry.downloadAll(NETDATA.serverDefault, function() {
3229 - // NETDATA._loadCSS(NETDATA.dashboard_css);
3230 - if(typeof netdataDontStart === 'undefined' || !netdataDontStart) {
3231 - if(NETDATA.options.debug.main_loop) console.log('starting chart refresh thread');
3232 - NETDATA.start();
3233 - }
3397 + if(typeof netdataDontStart === 'undefined' || !netdataDontStart) {
3398 + if(NETDATA.options.debug.main_loop) console.log('starting chart refresh thread');
3399 + NETDATA.start();
3400 + }
3401
3235 - if(typeof NETDATA.options.readyCallback === 'function')
3236 - NETDATA.options.readyCallback();
3237 - //});
3402 + if(typeof NETDATA.options.readyCallback === 'function')
3403 + NETDATA.options.readyCallback();
3404 });
3405 });
3406
web/dashboard_full.html
+1 -1
@@ -274,7 +274,7 @@ var options = {
274 };
275
276 var messages = {
277 - 'system.cpu': 'The current CPU utilization of the system is below.<br/>Keep an eye on iowait <div data-netdata="system.cpu" data-after="-60" data-width="15%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="iowait" data-colors="' + NETDATA.colors[8] + '" data-show-value-of-iowait-at="system.cpu.iowait.1"></div> (<span id="system.cpu.iowait.1" style="display: inline-block; min-width: 40px; text-align: right;">X</span>%). If it is constantly high, your disks are a bottleneck and they slow your system down.'
277 + 'system.cpu': 'The current CPU utilization of the system is below.<br/>Keep an eye on iowait <div data-netdata="system.cpu" data-after="-60" data-width="15%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="iowait" data-show-value-of-iowait-at="system.cpu.iowait.1"></div> (<span id="system.cpu.iowait.1" style="display: inline-block; min-width: 40px; text-align: right;">X</span>%). If it is constantly high, your disks are a bottleneck and they slow your system down.'
278 };
279
280 function screenWidth() {