@cryptotaxi247 / netdata-1 / commits / 0bf086e57

added API option percentage to return the percentage of each dimension against the sum of all dimensions; added easypiecharts for system values

Costa Tsaousis (ktsaou) committed Jan 8, 2016 at 02:52 UTC 0bf086e577fa1ff42f227c48da15d3cbfaf1580a
7 files changed +404 -102
src/rrd2json.c
+94 -20
@@ -371,6 +371,11 @@ void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
371 for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
372 if(!strcmp(d->name, tok)) {
373 r->od[c] &= ~RRDR_HIDDEN;
374 +
375 + // since the user needs this dimension
376 + // make it appear as NONZERO, to return it
377 + // even if the dimension has only zeros
378 + r->od[c] |= RRDR_NONZERO;
379 }
380 }
381 }
@@ -425,22 +430,31 @@ void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
430 }
431 }
432
428 -uint32_t rrdr_check_options(RRDR *r, uint32_t options)
433 +uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
434 {
435 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++;
436 + long i;
437 +
438 + if(dims && *dims) {
439 + // the caller wants specific dimensions
440 + // disable NONZERO option
441 + // to make sure we don't accidentally prevent
442 + // the specific dimensions from being returned
443 + i = 0;
444 + }
445 + else {
446 + // find how many dimensions are not zero
447 + long c;
448 + RRDDIM *rd;
449 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
450 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
451 + if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
452 + i++;
453 + }
454 }
455
441 - // if with nonzero we get i = 0
442 - // but c != 0, then disable nonzero
443 - // to show all dimensions
456 + // if with nonzero we get i = 0 (no dimensions will be returned)
457 + // disable nonzero to show all dimensions
458 if(!i) options &= ~RRDR_OPTION_NONZERO;
459 }
460
@@ -749,6 +763,7 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
763 }
764
765 // for each line in the array
766 + calculated_number total = 1;
767 for(i = start; i != end ;i += step) {
768 calculated_number *cn = &r->v[ i * r->d ];
769 uint8_t *co = &r->o[ i * r->d ];
@@ -802,6 +817,20 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
817 buffer_strcat(wb, post_date);
818 }
819
820 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
821 + total = 0;
822 + for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
823 + calculated_number n = cn[c];
824 +
825 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
826 + n = -n;
827 +
828 + total += n;
829 + }
830 + // prevent a division by zero
831 + if(total == 0) total = 1;
832 + }
833 +
834 // for each dimension
835 for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
836 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
@@ -820,10 +849,15 @@ static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
849 else
850 buffer_strcat(wb, "null");
851 }
823 - else if((options & RRDR_OPTION_ABSOLUTE))
824 - buffer_rrd_value(wb, (n<0)?-n:n);
825 - else
852 + else {
853 + if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
854 + n = -n;
855 +
856 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
857 + n = n * 100 / total;
858 +
859 buffer_rrd_value(wb, n);
860 + }
861
862 buffer_strcat(wb, post_value);
863 }
@@ -873,6 +907,7 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
907 }
908
909 // for each line in the array
910 + calculated_number total = 1;
911 for(i = start; i != end ;i += step) {
912 calculated_number *cn = &r->v[ i * r->d ];
913 uint8_t *co = &r->o[ i * r->d ];
@@ -895,6 +930,20 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
930 buffer_date(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
931 }
932
933 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
934 + total = 0;
935 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
936 + calculated_number n = cn[c];
937 +
938 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
939 + n = -n;
940 +
941 + total += n;
942 + }
943 + // prevent a division by zero
944 + if(total == 0) total = 1;
945 + }
946 +
947 // for each dimension
948 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
949 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
@@ -910,10 +959,15 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
959 else
960 buffer_strcat(wb, "null");
961 }
913 - else if((options & RRDR_OPTION_ABSOLUTE))
914 - buffer_rrd_value(wb, (n<0)?-n:n);
915 - else
962 + else {
963 + if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
964 + n = -n;
965 +
966 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
967 + n = n * 100 / total;
968 +
969 buffer_rrd_value(wb, n);
970 + }
971 }
972
973 buffer_strcat(wb, endline);
@@ -936,6 +990,7 @@ static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix,
990 }
991
992 // for each line in the array
993 + calculated_number total = 1;
994 for(i = start; i != end ;i += step) {
995
996 calculated_number *cn = &r->v[ i * r->d ];
@@ -944,6 +999,20 @@ static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix,
999 calculated_number sum = 0, min = 0, max = 0, v;
1000 int all_null = 1, init = 1;
1001
1002 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
1003 + total = 0;
1004 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1005 + calculated_number n = cn[c];
1006 +
1007 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1008 + n = -n;
1009 +
1010 + total += n;
1011 + }
1012 + // prevent a division by zero
1013 + if(total == 0) total = 1;
1014 + }
1015 +
1016 // for each dimension
1017 for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1018 if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
@@ -951,6 +1020,12 @@ static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix,
1020
1021 calculated_number n = cn[c];
1022
1023 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1024 + n = -n;
1025 +
1026 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1027 + n = n * 100 / total;
1028 +
1029 if(unlikely(init)) {
1030 if(n > 0) {
1031 min = 0;
@@ -965,7 +1040,6 @@ static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix,
1040
1041 if(likely(!(co[c] & RRDR_EMPTY))) {
1042 all_null = 0;
968 - if((options & RRDR_OPTION_ABSOLUTE) && n < 0) n = -n;
1043 sum += n;
1044 }
1045
@@ -1423,7 +1497,7 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
1497 return 500;
1498 }
1499
1426 - options = rrdr_check_options(r, options);
1500 + options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1501
1502 if(dimensions)
1503 rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
src/rrd2json.h
+2 -1
@@ -42,7 +42,7 @@ extern char *hostname;
42 #define RRDR_OPTION_NONZERO 0x00000001 // don't output dimensions will just zero values
43 #define RRDR_OPTION_REVERSED 0x00000002 // output the rows in reverse order (oldest to newest)
44 #define RRDR_OPTION_ABSOLUTE 0x00000004 // values positive, for DATASOURCE_SSV before summing
45 -#define RRDR_OPTION_MIN2MAX 0x00000008 // for DATASOURCE_SSV, out max - min
45 +#define RRDR_OPTION_MIN2MAX 0x00000008 // for DATASOURCE_SSV, out max - min, instead of sum
46 #define RRDR_OPTION_SECONDS 0x00000010 // output seconds, instead of dates
47 #define RRDR_OPTION_MILLISECONDS 0x00000020 // output milliseconds, instead of dates
48 #define RRDR_OPTION_NULL2ZERO 0x00000040 // do not show nulls, convert them to zeros
@@ -50,6 +50,7 @@ extern char *hostname;
50 #define RRDR_OPTION_GOOGLE_JSON 0x00000100 // comply with google JSON/JSONP specs
51 #define RRDR_OPTION_JSON_WRAP 0x00000200 // wrap the response in a JSON header with info about the result
52 #define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes
53 +#define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total
54
55 extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
56 extern void rrd_stats_api_v1_charts(BUFFER *wb);
src/web_client.c
+2
@@ -431,6 +431,8 @@ uint32_t web_client_api_request_v1_data_options(char *o)
431 ret |= RRDR_OPTION_OBJECTSROWS;
432 else if(!strcmp(tok, "google_json"))
433 ret |= RRDR_OPTION_GOOGLE_JSON;
434 + else if(!strcmp(tok, "percentage"))
435 + ret |= RRDR_OPTION_PERCENTAGE;
436 }
437
438 return ret;
web/dashboard.css
+1 -1
@@ -73,7 +73,7 @@ html {
73 }
74
75 .netdata-message.icon {
76 - color: #FAFAFA;
76 + color: #F8F8F8;
77 text-align: center;
78 vertical-align: middle;
79 }
web/dashboard.js
+132 -78
@@ -377,12 +377,12 @@
377 if(NETDATA.options.debug.main_loop === true)
378 console.log('welcome to NETDATA');
379
380 - window.onresize = function(event) {
381 - NETDATA.options.last_page_scroll = new Date().getTime();
380 + NETDATA.onresize = function() {
381 NETDATA.options.last_resized = new Date().getTime();
382 + NETDATA.onscroll();
383 };
384
385 - window.onscroll = function(event) {
385 + NETDATA.onscroll = function() {
386 NETDATA.options.last_page_scroll = new Date().getTime();
387 if(NETDATA.options.targets === null) return;
388
@@ -393,7 +393,10 @@
393 var targets = NETDATA.options.targets;
394 var len = targets.length;
395 while(len--) targets[len].isVisible();
396 - }
396 + };
397 +
398 + window.onresize = NETDATA.onresize;
399 + window.onscroll = NETDATA.onscroll;
400
401 // ----------------------------------------------------------------------------------------------------------------
402 // Error Handling
@@ -900,6 +903,8 @@
903 this.chart = null; // object - the chart as downloaded from the server
904
905 this.title = self.data('title') || null; // the title of the chart
906 + this.units = self.data('units') || null; // the units of the chart dimensions
907 + this.append_options = self.data('append-options') || null; // the units of the chart dimensions
908
909 this.validated = false; // boolean - has the chart been validated?
910 this.enabled = true; // boolean - is the chart enabled for refresh?
@@ -1004,11 +1009,15 @@
1009 }
1010 that.element_legend_childs.series = null;
1011
1007 - if(that.width !== 0)
1012 + if(typeof(that.width) === 'string')
1013 $(that.element).css('width', that.width);
1014 + else if(typeof(that.width) === 'number')
1015 + $(that.element).css('width', that.width + 'px');
1016
1010 - if(that.height !== 0)
1017 + if(typeof(that.height) === 'string')
1018 $(that.element).css('height', that.height);
1019 + else if(typeof(that.height) === 'number')
1020 + $(that.element).css('height', that.height + 'px');
1021
1022 if(NETDATA.chartDefaults.min_width !== null)
1023 $(that.element).css('min-width', NETDATA.chartDefaults.min_width);
@@ -1140,36 +1149,71 @@
1149
1150 // hide the chart, when it is not visible - called from isVisible()
1151 var hideChart = function() {
1143 - // no chart yet
1144 - if(that.chart_created === false) return;
1152 + // hide it, if it is not already hidden
1153 + if(typeof that.___chartIsHidden___ !== 'undefined')
1154 + return;
1155
1156 // we should destroy it
1157 if(NETDATA.options.current.destroy_on_hide === true) {
1148 - init();
1149 - that.___chartIsHidden___ = undefined;
1150 - return;
1158 + if(that.chart_created === true) init();
1159 }
1152 -
1153 - // just hide it, if it is not already hidden
1154 - if(typeof that.___chartIsHidden___ === 'undefined') {
1160 + else {
1161 showRendering();
1162 that.element_chart.style.display = 'none';
1163 if(that.element_legend !== null) that.element_legend.style.display = 'none';
1158 - that.___chartIsHidden___ = true;
1164 }
1165 +
1166 + that.___chartIsHidden___ = true;
1167 }
1168
1169 // unhide the chart, when it is visible - called from isVisible()
1170 var unhideChart = function() {
1164 - if(typeof that.___chartIsHidden___ !== 'undefined') {
1171 + if(typeof that.___chartIsHidden___ === 'undefined')
1172 + return;
1173 +
1174 + that.___chartIsHidden___ = undefined;
1175 +
1176 + if(that.chart_created === false) {
1177 + // we need to re-initialize it, to show our background
1178 + // logo in bootstrap tabs, until the chart loads
1179 + init();
1180 + }
1181 + else {
1182 that.element_chart.style.display = 'inline-block';
1183 if(that.element_legend !== null) that.element_legend.style.display = 'inline-block';
1167 - that.___chartIsHidden___ = undefined;
1184 resizeChart();
1185 hideMessage();
1186 }
1187 }
1188
1189 + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
1190 + var callChartLibraryUpdateSafely = function(data) {
1191 + var status;
1192 +
1193 + try {
1194 + status = that.library.update(that, data);
1195 + }
1196 + catch(err) {
1197 + status = false;
1198 + }
1199 +
1200 + return status;
1201 + }
1202 +
1203 + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
1204 + var callChartLibraryCreateSafely = function(data) {
1205 + var status;
1206 +
1207 + try {
1208 + status = that.library.create(that, data);
1209 + }
1210 + catch(err) {
1211 + status = false;
1212 + }
1213 +
1214 + return status;
1215 + }
1216 +
1217 // ----------------------------------------------------------------------------------------------------------------
1218 // Chart Resize
1219
@@ -1178,12 +1222,11 @@
1222 // a properly sized dom is available
1223 var resizeChart = function() {
1224 if(that.isVisible() === true && that.tm.last_resized < NETDATA.options.last_resized) {
1181 - that.tm.last_resized = new Date().getTime();
1225 if(that.chart_created === false) return;
1226
1184 - if(that.needsRecreation())
1227 + if(that.needsRecreation()) {
1228 init();
1186 -
1229 + }
1230 else if(typeof that.library.resize === 'function') {
1231 that.library.resize(that);
1232
@@ -1192,6 +1235,8 @@
1235
1236 maxMessageFontSize();
1237 }
1238 +
1239 + that.tm.last_resized = new Date().getTime();
1240 }
1241 }
1242
@@ -1690,7 +1735,7 @@
1735 this.element_legend_childs.title_time.innerHTML = d.toLocaleTimeString();
1736
1737 if(this.element_legend_childs.title_units)
1693 - this.element_legend_childs.title_units.innerHTML = this.chart.units;
1738 + this.element_legend_childs.title_units.innerHTML = this.units;
1739 }
1740
1741 this.legendShowUndefined = function() {
@@ -2096,6 +2141,9 @@
2141 if(NETDATA.options.current.eliminate_zero_dimensions === true)
2142 this.data_url += '|nonzero';
2143
2144 + if(this.append_options !== null)
2145 + this.data_url += '|' + this.append_options.toString();
2146 +
2147 if(after)
2148 this.data_url += "&after=" + after.toString();
2149
@@ -2184,22 +2232,17 @@
2232 if(this.debug === true)
2233 this.log('updating chart...');
2234
2187 - this.updates_since_last_creation++;
2188 - if(NETDATA.options.debug.chart_errors === true) {
2235 + if(NETDATA.options.debug.chart_errors === true)
2236 status = this.library.update(this, data);
2237 + else
2238 + status = callChartLibraryUpdateSafely(data);
2239 +
2240 + if(status === false) {
2241 + error('chart failed to be updated as ' + this.library_name);
2242 }
2243 else {
2192 - try {
2193 - status = this.library.update(this, data);
2194 - }
2195 - catch(err) {
2196 - status = false;
2197 - error('chart failed to be updated as ' + this.library_name);
2198 - }
2244 + this.updates_since_last_creation++;
2245 }
2200 -
2201 - if(status === false)
2202 - error('chart failed to be created as ' + this.library_name);
2246 }
2247 else {
2248 var status = false;
@@ -2207,25 +2250,18 @@
2250 if(this.debug === true)
2251 this.log('creating chart...');
2252
2210 - if(NETDATA.options.debug.chart_errors === true) {
2253 + if(NETDATA.options.debug.chart_errors === true)
2254 status = this.library.create(this, data);
2212 - this.chart_created = true;
2213 - this.updates_since_last_creation = 0;
2255 + else
2256 + status = callChartLibraryCreateSafely(data);
2257 +
2258 + if(status === false) {
2259 + error('chart failed to be created as ' + this.library_name);
2260 }
2261 else {
2216 - try {
2217 - status = this.library.create(this, data);
2218 - this.chart_created = true;
2219 - this.updates_since_last_creation = 0;
2220 - }
2221 - catch(err) {
2222 - status = false;
2223 - error('chart failed to be created as ' + this.library_name);
2224 - }
2262 + this.chart_created = true;
2263 + this.updates_since_last_creation = 0;
2264 }
2226 -
2227 - if(status === false)
2228 - error('chart failed to be created as ' + this.library_name);
2265 }
2266 hideMessage();
2267 this.legendShowLatestValues();
@@ -2327,12 +2363,12 @@
2363 var ret = 0;
2364 var tolerance = 0;
2365
2330 - if(x.width === 0 || x.height === 0 || this.element.style.display === 'none') {
2366 + if(x.width === 0 || x.height === 0) {
2367 hideChart();
2368 this.___isVisible___ = false;
2369
2370 if(this.debug === true)
2335 - this.log('isVisible: ' + this.___isVisible___);
2371 + this.log('isVisible (width:' + x.width + ', height:' + x.height + ', display:"' + this.element.style.display + '"): ' + this.___isVisible___);
2372
2373 return this.___isVisible___;
2374 }
@@ -2485,6 +2521,9 @@
2521
2522 if(this.title === null)
2523 this.title = chart.title;
2524 +
2525 + if(this.units === null)
2526 + this.units = chart.units;
2527 }
2528
2529 // fetch the chart description from the netdata server
@@ -2808,7 +2847,7 @@
2847 NETDATA.options.last_page_scroll = new Date().getTime();
2848 NETDATA.options.updated_dom = false;
2849
2811 - var targets = $('div[data-netdata]').filter(':visible');
2850 + var targets = $('div[data-netdata]'); //.filter(':visible');
2851
2852 if(NETDATA.options.debug.main_loop === true)
2853 console.log('DOM updated - there are ' + targets.length + ' charts on page.');
@@ -2854,6 +2893,11 @@
2893 }
2894 }
2895
2896 + // bootstrap tab switching
2897 + $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
2898 + NETDATA.onresize();
2899 + });
2900 +
2901 NETDATA.parseDom(NETDATA.chartRefresher);
2902 }
2903
@@ -2993,7 +3037,7 @@
3037 var tooltipClassname = self.data('sparkline-tooltipclassname') || undefined;
3038 var tooltipFormat = self.data('sparkline-tooltipformat') || undefined;
3039 var tooltipPrefix = self.data('sparkline-tooltipprefix') || undefined;
2996 - var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + state.chart.units;
3040 + var tooltipSuffix = self.data('sparkline-tooltipsuffix') || ' ' + state.units;
3041 var tooltipSkipNull = self.data('sparkline-tooltipskipnull') || true;
3042 var tooltipValueLookups = self.data('sparkline-tooltipvaluelookups') || undefined;
3043 var tooltipFormatFieldlist = self.data('sparkline-tooltipformatfieldlist') || undefined;
@@ -3223,7 +3267,7 @@
3267 showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight') || true,
3268 hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout') || true,
3269
3226 - ylabel: state.chart.units,
3270 + ylabel: state.units,
3271 yLabelWidth: self.data('dygraph-ylabelwidth') || 12,
3272
3273 // the function to plot the chart
@@ -3309,10 +3353,7 @@
3353 // we are not managing the legend
3354 if(elements.hidden === null) return;
3355
3312 - if (typeof data.x === 'undefined') {
3313 - //state.legendReset();
3314 - }
3315 - else {
3356 + if (typeof data.x !== 'undefined') {
3357 state.legendSetDate(data.x);
3358 var i = data.series.length;
3359 while(i--) {
@@ -4003,7 +4044,7 @@
4044 }
4045 },
4046 vAxis: {
4006 - title: state.chart.units,
4047 + title: state.units,
4048 viewWindowMode: 'pretty',
4049 minValue: -0.1,
4050 maxValue: 0.1,
@@ -4105,7 +4146,7 @@
4146 state.easyPieChartEvent.timer = null;
4147 }
4148
4108 - state.easyPieChartLabel.innerHTML = '';
4149 + state.easyPieChartLabel.innerHTML = state.legendFormatValue(null);
4150 state.easyPieChart_instance.update(0);
4151 state.easyPieChart_instance.enableAnimation();
4152 return true;
@@ -4126,8 +4167,10 @@
4167 if(max < value) max = value;
4168
4169 var pcent = 0;
4129 - if(max !== 0)
4170 + if(max !== 0) {
4171 pcent = Math.round(value * 100 / max);
4172 + if(pcent === 0 && value > 0) pcent = 1;
4173 + }
4174
4175 // console.log('slot = ' + slot + ' value = ' + value + ' max = ' + max + ' pcent = ' + pcent);
4176
@@ -4156,24 +4199,29 @@
4199 };
4200
4201 NETDATA.easypiechartChartUpdate = function(state, data) {
4159 - var value = data.result[0];
4160 - if(value === null) value = 0;
4161 -
4162 - var max = (state.easyPieChartMax === null)?data.max:state.easyPieChartMax;
4163 - if(max < value) max = value;
4164 -
4165 - var pcent = 0;
4166 - if(max !== 0)
4167 - pcent = Math.round(value * 100 / max);
4202 + var value, max, pcent;
4203
4169 - if(state.isAutoRefreshed() === true) {
4170 - state.easyPieChartLabel.innerHTML = state.legendFormatValue(value);
4171 - state.easyPieChart_instance.update(pcent);
4204 + if(NETDATA.globalPanAndZoom.isActive() === true || state.isAutoRefreshed() === false) {
4205 + value = null;
4206 + max = 0;
4207 + pcent = 0;
4208 }
4209 else {
4174 - state.easyPieChartLabel.innerHTML = '';
4175 - state.easyPieChart_instance.update(0);
4210 + value = data.result[0];
4211 + if(value === null) value = 0;
4212 +
4213 + max = (state.easyPieChartMax === null)?data.max:state.easyPieChartMax;
4214 + if(max < value) max = value;
4215 +
4216 + pcent = 0;
4217 + if(max !== 0) {
4218 + pcent = Math.round(value * 100 / max);
4219 + if(pcent === 0 && value > 0) pcent = 1;
4220 + }
4221 }
4222 +
4223 + state.easyPieChartLabel.innerHTML = state.legendFormatValue(value);
4224 + state.easyPieChart_instance.update(pcent);
4225 return true;
4226 };
4227
@@ -4195,14 +4243,20 @@
4243 if(max < value) max = value;
4244
4245 var pcent = 0;
4198 - if(max !== 0)
4246 + if(max !== 0) {
4247 pcent = Math.round(value * 100 / max);
4248 + if(pcent === 0 && value > 0) pcent = 1;
4249 + }
4250
4251 // console.log('value = ' + value + ' max = ' + max + ' pcent = ' + pcent);
4252 chart.data('data-percent', pcent);
4253
4254 var size = Math.min(state.chartWidth(), state.chartHeight());
4205 - var stroke = size / 15 - 2;
4255 + if(size < 50) size = state.chartWidth();
4256 + state.element.style.width = size + 'px';
4257 + state.element.style.height = size + 'px';
4258 +
4259 + var stroke = Math.floor(size / 22);
4260 if(stroke < 3) stroke = 2;
4261
4262 var valuefontsize = Math.floor((size * 2 / 3) / 5);
@@ -4228,7 +4282,7 @@
4282 var unittop = Math.round(valuetop + (valuefontsize + unitfontsize) + (size / 40));
4283 state.easyPieChartUnits = document.createElement('span');
4284 state.easyPieChartUnits.className = 'easyPieChartUnits';
4231 - state.easyPieChartUnits.innerHTML = state.chart.units;
4285 + state.easyPieChartUnits.innerHTML = state.units;
4286 state.easyPieChartUnits.style.fontSize = unitfontsize + 'px';
4287 state.easyPieChartUnits.style.top = unittop.toString() + 'px';
4288 state.element_chart.appendChild(state.easyPieChartUnits);
@@ -4426,7 +4480,7 @@
4480 initialized: false,
4481 enabled: true,
4482 format: function(state) { return 'array'; },
4429 - options: function(state) { if(state.chart.chart_type === 'stacked') return ''; else return 'min2max'; },
4483 + options: function(state) { return 'absolute'; },
4484 legend: function(state) { return null; },
4485 autoresize: function(state) { return false; },
4486 max_updates_to_recreate: function(state) { return 5000; },
web/index.html
+171
@@ -1007,6 +1007,177 @@ function prepareScreen(data) {
1007 + ' role="application"></div>';
1008 });
1009 }
1010 + else if(t.name === 'system') {
1011 + var head = '<div style="text-align: center; vertical-align: bottom; width: 100%;">';
1012 +
1013 + if(typeof charts['system.swap'] !== 'undefined')
1014 + head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
1015 + + ' data-dimensions="free"'
1016 + + ' data-append-options="percentage"'
1017 + + ' data-chart-library="easypiechart"'
1018 + + ' data-title="Free Swap"'
1019 + + ' data-units="%"'
1020 + + ' data-easypiechart-max-value="100"'
1021 + + ' data-width="8%"'
1022 + + ' data-height="49px"'
1023 + + ' data-before="0"'
1024 + + ' data-after="-' + duration.toString() + '"'
1025 + + ' data-points="' + duration.toString() + '"'
1026 + + ' data-colors="' + NETDATA.colors[1] + '"'
1027 + + ' role="application"></div>';
1028 +
1029 + if(typeof charts['system.io'] !== 'undefined') {
1030 + head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1031 + + ' data-dimensions="in"'
1032 + + ' data-chart-library="easypiechart"'
1033 + + ' data-title="Disk Read"'
1034 + + ' data-units="KB / s"'
1035 + + ' data-width="10%"'
1036 + + ' data-height="49px"'
1037 + + ' data-before="0"'
1038 + + ' data-after="-' + duration.toString() + '"'
1039 + + ' data-points="' + duration.toString() + '"'
1040 + + ' data-colors="' + NETDATA.colors[0] + '"'
1041 + + ' role="application"></div>';
1042 +
1043 + head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1044 + + ' data-dimensions="out"'
1045 + + ' data-chart-library="easypiechart"'
1046 + + ' data-title="Disk Write"'
1047 + + ' data-units="KB / s"'
1048 + + ' data-width="10%"'
1049 + + ' data-height="49px"'
1050 + + ' data-before="0"'
1051 + + ' data-after="-' + duration.toString() + '"'
1052 + + ' data-points="' + duration.toString() + '"'
1053 + + ' data-colors="' + NETDATA.colors[1] + '"'
1054 + + ' role="application"></div>';
1055 + }
1056 +
1057 + if(typeof charts['system.cpu'] !== 'undefined')
1058 + head += '<div style="margin-right: 10px;" data-netdata="system.cpu"'
1059 + + ' data-chart-library="easypiechart"'
1060 + + ' data-title="CPU"'
1061 + + ' data-units="%"'
1062 + + ' data-easypiechart-max-value="100"'
1063 + + ' data-width="11%"'
1064 + + ' data-height="49px"'
1065 + + ' data-after="-' + duration.toString() + '"'
1066 + + ' data-points="' + duration.toString() + '"'
1067 + + ' data-colors="' + NETDATA.colors[12] + '"'
1068 + + ' role="application"></div>';
1069 +
1070 + if(typeof charts['system.ipv4'] !== 'undefined') {
1071 + head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1072 + + ' data-dimensions="received"'
1073 + + ' data-chart-library="easypiechart"'
1074 + + ' data-title="IPv4 Inbound"'
1075 + + ' data-units="kbps"'
1076 + + ' data-width="10%"'
1077 + + ' data-height="49px"'
1078 + + ' data-before="0"'
1079 + + ' data-after="-' + duration.toString() + '"'
1080 + + ' data-points="' + duration.toString() + '"'
1081 + + ' data-colors="' + NETDATA.colors[0] + '"'
1082 + + ' role="application"></div>';
1083 +
1084 + head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1085 + + ' data-dimensions="sent"'
1086 + + ' data-chart-library="easypiechart"'
1087 + + ' data-title="IPv4 Outbound"'
1088 + + ' data-units="kbps"'
1089 + + ' data-width="10%"'
1090 + + ' data-height="49px"'
1091 + + ' data-before="0"'
1092 + + ' data-after="-' + duration.toString() + '"'
1093 + + ' data-points="' + duration.toString() + '"'
1094 + + ' data-colors="' + NETDATA.colors[1] + '"'
1095 + + ' role="application"></div>';
1096 + }
1097 +
1098 + if(typeof charts['system.ram'] !== 'undefined')
1099 + head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
1100 + + ' data-dimensions="cached|free"'
1101 + + ' data-append-options="percentage"'
1102 + + ' data-chart-library="easypiechart"'
1103 + + ' data-title="Available RAM"'
1104 + + ' data-units="%"'
1105 + + ' data-easypiechart-max-value="100"'
1106 + + ' data-width="8%"'
1107 + + ' data-height="1"'
1108 + + ' data-before="49px"'
1109 + + ' data-after="-' + duration.toString() + '"'
1110 + + ' data-points="' + duration.toString() + '"'
1111 + + ' data-colors="' + NETDATA.colors[7] + '"'
1112 + + ' role="application"></div>';
1113 +
1114 +/* if(typeof charts['system.swapio'] !== 'undefined') {
1115 + head += "<div style=\"display: inline-block\">";
1116 +
1117 + head += '<div style="margin-right: 10px;" data-netdata="system.swapio"'
1118 + + ' data-dimensions="in"'
1119 + + ' data-chart-library="easypiechart"'
1120 + + ' data-title="Swap Read"'
1121 + + ' data-width="100px"'
1122 + + ' data-height="100px"'
1123 + + ' data-before="0"'
1124 + + ' data-after="-' + duration.toString() + '"'
1125 + + ' data-points="' + duration.toString() + '"'
1126 + + ' data-colors="' + NETDATA.colors[2] + '"'
1127 + + ' role="application"></div>';
1128 +
1129 + head += '<div style="margin-right: 10px;" data-netdata="system.swapio"'
1130 + + ' data-dimensions="out"'
1131 + + ' data-chart-library="easypiechart"'
1132 + + ' data-title="Swap Write"'
1133 + + ' data-width="100px"'
1134 + + ' data-height="100px"'
1135 + + ' data-before="0"'
1136 + + ' data-after="-' + duration.toString() + '"'
1137 + + ' data-points="' + duration.toString() + '"'
1138 + + ' data-colors="' + NETDATA.colors[1] + '"'
1139 + + ' role="application"></div>';
1140 +
1141 + head += "</div>";
1142 + }
1143 +
1144 + if(typeof charts['system.ctxt'] !== 'undefined')
1145 + head += '<div style="margin-right: 10px;" data-netdata="system.ctxt"'
1146 + + ' data-chart-library="easypiechart"'
1147 + + ' data-title="Switches"'
1148 + + ' data-width="100px"'
1149 + + ' data-height="100px"'
1150 + + ' data-before="0"'
1151 + + ' data-after="-' + duration.toString() + '"'
1152 + + ' data-points="' + duration.toString() + '"'
1153 + + ' data-colors="' + NETDATA.colors[3] + '"'
1154 + + ' role="application"></div>';
1155 +
1156 + if(typeof charts['system.intr'] !== 'undefined')
1157 + head += '<div style="margin-right: 10px;" data-netdata="system.intr"'
1158 + + ' data-chart-library="easypiechart"'
1159 + + ' data-title="Interrupts"'
1160 + + ' data-width="100px"'
1161 + + ' data-height="100px"'
1162 + + ' data-before="0"'
1163 + + ' data-after="-' + duration.toString() + '"'
1164 + + ' data-points="' + duration.toString() + '"'
1165 + + ' data-colors="' + NETDATA.colors[7] + '"'
1166 + + ' role="application"></div>';
1167 +*/
1168 + head += "</div>";
1169 + var all = '';
1170 + $.each(t.charts, function(x, f) {
1171 + all += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
1172 + + ' data-width="' + pcent_width.toString() + '%"'
1173 + + ' data-height="' + options.chartsHeight.toString() + 'px"'
1174 + + ' data-before="0"'
1175 + + ' data-after="-' + duration.toString() + '"'
1176 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
1177 + + ' role="application"></div>';
1178 + });
1179 + html += head + all;
1180 + }
1181 else {
1182 $.each(t.charts, function(x, f) {
1183 html += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
web/netdata-swagger.yaml
+2 -2
@@ -101,7 +101,7 @@ paths:
101 description: 'The format of the data to be returned.'
102 required: true
103 type: string
104 - enum: [ 'json', 'jsonp', 'csv', 'tsv', 'tsv-excel', 'ssv', 'ssvcomma', 'datatable', 'datasource', 'html', 'array' ]
104 + enum: [ 'json', 'jsonp', 'csv', 'tsv', 'tsv-excel', 'ssv', 'ssvcomma', 'datatable', 'datasource', 'html', 'array', 'csvjsonarray' ]
105 default: json
106 allowEmptyValue: false
107 - name: options
@@ -111,7 +111,7 @@ paths:
111 type: array
112 items:
113 type: string
114 - enum: [ 'nonzero', 'flip', 'jsonwrap', 'min2max', 'seconds', 'milliseconds', 'abs', 'absolute', 'absolute-sum', 'null2zero', 'objectrows', 'google_json' ]
114 + enum: [ 'nonzero', 'flip', 'jsonwrap', 'min2max', 'seconds', 'milliseconds', 'abs', 'absolute', 'absolute-sum', 'null2zero', 'objectrows', 'google_json', 'percentage' ]
115 collectionFormat: pipes
116 format: ''
117 default: seconds|jsonwrap