dashboard show tooltip on charts, with the context and the resolution of the chart; fixes #2829; fixes #2708
Costa Tsaousis (ktsaou) committed
Oct 3, 2017 at 01:53 UTC
62d39bf294d25c847f2504165f176f2a97a6dd16
2 files changed
+105
-76
web/dashboard.js
+94
-1
@@ -2869,6 +2869,18 @@ var NETDATA = window.NETDATA || {};
2869
return this.colors;
2870
};
2871
2872
+ this.legendResolutionTooltip = function () {
2873
+ if(!this.chart) return '';
2874
+
2875
+ var collected = this.chart.update_every;
2876
+ var viewed = (this.data)?this.data.view_update_every:collected;
2877
+
2878
+ if(collected === viewed)
2879
+ return "resolution " + NETDATA.seconds4human(collected);
2880
+
2881
+ return "resolution " + NETDATA.seconds4human(viewed) + ", collected every " + NETDATA.seconds4human(collected);
2882
+ };
2883
+
2884
this.legendUpdateDOM = function() {
2885
var needed = false, dim, keys, len, i;
2886
@@ -3189,6 +3201,11 @@ var NETDATA = window.NETDATA || {};
3201
that.resizeHandler(e);
3202
}, false);
3203
3204
+ if(this.chart) {
3205
+ this.element_legend_childs.title_date.title = this.chart.context.toString();
3206
+ this.element_legend_childs.title_time.title = this.legendResolutionTooltip();
3207
+ }
3208
+
3209
this.element_legend_childs.title_date.className += " netdata-legend-title-date";
3210
this.element_legend.appendChild(this.element_legend_childs.title_date);
3211
this.tmp.__last_shown_legend_date = undefined;
@@ -3450,14 +3467,22 @@ var NETDATA = window.NETDATA || {};
3467
this.updates_since_last_creation++;
3468
3469
var started = Date.now();
3470
+ var view_update_every = data.view_update_every * 1000;
3471
+
3472
+
3473
+ if(this.data_update_every !== view_update_every) {
3474
+ if(this.element_legend_childs.title_time)
3475
+ this.element_legend_childs.title_time.title = this.legendResolutionTooltip();
3476
+ }
3477
3478
// if the result is JSON, find the latest update-every
3455
- this.data_update_every = data.view_update_every * 1000;
3479
+ this.data_update_every = view_update_every;
3480
this.data_after = data.after * 1000;
3481
this.data_before = data.before * 1000;
3482
this.netdata_first = data.first_entry * 1000;
3483
this.netdata_last = data.last_entry * 1000;
3484
this.data_points = data.points;
3485
+
3486
data.state = this;
3487
3488
if(NETDATA.options.current.pan_and_zoom_data_padding === true && this.requested_padding !== null) {
@@ -4036,6 +4061,74 @@ var NETDATA = window.NETDATA || {};
4061
NETDATA.options.pause = false;
4062
};
4063
4064
+ NETDATA.seconds4human = function (seconds, options) {
4065
+ var default_options = {
4066
+ now: 'now',
4067
+ space: ' ',
4068
+ negative_suffix: 'ago',
4069
+ day: 'day',
4070
+ days: 'days',
4071
+ hour: 'hour',
4072
+ hours: 'hours',
4073
+ minute: 'min',
4074
+ minutes: 'mins',
4075
+ second: 'sec',
4076
+ seconds: 'secs',
4077
+ and: 'and'
4078
+ };
4079
+
4080
+ if(typeof options !== 'object')
4081
+ options = default_options;
4082
+ else {
4083
+ var x;
4084
+ for(x in default_options) {
4085
+ if(typeof options[x] !== 'string')
4086
+ options[x] = default_options[x];
4087
+ }
4088
+ }
4089
+
4090
+ if(typeof seconds === 'string')
4091
+ seconds = parseInt(seconds);
4092
+
4093
+ if(seconds === 0)
4094
+ return options.now;
4095
+
4096
+ var suffix = '';
4097
+ if(seconds < 0) {
4098
+ seconds = -seconds;
4099
+ if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
4100
+ }
4101
+
4102
+ var days = Math.floor(seconds / 86400);
4103
+ seconds -= (days * 86400);
4104
+
4105
+ var hours = Math.floor(seconds / 3600);
4106
+ seconds -= (hours * 3600);
4107
+
4108
+ var minutes = Math.floor(seconds / 60);
4109
+ seconds -= (minutes * 60);
4110
+
4111
+ var strings = [];
4112
+
4113
+ if(days > 1) strings.push(days.toString() + options.space + options.days);
4114
+ else if(days === 1) strings.push(days.toString() + options.space + options.day);
4115
+
4116
+ if(hours > 1) strings.push(hours.toString() + options.space + options.hours);
4117
+ else if(hours === 1) strings.push(hours.toString() + options.space + options.hour);
4118
+
4119
+ if(minutes > 1) strings.push(minutes.toString() + options.space + options.minutes);
4120
+ else if(minutes === 1) strings.push(minutes.toString() + options.space + options.minute);
4121
+
4122
+ if(seconds > 1) strings.push(Math.floor(seconds).toString() + options.space + options.seconds);
4123
+ else if(seconds === 1) strings.push(Math.floor(seconds).toString() + options.space + options.second);
4124
+
4125
+ if(strings.length === 1)
4126
+ return strings.pop() + suffix;
4127
+
4128
+ var last = strings.pop();
4129
+ return strings.join(", ") + " " + options.and + " " + last + suffix;
4130
+ };
4131
+
4132
// ----------------------------------------------------------------------------------------------------------------
4133
4134
// this is purely sequential charts refresher
web/index.html
+11
-75
@@ -1540,7 +1540,7 @@
1540
1541
sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more charts</a></li>';
1542
sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more alarms</a></li>';
1543
- sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + seconds4human(data.update_every * data.history) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
1543
+ sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + NETDATA.seconds4human(data.update_every * data.history, { space: ' ' }) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
1544
sidebar += '</ul>';
1545
div.innerHTML = html;
1546
document.getElementById('sidebar').innerHTML = sidebar;
@@ -1711,7 +1711,7 @@
1711
1712
return '<code>' + alarm.lookup_method + '</code> '
1713
+ dimensions + ', of chart <code>' + alarm.chart + '</code>'
1714
- + ', starting <code>' + seconds4human(alarm.lookup_after + alarm.lookup_before) + '</code> and up to <code>' + seconds4human(alarm.lookup_before) + '</code>'
1714
+ + ', starting <code>' + NETDATA.seconds4human(alarm.lookup_after + alarm.lookup_before, { space: ' ' }) + '</code> and up to <code>' + NETDATA.seconds4human(alarm.lookup_before, { space: ' ' }) + '</code>'
1715
+ ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ', ') + '</code>'):'')
1716
+ '.';
1717
}
@@ -1747,25 +1747,25 @@
1747
var delay = '';
1748
if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier !== 0 && alarm.delay_max_duration > 0) {
1749
if(alarm.delay_up_duration === alarm.delay_down_duration) {
1750
- delay += '<small><br/>hysteresis ' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' });
1750
+ delay += '<small><br/>hysteresis ' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' });
1751
}
1752
else {
1753
delay = '<small><br/>hysteresis ';
1754
if(alarm.delay_up_duration > 0) {
1755
- delay += 'on escalation <code>' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }) + '</code>, ';
1755
+ delay += 'on escalation <code>' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' }) + '</code>, ';
1756
}
1757
if(alarm.delay_down_duration > 0) {
1758
- delay += 'on recovery <code>' + seconds4human(alarm.delay_down_duration, { negative_suffix: '' }) + '</code>, ';
1758
+ delay += 'on recovery <code>' + NETDATA.seconds4human(alarm.delay_down_duration, { space: ' ', negative_suffix: '' }) + '</code>, ';
1759
}
1760
}
1761
if(alarm.delay_multiplier !== 1.0) {
1762
delay += 'multiplied by <code>' + alarm.delay_multiplier.toString() + '</code>';
1763
- delay += ', up to <code>' + seconds4human(alarm.delay_max_duration, { negative_suffix: '' }) + '</code>';
1763
+ delay += ', up to <code>' + NETDATA.seconds4human(alarm.delay_max_duration, { space: ' ', negative_suffix: '' }) + '</code>';
1764
}
1765
delay += '</small>';
1766
}
1767
1768
- html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + seconds4human(alarm.update_every, { negative_suffix: '' }) + '</td></tr>'
1768
+ html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + NETDATA.seconds4human(alarm.update_every, { space: ' ', negative_suffix: '' }) + '</td></tr>'
1769
+ ((has_alarm === true)?('<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>'):'')
1770
+ '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
1771
+ '</table></td></tr>';
@@ -2103,7 +2103,7 @@
2103
formatter: function(value, row, index) {
2104
void(row);
2105
void(index);
2106
- return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2106
+ return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2107
},
2108
align: 'center',
2109
valign: 'middle',
@@ -2117,7 +2117,7 @@
2117
formatter: function(value, row, index) {
2118
void(row);
2119
void(index);
2120
- return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2120
+ return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2121
},
2122
align: 'center',
2123
valign: 'middle',
@@ -2234,7 +2234,7 @@
2234
void(row);
2235
void(index);
2236
2237
- return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2237
+ return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2238
},
2239
align: 'center',
2240
valign: 'middle',
@@ -2276,70 +2276,6 @@
2276
});
2277
}
2278
2279
- function seconds4human(seconds, options) {
2280
- var default_options = {
2281
- now: 'now',
2282
- space: ' ',
2283
- negative_suffix: 'ago',
2284
- hour: 'hour',
2285
- hours: 'hours',
2286
- minute: 'minute',
2287
- minutes: 'minutes',
2288
- second: 'second',
2289
- seconds: 'seconds',
2290
- and: 'and'
2291
- };
2292
-
2293
- if(typeof options !== 'object')
2294
- options = default_options;
2295
- else {
2296
- var x;
2297
- for(x in default_options) {
2298
- if(typeof options[x] !== 'string')
2299
- options[x] = default_options[x];
2300
- }
2301
- }
2302
-
2303
- if(typeof seconds === 'string')
2304
- seconds = parseInt(seconds);
2305
-
2306
- if(seconds === 0)
2307
- return options.now;
2308
-
2309
- var suffix = '';
2310
- if(seconds < 0) {
2311
- seconds = -seconds;
2312
- if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
2313
- }
2314
-
2315
- var hours = Math.floor(seconds / 3600);
2316
- seconds -= (hours * 3600);
2317
-
2318
- var minutes = Math.floor(seconds / 60);
2319
- seconds -= (minutes * 60);
2320
-
2321
- var txt = '';
2322
-
2323
- if(hours > 1) txt += hours.toString() + options.space + options.hours;
2324
- else if(hours === 1) txt += hours.toString() + options.space + options.hour;
2325
-
2326
- if(hours > 0 && minutes > 0 && seconds === 0)
2327
- txt += options.space + options.and + options.space;
2328
- else if(hours > 0 && minutes > 0 && seconds > 0)
2329
- txt += ',' + options.space;
2330
-
2331
- if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
2332
- else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
2333
-
2334
- if((minutes > 0 || minutes > 0) && seconds > 0)
2335
- txt += options.space + options.and + options.space;
2336
-
2337
- if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
2338
- else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
2339
-
2340
- return txt + suffix;
2341
- }
2342
-
2279
function alarmsCallback(data) {
2280
var count = 0;
2281
for(x in data.alarms) {
@@ -3597,4 +3533,4 @@
3533
</div>
3534
</body>
3535
</html>
3600
-<script type="text/javascript" src="dashboard.js?v20170815-14"></script>
3536
+<script type="text/javascript" src="dashboard.js?v20171003-20"></script>