first operational new dashboard
Costa Tsaousis (ktsaou) committed
Dec 15, 2015 at 03:19 UTC
f808f0fabe0170960120b9371e60ddc7e7e66b7e
3 files changed
+530
-268
web/dashboard.css
+1
-1
@@ -25,7 +25,7 @@ html {
25
width: 100%;
26
height: 100%;
27
overflow: hidden;
28
- background: white;
28
+ background: inherit;
29
z-index: 10000;
30
}
31
web/dashboard.js
+263
-177
@@ -146,6 +146,8 @@
146
147
crossDomainAjax: false, // enable this to request crossDomain AJAX
148
149
+ last_page_scroll: 0, // the timestamp the last time the page was scrolled
150
+
151
// the current profile
152
// we may have many...
153
current: {
@@ -215,10 +217,13 @@
217
if(NETDATA.options.debug.main_loop) console.log('welcome to NETDATA');
218
219
window.onresize = function(event) {
220
+ NETDATA.options.last_page_scroll = new Date().getTime();
221
NETDATA.options.last_resized = new Date().getTime();
222
};
223
224
window.onscroll = function(event) {
225
+ NETDATA.options.last_page_scroll = new Date().getTime();
226
+
227
// when the user scrolls he sees that we have
228
// hidden all the not-visible charts
229
// using this little function we try to switch
@@ -405,7 +410,7 @@
410
if(state.needsResize())
411
return true;
412
408
- if(state.follows_global === this.seq)
413
+ if(state.tm.pan_and_zoom_seq === this.seq)
414
return false;
415
416
return true;
@@ -461,14 +466,14 @@
466
title_date: null,
467
title_time: null,
468
title_units: null,
469
+ nano: null,
470
+ nano_options: null,
471
series: null
472
},
473
474
chart_url: null, // string - the url to download chart info
475
chart: null, // object - the chart as downloaded from the server
476
470
- downloaded_ms: 0, // milliseconds - the timestamp we downloaded the chart
471
- created_ms: 0, // boolean - the timestamp the chart was created
477
validated: false, // boolean - has the chart been validated?
478
enabled: true, // boolean - is the chart enabled for refresh?
479
paused: false, // boolean - is the chart paused for any reason?
@@ -478,13 +483,23 @@
483
updates_counter: 0, // numeric - the number of refreshes made so far
484
updates_since_last_creation: 0,
485
481
- follows_global: 0, // the sequence number of the global synchronization
482
- // between chart.
483
- // Used with NETDATA.globalPanAndZoom.seq
486
+ tm: {
487
+ last_info_downloaded: 0, // milliseconds - the timestamp we downloaded the chart
488
+
489
+ last_created: 0, // the timestamp the chart was created
490
+
491
+ last_updated: 0, // the timestamp the chart last updated with data
492
+
493
+ pan_and_zoom_seq: 0, // the sequence number of the global synchronization
494
+ // between chart.
495
+ // Used with NETDATA.globalPanAndZoom.seq
496
485
- last_resized: 0, // the last time the chart was resized
486
- last_hidden: 0,
487
- last_unhidden: 0,
497
+ last_visible_check: 0, // the time we last checked if it is visible
498
+
499
+ last_resized: 0, // the time the chart was resized
500
+ last_hidden: 0, // the time the chart was hidden
501
+ last_unhidden: 0, // the time the chart was unhidden
502
+ },
503
504
current: null, // auto, pan, zoom
505
// this is a pointer to one of the sub-classes below
@@ -622,7 +637,7 @@
637
638
// can the chart participate to the global selection sync as a slave?
639
chartState.prototype.globalSelectionSyncIsEligible = function() {
625
- if(this.library !== null && typeof this.library.setSelection === 'function' && this.isVisible() && this.created_ms !== 0)
640
+ if(this.library !== null && typeof this.library.setSelection === 'function' && this.isVisible() && this.tm.last_created !== 0)
641
return true;
642
return false;
643
}
@@ -755,7 +770,7 @@
770
if(NETDATA.globalPanAndZoom.isMaster(this) && this.isVisible())
771
NETDATA.globalPanAndZoom.clearMaster();
772
758
- this.follows_global = 0;
773
+ this.tm.pan_and_zoom_seq = 0;
774
775
this.clearSelection();
776
@@ -874,7 +889,7 @@
889
}
890
891
chartState.prototype.legendFormatValue = function(value) {
877
- if(value === null) return '';
892
+ if(value === null) return '-';
893
if(typeof value !== 'number') return value;
894
895
var abs = Math.abs(value);
@@ -885,8 +900,8 @@
900
901
chartState.prototype.legendSetLabelValue = function(label, value) {
902
var series = this.element_legend_childs.series[label];
888
-
903
if(typeof series === 'undefined') return;
904
+ if(series.value === null && series.user === null) return;
905
906
value = this.legendFormatValue(value);
907
@@ -925,6 +940,18 @@
940
941
if(this.element_legend_childs.title_units)
942
this.element_legend_childs.title_units.innerHTML = ' ';
943
+
944
+ if(this.current.data && this.element_legend_childs.series !== null) {
945
+ var labels = this.current.data.dimension_names;
946
+ var i = labels.length;
947
+ while(i--) {
948
+ var label = labels[i];
949
+
950
+ if(typeof label === 'undefined') continue;
951
+ if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
952
+ this.legendSetLabelValue(label, null);
953
+ }
954
+ }
955
}
956
957
chartState.prototype.legendShowLatestValues = function() {
@@ -936,10 +963,14 @@
963
return;
964
}
965
966
+ var show_undefined = true;
967
if(Math.abs(this.current.data.last_entry_t - this.current.data.before) <= this.current.data.view_update_every)
940
- this.legendSetDate(this.current.data.before * 1000);
941
- else
968
+ show_undefined = false;
969
+
970
+ if(show_undefined)
971
this.legendUndefined();
972
+ else
973
+ this.legendSetDate(this.current.data.before * 1000);
974
975
var labels = this.current.data.dimension_names;
976
var i = labels.length;
@@ -949,10 +980,10 @@
980
if(typeof label === 'undefined') continue;
981
if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
982
952
- if(Math.abs(this.current.data.last_entry_t - this.current.data.before) <= this.current.data.view_update_every)
953
- this.legendSetLabelValue(label, this.current.data.result_latest_values[i]);
954
- else
983
+ if(show_undefined)
984
this.legendSetLabelValue(label, null);
985
+ else
986
+ this.legendSetLabelValue(label, this.current.data.result_latest_values[i]);
987
}
988
}
989
@@ -988,8 +1019,6 @@
1019
}
1020
1021
chartState.prototype.legendUpdateDOM = function() {
991
- if(!this.hasLegend()) return;
992
-
1022
var needed = false;
1023
1024
// check that the legend DOM is up to date for the downloaded dimensions
@@ -1023,45 +1052,17 @@
1052
1053
if(this.debug) this.log('updating Legend DOM');
1054
1026
- this.element_legend.innerHTML = '';
1027
-
1028
- this.element_legend_childs = {
1029
- title_date: document.createElement('span'),
1030
- title_time: document.createElement('span'),
1031
- title_units: document.createElement('span'),
1032
- series: {}
1033
- };
1034
-
1035
- this.element_legend_childs.title_date.className += " netdata-legend-title-date";
1036
- this.element_legend.appendChild(this.element_legend_childs.title_date);
1037
-
1038
- this.element_legend.appendChild(document.createElement('br'));
1039
-
1040
- this.element_legend_childs.title_time.className += " netdata-legend-title-time";
1041
- this.element_legend.appendChild(this.element_legend_childs.title_time);
1042
-
1043
- this.element_legend.appendChild(document.createElement('br'));
1044
-
1045
- this.element_legend_childs.title_units.className += " netdata-legend-title-units";
1046
- this.element_legend.appendChild(this.element_legend_childs.title_units);
1047
-
1048
- this.element_legend.appendChild(document.createElement('br'));
1049
-
1050
- var nano = document.createElement('div');
1051
- nano.className = 'netdata-legend-series';
1052
- this.element_legend.appendChild(nano);
1053
-
1054
- var content = document.createElement('div');
1055
- content.className = 'netdata-legend-series-content';
1056
- nano.appendChild(content);
1057
-
1058
- self = $(this);
1055
+ self = $(this.element);
1056
var genLabel = function(state, parent, name, count) {
1057
var c = count % state.chartColors().length;
1058
1059
var user_element = null;
1060
var user_id = self.data('show-value-of-' + name + '-at') || null;
1064
- if(user_id) user_element = document.getElementById(user_id);
1061
+ if(user_id !== null) {
1062
+ user_element = document.getElementById(user_id) || null;
1063
+ if(user_element === null)
1064
+ me.log('Cannot find element with id: ' + user_id);
1065
+ }
1066
1067
state.element_legend_childs.series[name] = {
1068
name: document.createElement('span'),
@@ -1097,6 +1098,61 @@
1098
parent.appendChild(label.value);
1099
};
1100
1101
+ var content = document.createElement('div');
1102
+
1103
+ if(this.hasLegend()) {
1104
+ this.element_legend_childs = {
1105
+ title_date: document.createElement('span'),
1106
+ title_time: document.createElement('span'),
1107
+ title_units: document.createElement('span'),
1108
+ nano: document.createElement('div'),
1109
+ nano_options: {
1110
+ paneClass: 'netdata-legend-series-pane',
1111
+ sliderClass: 'netdata-legend-series-slider',
1112
+ contentClass: 'netdata-legend-series-content',
1113
+ enabledClass: '__enabled',
1114
+ flashedClass: '__flashed',
1115
+ activeClass: '__active',
1116
+ tabIndex: -1,
1117
+ alwaysVisible: true
1118
+ },
1119
+ series: {}
1120
+ };
1121
+
1122
+ this.element_legend.innerHTML = '';
1123
+
1124
+ this.element_legend_childs.title_date.className += " netdata-legend-title-date";
1125
+ this.element_legend.appendChild(this.element_legend_childs.title_date);
1126
+
1127
+ this.element_legend.appendChild(document.createElement('br'));
1128
+
1129
+ this.element_legend_childs.title_time.className += " netdata-legend-title-time";
1130
+ this.element_legend.appendChild(this.element_legend_childs.title_time);
1131
+
1132
+ this.element_legend.appendChild(document.createElement('br'));
1133
+
1134
+ this.element_legend_childs.title_units.className += " netdata-legend-title-units";
1135
+ this.element_legend.appendChild(this.element_legend_childs.title_units);
1136
+
1137
+ this.element_legend.appendChild(document.createElement('br'));
1138
+
1139
+ this.element_legend_childs.nano.className = 'netdata-legend-series';
1140
+ this.element_legend.appendChild(this.element_legend_childs.nano);
1141
+
1142
+ content.className = 'netdata-legend-series-content';
1143
+ this.element_legend_childs.nano.appendChild(content);
1144
+ }
1145
+ else {
1146
+ this.element_legend_childs = {
1147
+ title_date: null,
1148
+ title_time: null,
1149
+ title_units: null,
1150
+ nano: null,
1151
+ nano_options: null,
1152
+ series: {}
1153
+ };
1154
+ }
1155
+
1156
if(this.current.data) {
1157
var me = this;
1158
$.each(me.current.data.dimension_names, function(i, d) {
@@ -1118,18 +1174,9 @@
1174
1175
this.element_legend_childs.hidden = document.createElement('div');
1176
el.appendChild(this.element_legend_childs.hidden);
1121
- nano.appendChild(el);
1122
-
1123
- $(nano).nanoScroller({
1124
- paneClass: 'netdata-legend-series-pane',
1125
- sliderClass: 'netdata-legend-series-slider',
1126
- contentClass: 'netdata-legend-series-content',
1127
- enabledClass: '__enabled',
1128
- flashedClass: '__flashed',
1129
- activeClass: '__active',
1130
- tabIndex: -1,
1131
- alwaysVisible: true
1132
- });
1177
+
1178
+ if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
1179
+ $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
1180
1181
this.legendShowLatestValues();
1182
}
@@ -1137,38 +1184,25 @@
1184
chartState.prototype.createChartDOM = function() {
1185
if(this.debug) this.log('creating DOM');
1186
1140
- if(this.hasLegend()) {
1141
- this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
1142
- this.element_chart = document.createElement('div');
1143
- this.element_chart.className += ' netdata-chart-with-legend-right';
1144
- this.element_chart.className += ' netdata-' + this.library_name + '-chart-with-legend-right';
1145
- this.element_chart.id = this.element_chart_id;
1146
- $(this.element_chart).data('netdata-state-object', this);
1147
- this.element.appendChild(this.element_chart);
1148
-
1149
- this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
1150
- this.element_legend = document.createElement('div');
1151
- this.element_legend.className += ' netdata-chart-legend';
1152
- this.element_legend.className += ' netdata-' + this.library_name + '-legend';
1153
- this.element_legend.id = this.element_legend_id;
1154
- $(this.element_legend).data('netdata-state-object', this);
1155
- this.element.appendChild(this.element_legend);
1156
- this.element_legend_childs.series = null;
1157
- this.legendUpdateDOM();
1158
- }
1159
- else {
1160
- this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
1161
- this.element_chart = document.createElement('div');
1162
- this.element_chart.className += ' netdata-chart';
1163
- this.element_chart.className += ' netdata-' + this.library_name + '-chart';
1164
- this.element_chart.id = this.element_chart_id;
1165
- $(this.element_chart).data('netdata-state-object', this);
1166
- this.element.appendChild(this.element_chart);
1167
-
1168
- this.element_legend_id = null;
1169
- this.element_legend = null;
1170
- this.element_legend_childs.series = null;
1171
- }
1187
+ this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
1188
+ this.element_chart = document.createElement('div');
1189
+ this.element_chart.className += ' netdata-chart' + (this.hasLegend()?'-with-legend-right':'').toString();
1190
+ this.element_chart.className += ' netdata-' + this.library_name + '-chart' + (this.hasLegend()?'-with-legend-right':'').toString();
1191
+ this.element_chart.id = this.element_chart_id;
1192
+ $(this.element_chart).data('netdata-state-object', this);
1193
+ this.element.appendChild(this.element_chart);
1194
+
1195
+ this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
1196
+ this.element_legend = document.createElement('div');
1197
+ this.element_legend.className += ' netdata-chart-legend';
1198
+ this.element_legend.className += ' netdata-' + this.library_name + '-legend';
1199
+ this.element_legend.id = this.element_legend_id;
1200
+ $(this.element_legend).data('netdata-state-object', this);
1201
+ if(!this.hasLegend()) this.element_legend.style.display = 'none';
1202
+ else this.element.appendChild(this.element_legend);
1203
+
1204
+ this.element_legend_childs.series = null;
1205
+ this.legendUpdateDOM();
1206
1207
// in case the user has an active global selection sync in place
1208
// reset it
@@ -1219,14 +1253,14 @@
1253
}
1254
1255
chartState.prototype.needsResize = function() {
1222
- return (this.library && !this.library.autoresize() && this.last_resized < NETDATA.options.last_resized);
1256
+ return (this.library && !this.library.autoresize() && this.tm.last_resized < NETDATA.options.last_resized);
1257
}
1258
1259
chartState.prototype.resizeChart = function() {
1260
if(this.needsResize()) {
1261
if(this.debug) this.log('forcing re-generation due to window resize.');
1228
- this.created_ms = 0;
1229
- this.last_resized = new Date().getTime();
1262
+ this.tm.last_created = 0;
1263
+ this.tm.last_resized = new Date().getTime();
1264
}
1265
}
1266
@@ -1236,12 +1270,12 @@
1270
if(NETDATA.globalPanAndZoom.isActive()) {
1271
after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
1272
before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
1239
- this.follows_global = NETDATA.globalPanAndZoom.seq;
1273
+ this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq;
1274
}
1275
else {
1276
before = this.current.force_before_ms !== null ? Math.round(this.current.force_before_ms / 1000) : this.before;
1277
after = this.current.force_after_ms !== null ? Math.round(this.current.force_after_ms / 1000) : this.after;
1244
- this.follows_global = 0;
1278
+ this.tm.pan_and_zoom_seq = 0;
1279
}
1280
1281
this.current.requested_after_ms = after * 1000;
@@ -1273,7 +1307,7 @@
1307
if(this.debug) this.log('got data from netdata server');
1308
this.current.data = data;
1309
1276
- var started = new Date().getTime();
1310
+ var started = this.tm.last_updated = new Date().getTime();
1311
1312
// if the result is JSON, find the latest update-every
1313
if(typeof data === 'object') {
@@ -1318,10 +1352,10 @@
1352
1353
if(this.updates_since_last_creation >= this.library.max_updates_to_recreate()) {
1354
if(this.debug) this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
1321
- this.created_ms = 0;
1355
+ this.tm.last_created = 0;
1356
}
1357
1324
- if(this.created_ms > 0 && typeof this.library.update === 'function') {
1358
+ if(this.tm.last_created > 0 && typeof this.library.update === 'function') {
1359
if(this.debug) this.log('updating chart...');
1360
1361
// check and update the legend
@@ -1336,7 +1370,7 @@
1370
this.library.update(this, data);
1371
}
1372
catch(err) {
1339
- this.error('chart "' + this.id + '" failed to be updated as ' + this.library_name);
1373
+ this.error('chart failed to be updated as ' + this.library_name);
1374
}
1375
}
1376
}
@@ -1348,15 +1382,15 @@
1382
1383
if(NETDATA.options.debug.chart_errors) {
1384
this.library.create(this, data);
1351
- this.created_ms = new Date().getTime();
1385
+ this.tm.last_created = new Date().getTime();
1386
}
1387
else {
1388
try {
1389
this.library.create(this, data);
1356
- this.created_ms = new Date().getTime();
1390
+ this.tm.last_created = new Date().getTime();
1391
}
1392
catch(err) {
1359
- this.error('chart "' + this.id + '" failed to be created as ' + this.library_name);
1393
+ this.error('chart failed to be created as ' + this.library_name);
1394
}
1395
}
1396
}
@@ -1455,19 +1489,24 @@
1489
title_date: null,
1490
title_time: null,
1491
title_units: null,
1492
+ nano: null,
1493
+ nano_options: null,
1494
series: null
1495
};
1496
1497
this.element.innerHTML = '';
1498
this.refresh_dt_element = null;
1499
1464
- this.created_ms = 0;
1500
+ this.tm.last_created = 0;
1501
this.paused = false;
1502
this.selected = false;
1503
this.updates_counter = 0;
1504
this.updates_since_last_creation = 0;
1469
- this.follows_global = 0;
1470
- this.last_resized = 0;
1505
+ this.tm.pan_and_zoom_seq = 0;
1506
+ this.tm.last_resized = 0;
1507
+ this.tm.last_visible_check = 0;
1508
+ this.tm.last_hidden = 0;
1509
+ this.tm.last_unhidden = 0;
1510
1511
if(this.current !== null) {
1512
this.current.last_autorefreshed = 0;
@@ -1488,19 +1527,24 @@
1527
}
1528
1529
chartState.prototype.unhideChart = function() {
1491
- if(typeof this.___isHidden___ !== 'undefined') {
1530
+ if(typeof this.___isHidden___ !== 'undefined' && this.enabled === true) {
1531
this.element_message.style.display = 'none';
1532
if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
1533
if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
1534
if(this.element_loading !== null) this.element_loading.style.display = 'none';
1535
this.___isHidden___ = undefined;
1536
this.element_message.innerHTML = 'chart ' + this.id + ' is visible now';
1498
- this.last_unhidden = new Date().getTime();
1537
+
1538
+ // refresh the scrolbar
1539
+ if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
1540
+ $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
1541
+
1542
+ this.tm.last_unhidden = new Date().getTime();
1543
}
1544
}
1545
1546
chartState.prototype.hideChart = function() {
1503
- if(typeof this.___isHidden___ === 'undefined') {
1547
+ if(typeof this.___isHidden___ === 'undefined' && this.enabled === true) {
1548
if(NETDATA.options.current.destroy_on_hide === true)
1549
this.destroyChart();
1550
@@ -1509,40 +1553,47 @@
1553
if(this.element_legend !== null) this.element_legend.style.display = 'none';
1554
if(this.element_loading !== null) this.element_loading.style.display = 'none';
1555
this.___isHidden___ = true;
1556
+ this.___showsLoading___ = undefined;
1557
this.element_message.innerHTML = 'chart ' + this.id + ' is hidden to speed up the browser';
1513
- this.last_hidden = new Date().getTime();
1558
+ this.tm.last_hidden = new Date().getTime();
1559
}
1560
}
1561
1562
chartState.prototype.hideLoading = function() {
1518
- if(typeof this.___showsLoading___ !== 'undefined') {
1563
+ if(typeof this.___showsLoading___ !== 'undefined' && this.enabled === true) {
1564
this.element_message.style.display = 'none';
1565
if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
1566
if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
1567
if(this.element_loading !== null) this.element_loading.style.display = 'none';
1568
this.___showsLoading___ = undefined;
1569
this.element_loading.innerHTML = 'chart ' + this.id + ' finished loading!';
1525
- this.last_unhidden = new Date().getTime();
1570
+ this.tm.last_unhidden = new Date().getTime();
1571
}
1572
}
1573
1574
chartState.prototype.showLoading = function() {
1530
- if(typeof this.___showsLoading___ === 'undefined' && this.created_ms === 0) {
1575
+ if(typeof this.___showsLoading___ === 'undefined' && this.tm.last_created === 0 && this.enabled === true) {
1576
this.element_message.style.display = 'none';
1577
if(this.element_chart !== null) this.element_chart.style.display = 'none';
1578
if(this.element_legend !== null) this.element_legend.style.display = 'none';
1579
if(this.element_loading !== null) this.element_loading.style.display = 'inline-block';
1580
this.___showsLoading___ = true;
1581
+ this.___isHidden___ = undefined;
1582
this.element_loading.innerHTML = 'chart ' + this.id + ' is loading...';
1537
- this.last_hidden = new Date().getTime();
1583
+ this.tm.last_hidden = new Date().getTime();
1584
}
1585
}
1586
1587
chartState.prototype.isVisible = function() {
1588
+ // 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)
1590
+ return this.___isVisible___;
1591
+
1592
+ this.tm.last_visible_check = new Date().getTime();
1593
+
1594
var wh = window.innerHeight;
1595
var x = this.element.getBoundingClientRect();
1596
var ret = 0;
1545
-
1597
var tolerance = 0;
1598
1599
if(x.top < 0 && -x.top > x.height) {
@@ -1556,13 +1607,16 @@
1607
1608
if(ret > tolerance) {
1609
// the chart is too far
1559
- if(this.created_ms !== 0) this.hideChart();
1560
- return false;
1610
+ this.___isVisible___ = false;
1611
+ if(this.tm.last_created !== 0) this.hideChart();
1612
+ return this.___isVisible___;
1613
+ }
1614
+ else {
1615
+ // the chart is inside or very close
1616
+ this.___isVisible___ = true;
1617
+ this.unhideChart();
1618
+ return this.___isVisible___;
1619
}
1562
-
1563
- // the chart is inside or very close
1564
- this.unhideChart();
1565
- return true;
1620
}
1621
1622
chartState.prototype.isAutoRefreshed = function() {
@@ -1649,6 +1703,7 @@
1703
this.chart_url = chart.url;
1704
this.current.view_update_every = chart.update_every * 1000;
1705
this.current.points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
1706
+ this.tm.last_info_downloaded = new Date().getTime();
1707
}
1708
1709
// fetch the chart description from the netdata server
@@ -1677,7 +1732,7 @@
1732
})
1733
.fail(function() {
1734
NETDATA.error(404, self.chart_url);
1680
- self.error('chart "' + self.id + '" not found on url "' + self.chart_url + '"');
1735
+ self.error('chart not found on url "' + self.chart_url + '"');
1736
})
1737
.always(function() {
1738
if(typeof callback === 'function') callback();
@@ -1704,8 +1759,8 @@
1759
1760
// show a message in the chart
1761
chartState.prototype.message = function(type, msg) {
1707
- this.element_message.innerHTML = msg;
1762
this.hideChart();
1763
+ this.element_message.innerHTML = msg;
1764
1765
// reset the creation datetime
1766
// since we overwrote the whole element
@@ -1802,6 +1857,10 @@
1857
}
1858
1859
NETDATA._loadCSS = function(filename) {
1860
+ // don't use jQuery here
1861
+ // styles are loaded before jQuery
1862
+ // to eliminate showing an unstyled page to the user
1863
+
1864
var fileref = document.createElement("link");
1865
fileref.setAttribute("rel", "stylesheet");
1866
fileref.setAttribute("type", "text/css");
@@ -1888,7 +1947,7 @@
1947
if(NETDATA.options.updated_dom) {
1948
// the dom has been updated
1949
// get the dom parts again
1891
- NETDATA.getDomCharts(NETDATA.chartRefresher);
1950
+ NETDATA.parseDom(NETDATA.chartRefresher);
1951
return;
1952
}
1953
if(index >= NETDATA.options.targets.length) {
@@ -1926,7 +1985,7 @@
1985
if(NETDATA.options.updated_dom) {
1986
// the dom has been updated
1987
// get the dom parts again
1929
- NETDATA.getDomCharts(NETDATA.chartRefresher);
1988
+ NETDATA.parseDom(NETDATA.chartRefresher);
1989
return;
1990
}
1991
@@ -1964,7 +2023,7 @@
2023
if(NETDATA.options.updated_dom) {
2024
// the dom has been updated
2025
// get the dom parts again
1967
- NETDATA.getDomCharts(NETDATA.chartRefresher);
2026
+ NETDATA.parseDom(NETDATA.chartRefresher);
2027
return;
2028
}
2029
@@ -2001,7 +2060,8 @@
2060
}
2061
}
2062
2004
- NETDATA.getDomCharts = function(callback) {
2063
+ NETDATA.parseDom = function(callback) {
2064
+ NETDATA.options.last_page_scroll = new Date().getTime();
2065
NETDATA.options.updated_dom = false;
2066
2067
var targets = $('div[data-netdata]').filter(':visible');
@@ -2041,7 +2101,7 @@
2101
if(NETDATA.options.debug.focus) console.log('Document has no focus!');
2102
}
2103
2044
- NETDATA.getDomCharts(NETDATA.chartRefresher);
2104
+ NETDATA.parseDom(NETDATA.chartRefresher);
2105
}
2106
2107
// ----------------------------------------------------------------------------------------------------------------
@@ -2238,8 +2298,10 @@
2298
var r = state.calculateRowForTime(t);
2299
if(r !== -1)
2300
state.dygraph_instance.setSelection(r);
2241
- else
2301
+ else {
2302
state.dygraph_instance.clearSelection();
2303
+ state.legendUndefined();
2304
+ }
2305
}
2306
2307
return true;
@@ -2300,11 +2362,9 @@
2362
// its element size as 0x0.
2363
// this will make it re-appear properly
2364
2303
- if(state.last_unhidden > state.dygraph_last_rendered)
2365
+ if(state.tm.last_unhidden > state.dygraph_last_rendered)
2366
dygraph.resize();
2367
2306
- state.dygraph_last_rendered = new Date().getTime();
2307
-
2368
if(state.current.name === 'pan') {
2369
if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartUpdate() loose update');
2370
dygraph.updateOptions({
@@ -2323,15 +2383,32 @@
2383
valueRange: null
2384
});
2385
}
2386
+
2387
+ state.dygraph_last_rendered = new Date().getTime();
2388
};
2389
2390
NETDATA.dygraphChartCreate = function(state, data) {
2391
if(NETDATA.options.debug.dygraph || state.debug) state.log('dygraphChartCreate()');
2392
2331
- state.dygraph_last_rendered = new Date().getTime();
2332
-
2393
var self = $(state.element);
2394
2395
+ var chart_type = state.chart.chart_type;
2396
+ if(chart_type === 'stacked' && data.dimensions === 1) chart_type = 'area';
2397
+ chart_type = self.data('dygraph-type') || chart_type;
2398
+
2399
+ var smooth = (chart_type === 'line' && !NETDATA.chartLibraries.dygraph.isSparkline(state))?true:false;
2400
+ smooth = self.data('dygraph-smooth') || smooth;
2401
+
2402
+ if(!NETDATA.dygraph.smooth)
2403
+ smooth = false;
2404
+
2405
+ var strokeWidth = (chart_type === 'stacked')?0.0:((smooth)?1.5:1.0)
2406
+ var highlightCircleSize = (NETDATA.chartLibraries.dygraph.isSparkline(state))?3:4;
2407
+
2408
+
2409
+ //if(state.id == 'system.cpu')
2410
+ // console.log(data);
2411
+
2412
state.dygraph_options = {
2413
colors: self.data('dygraph-colors') || state.chartColors(),
2414
@@ -2343,7 +2420,8 @@
2420
title: self.data('dygraph-title') || state.chart.title,
2421
titleHeight: self.data('dygraph-titleheight') || 19,
2422
2346
- legend: self.data('dygraph-legend') || NETDATA.chartLibraries.dygraph.legend(state)?'always':'never', // 'onmouseover',
2423
+// legend: self.data('dygraph-legend') || NETDATA.chartLibraries.dygraph.legend(state)?'always':'never', // 'onmouseover',
2424
+ legend: self.data('dygraph-legend') || 'always', // 'onmouseover',
2425
labels: data.result.labels,
2426
labelsDiv: self.data('dygraph-labelsdiv') || state.element_legend_childs.hidden,
2427
labelsDivStyles: self.data('dygraph-labelsdivstyles') || { 'fontSize':'10px', 'zIndex': 10000 },
@@ -2362,7 +2440,7 @@
2440
plotter: null,
2441
2442
// The width of the lines connecting data points. This can be used to increase the contrast or some graphs.
2365
- strokeWidth: self.data('dygraph-strokewidth') || (state.chart.chart_type === 'stacked')?0.0:1.0,
2443
+ strokeWidth: self.data('dygraph-strokewidth') || strokeWidth,
2444
strokePattern: self.data('dygraph-strokepattern') || undefined,
2445
2446
// The size of the dot to draw on each point in pixels (see drawPoints). A dot is always drawn when a point is "isolated",
@@ -2380,16 +2458,16 @@
2458
2459
// Draw a border around graph lines to make crossing lines more easily distinguishable. Useful for graphs with many lines.
2460
strokeBorderColor: self.data('dygraph-strokebordercolor') || 'white',
2383
- strokeBorderWidth: self.data('dygraph-strokeborderwidth') || (state.chart.chart_type === 'stacked')?0.0:0.0,
2461
+ strokeBorderWidth: self.data('dygraph-strokeborderwidth') || (chart_type === 'stacked')?0.0:0.0,
2462
2385
- fillGraph: self.data('dygraph-fillgraph') || (state.chart.chart_type === 'area')?true:false,
2386
- fillAlpha: self.data('dygraph-fillalpha') || (state.chart.chart_type === 'stacked')?0.8:0.2,
2387
- stackedGraph: self.data('dygraph-stackedgraph') || (state.chart.chart_type === 'stacked')?true:false,
2463
+ fillGraph: self.data('dygraph-fillgraph') || (chart_type === 'area')?true:false,
2464
+ fillAlpha: self.data('dygraph-fillalpha') || (chart_type === 'stacked')?0.8:0.2,
2465
+ stackedGraph: self.data('dygraph-stackedgraph') || (chart_type === 'stacked')?true:false,
2466
stackedGraphNaNFill: self.data('dygraph-stackedgraphnanfill') || 'none',
2467
2468
drawAxis: self.data('dygraph-drawaxis') || true,
2469
axisLabelFontSize: self.data('dygraph-axislabelfontsize') || 10,
2392
- axisLineColor: self.data('dygraph-axislinecolor') || '#DDD',
2470
+ axisLineColor: self.data('dygraph-axislinecolor') || '#CCC',
2471
axisLineWidth: self.data('dygraph-axislinewidth') || 0.3,
2472
2473
drawGrid: self.data('dygraph-drawgrid') || true,
@@ -2397,16 +2475,16 @@
2475
drawYGrid: self.data('dygraph-drawygrid') || undefined,
2476
gridLinePattern: self.data('dygraph-gridlinepattern') || null,
2477
gridLineWidth: self.data('dygraph-gridlinewidth') || 0.3,
2400
- gridLineColor: self.data('dygraph-gridlinecolor') || '#EEE',
2478
+ gridLineColor: self.data('dygraph-gridlinecolor') || '#DDD',
2479
2480
maxNumberWidth: self.data('dygraph-maxnumberwidth') || 8,
2481
sigFigs: self.data('dygraph-sigfigs') || null,
2482
digitsAfterDecimal: self.data('dygraph-digitsafterdecimal') || 2,
2483
valueFormatter: self.data('dygraph-valueformatter') || function(x){ return x.toFixed(2); },
2484
2407
- highlightCircleSize: self.data('dygraph-highlightcirclesize') || 4,
2485
+ highlightCircleSize: self.data('dygraph-highlightcirclesize') || highlightCircleSize,
2486
highlightSeriesOpts: self.data('dygraph-highlightseriesopts') || null, // TOO SLOW: { strokeWidth: 1.5 },
2409
- highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha') || null, // TOO SLOW: (state.chart.chart_type === 'stacked')?0.7:0.5,
2487
+ highlightSeriesBackgroundAlpha: self.data('dygraph-highlightseriesbackgroundalpha') || null, // TOO SLOW: (chart_type === 'stacked')?0.7:0.5,
2488
2489
pointClickCallback: self.data('dygraph-pointclickcallback') || undefined,
2490
axes: {
@@ -2623,26 +2701,21 @@
2701
state.dygraph_options.drawAxis = false;
2702
state.dygraph_options.title = undefined;
2703
state.dygraph_options.units = undefined;
2626
- state.dygraph_options.legend = 'never'; // 'follow'
2704
state.dygraph_options.ylabel = undefined;
2705
state.dygraph_options.yLabelWidth = 0;
2706
state.dygraph_options.labelsDivWidth = 120;
2707
state.dygraph_options.labelsDivStyles.width = '120px';
2708
state.dygraph_options.labelsSeparateLines = true;
2632
- state.dygraph_options.highlightCircleSize = 3;
2709
state.dygraph_options.rightGap = 0;
2634
- state.dygraph_options.strokeWidth = 1.0;
2710
}
2636
- else if(NETDATA.dygraph.smooth && state.chart.chart_type === 'line') {
2637
- // smooth lines patch
2711
+
2712
+ if(smooth === true && typeof smoothPlotter === 'function')
2713
state.dygraph_options.plotter = smoothPlotter;
2639
- state.dygraph_options.strokeWidth = 1.5;
2640
- }
2641
-
2642
-
2714
2715
state.dygraph_instance = new Dygraph(state.element_chart,
2716
data.result.data, state.dygraph_options);
2717
+
2718
+ state.dygraph_last_rendered = new Date().getTime();
2719
};
2720
2721
// ----------------------------------------------------------------------------------------------------------------
@@ -3091,8 +3164,25 @@
3164
// Start up
3165
3166
NETDATA.requiredJs = [
3094
- NETDATA.serverDefault + 'lib/jquery.nanoscroller.min.js',
3095
- NETDATA.serverDefault + 'lib/bootstrap.min.js'
3167
+ {
3168
+ url: NETDATA.serverDefault + 'lib/bootstrap.min.js',
3169
+ isAlreadyLoaded: function() {
3170
+ if(typeof $().emulateTransitionEnd == 'function')
3171
+ return true;
3172
+ else
3173
+ return false;
3174
+ }
3175
+ },
3176
+ {
3177
+ url: NETDATA.serverDefault + 'lib/jquery.nanoscroller.min.js',
3178
+ isAlreadyLoaded: function() { return false; }
3179
+ }
3180
+ ];
3181
+
3182
+ NETDATA.requiredCSS = [
3183
+ NETDATA.serverDefault + 'css/bootstrap.min.css',
3184
+ //NETDATA.serverDefault + 'css/bootstrap-theme.min.css',
3185
+ NETDATA.dashboard_css
3186
];
3187
3188
NETDATA.loadRequiredJs = function(index, callback) {
@@ -3102,33 +3192,29 @@
3192
return;
3193
}
3194
3105
- if(NETDATA.options.debug.main_loop) console.log('loading ' + NETDATA.requiredJs[index]);
3195
+ if(NETDATA.requiredJs[index].isAlreadyLoaded()) {
3196
+ NETDATA.loadRequiredJs(++index, callback);
3197
+ return;
3198
+ }
3199
+
3200
+ if(NETDATA.options.debug.main_loop) console.log('loading ' + NETDATA.requiredJs[index].url);
3201
$.ajax({
3107
- url: NETDATA.requiredJs[index],
3202
+ url: NETDATA.requiredJs[index].url,
3203
cache: true,
3204
dataType: "script"
3205
})
3206
.success(function() {
3112
- if(NETDATA.options.debug.main_loop) console.log('loaded ' + NETDATA.requiredJs[index]);
3207
+ if(NETDATA.options.debug.main_loop) console.log('loaded ' + NETDATA.requiredJs[index].url);
3208
NETDATA.loadRequiredJs(++index, callback);
3209
})
3210
.fail(function() {
3116
- alert('Cannot load required JS library: ' + NETDATA.requiredJs[index]);
3211
+ alert('Cannot load required JS library: ' + NETDATA.requiredJs[index].url);
3212
})
3213
}
3214
3120
- NETDATA.requiredCSS = [
3121
- NETDATA.serverDefault + 'css/bootstrap.min.css',
3122
- //NETDATA.serverDefault + 'css/bootstrap-theme.min.css',
3123
- NETDATA.dashboard_css
3124
- ];
3125
-
3215
NETDATA.loadRequiredCSS = function(index) {
3127
- if(index >= NETDATA.requiredCSS.length) {
3128
- if(typeof callback === 'function')
3129
- callback();
3216
+ if(index >= NETDATA.requiredCSS.length)
3217
return;
3131
- }
3218
3219
if(NETDATA.options.debug.main_loop) console.log('loading ' + NETDATA.requiredCSS[index]);
3220
NETDATA._loadCSS(NETDATA.requiredCSS[index]);
@@ -3136,10 +3222,10 @@
3222
}
3223
3224
NETDATA.errorReset();
3225
+ NETDATA.loadRequiredCSS(0);
3226
NETDATA._loadjQuery(function() {
3227
NETDATA.loadRequiredJs(0, function() {
3228
//NETDATA.chartRegistry.downloadAll(NETDATA.serverDefault, function() {
3142
- NETDATA.loadRequiredCSS(0);
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');
web/dashboard_full.html
+266
-90
@@ -11,8 +11,25 @@
11
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
12
<meta name="author" content="costa@tsaousis.gr">
13
<style>
14
+
15
+ /* prevent body from hidding under the navbar */
16
body {
15
- padding-top:50px;
17
+ padding-top: 50px;
18
+ }
19
+
20
+ /* fix # anchors scrolling under the navbar
21
+ https://github.com/twbs/bootstrap/issues/1768#issuecomment-46519033
22
+ */
23
+ *[id]:before {
24
+ display: block;
25
+ content: " ";
26
+ margin-top: -70px;
27
+ height: 70px;
28
+ visibility: hidden;
29
+ }
30
+
31
+ .container {
32
+ width: 90% !important;
33
}
34
35
#masthead h1 {
@@ -25,23 +42,144 @@
42
margin-top:4%;
43
}
44
28
- #sidebar li.active {
29
- border:0 #eee solid;
30
- border-right-width:5px;
45
+
46
+ /*
47
+ * Side navigation
48
+ *
49
+ * Scrollspy and affixed enhanced navigation to highlight sections and secondary
50
+ * sections of docs content.
51
+ */
52
+
53
+ /* By default it's not affixed in mobile views, so undo that */
54
+ .dashboard-sidebar.affix {
55
+ position: static;
56
+ }
57
+ @media (min-width: 768px) {
58
+ .dashboard-sidebar {
59
+ padding-left: 20px;
60
+ }
61
+ }
62
+
63
+ .affix {
64
+ position: static;
65
+ top: 50px;
66
+ width: 170px;
67
+ }
68
+ .affix-top {
69
+ width: 170px;
70
+ }
71
+
72
+ /* First level of nav */
73
+ .dashboard-sidenav {
74
+ margin-top: 20px;
75
+ margin-bottom: 20px;
76
+ }
77
+
78
+ /* All levels of nav */
79
+ .dashboard-sidebar .nav > li > a {
80
+ display: block;
81
+ padding: 4px 20px;
82
+ font-size: 13px;
83
+ font-weight: 500;
84
+ color: #767676;
85
+ }
86
+ .dashboard-sidebar .nav > li > a:hover,
87
+ .dashboard-sidebar .nav > li > a:focus {
88
+ padding-left: 19px;
89
+ color: #563d7c;
90
+ text-decoration: none;
91
+ background-color: transparent;
92
+ border-left: 1px solid #563d7c;
93
+ }
94
+ .dashboard-sidebar .nav > .active > a,
95
+ .dashboard-sidebar .nav > .active:hover > a,
96
+ .dashboard-sidebar .nav > .active:focus > a {
97
+ padding-left: 18px;
98
+ font-weight: bold;
99
+ color: #563d7c;
100
+ background-color: transparent;
101
+ border-left: 2px solid #563d7c;
102
}
103
33
- @media (min-width: 979px) {
34
- #sidebar.affix-top {
35
- position: static;
36
- margin-top:30px;
37
- width:228px;
38
- }
39
-
40
- #sidebar.affix {
41
- position: fixed;
42
- top:70px;
43
- width:228px;
44
- }
104
+ /* Nav: second level (shown on .active) */
105
+ .dashboard-sidebar .nav .nav {
106
+ display: none; /* Hide by default, but at >768px, show it */
107
+ padding-bottom: 10px;
108
+ }
109
+ .dashboard-sidebar .nav .nav > li > a {
110
+ padding-top: 1px;
111
+ padding-bottom: 1px;
112
+ padding-left: 30px;
113
+ font-size: 12px;
114
+ font-weight: normal;
115
+ }
116
+ .dashboard-sidebar .nav .nav > li > a:hover,
117
+ .dashboard-sidebar .nav .nav > li > a:focus {
118
+ padding-left: 29px;
119
+ }
120
+ .dashboard-sidebar .nav .nav > .active > a,
121
+ .dashboard-sidebar .nav .nav > .active:hover > a,
122
+ .dashboard-sidebar .nav .nav > .active:focus > a {
123
+ padding-left: 28px;
124
+ font-weight: 500;
125
+ }
126
+
127
+ /* Back to top (hidden on mobile) */
128
+ .back-to-top,
129
+ .dashboard-theme-toggle {
130
+ display: none;
131
+ padding: 4px 10px;
132
+ margin-top: 10px;
133
+ margin-left: 10px;
134
+ font-size: 12px;
135
+ font-weight: 500;
136
+ color: #999;
137
+ }
138
+ .back-to-top:hover,
139
+ .dashboard-theme-toggle:hover {
140
+ color: #563d7c;
141
+ text-decoration: none;
142
+ }
143
+ .dashboard-theme-toggle {
144
+ margin-top: 0;
145
+ }
146
+
147
+ @media (min-width: 768px) {
148
+ .back-to-top,
149
+ .dashboard-theme-toggle {
150
+ display: block;
151
+ }
152
+ }
153
+
154
+ /* Show and affix the side nav when space allows it */
155
+ @media (min-width: 992px) {
156
+ .dashboard-sidebar .nav > .active > ul {
157
+ display: block;
158
+ }
159
+ /* Widen the fixed sidebar */
160
+ .dashboard-sidebar.affix,
161
+ .dashboard-sidebar.affix-bottom {
162
+ width: 213px;
163
+ }
164
+ .dashboard-sidebar.affix {
165
+ position: fixed; /* Undo the static from mobile first approach */
166
+ top: 20px;
167
+ }
168
+ .dashboard-sidebar.affix-bottom {
169
+ position: absolute; /* Undo the static from mobile first approach */
170
+ }
171
+ .dashboard-sidebar.affix-bottom .dashboard-sidenav,
172
+ .dashboard-sidebar.affix .dashboard-sidenav {
173
+ margin-top: 0;
174
+ margin-bottom: 0;
175
+ }
176
+ }
177
+ @media (min-width: 1200px) {
178
+ /* Widen the fixed sidebar again */
179
+ .dashboard-sidebar.affix-bottom,
180
+ .dashboard-sidebar.affix {
181
+ width: 263px;
182
+ }
183
}
184
</style>
185
@@ -52,7 +190,7 @@
190
<!-- load the dashboard manager - it will do the rest -->
191
<script type="text/javascript" src="dashboard.js"></script>
192
</head>
55
-<body>
193
+<body data-spy="scroll">
194
<nav class="navbar navbar-default navbar-fixed-top" role="banner">
195
<div class="container">
196
<div class="navbar-header">
@@ -78,21 +216,22 @@
216
<div id="masthead">
217
<div class="container">
218
<div class="row">
81
- <div class="col-md-6">
219
+ <div class="col-md-7">
220
<h1>Netdata Dashboard
221
<p class="lead">Real time data collection and graphs...</p>
222
</h1>
223
</div>
86
- <div class="col-md-6">
224
+ <div class="col-md-5">
225
<div class="well well-lg">
226
<div class="row">
89
- <div class="col-sm-6">
90
- <div data-netdata="system.cpu" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-before="0" data-after="-60" data-width="100%" data-height="60px"></div>
227
+ <div class="col-md-6">
228
+ <b>Drag</b> charts to pan.
229
+ <b>Shift + wheel</b> on them, to zoom in and out.
230
+ <b>Double-click</b> on them, to reset.
231
+ <b>Hover</b> on them too!
232
</div>
92
- <div class="col-sm-6">
93
- Drag charts to pan.<br/>
94
- Shift + wheel on them, to zoom.</br>
95
- Double-click on them, to reset.
233
+ <div class="col-md-6">
234
+ <div data-netdata="system.intr" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dygraph-type="line" data-dygraph-strokewidth="3" data-dygraph-smooth="true" data-dygraph-highlightcirclesize="6" data-after="-40" data-height="60px" data-colors="#C66"></div>
235
</div>
236
</div>
237
</div>
@@ -106,18 +245,8 @@
245
<div class="col-md-10" role="main">
246
<div id="charts_div"></div>
247
</div>
109
- <div class="col-md-2" role="complementary">
110
- <div class="hidden-print hidden-xs hidden-sm affix-top">
111
- <ul class="nav nav-stacked" id="sidebar">
112
- <li><a href="#sec0">Section 0</a>
113
- <ul class="nav">
114
- <li><a href="#sec0">Section 0a</a></li>
115
- <li><a href="#sec0">Section 0b</a></li>
116
- </ul>
117
- </li>
118
- <li><a href="#sec0">Section 1</a></li>
119
- </ul>
120
- </div>
248
+ <div class="col-md-2" role="main">
249
+ <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" data-spy="affix" id="sidebar"></nav>
250
</div>
251
</div>
252
</div>
@@ -134,9 +263,13 @@ var options = {
263
families_idx: {},
264
chartsPerRow: 0,
265
chartsMinWidth: 1450,
137
- chartsHeight: 150,
266
+ chartsHeight: 180,
267
sparklinesHeight: 60
139
-}
268
+};
269
+
270
+var messages = {
271
+ '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.'
272
+};
273
274
function screenWidth() {
275
return (($(window).width() * 0.95) - 50);
@@ -369,48 +502,56 @@ function prepareScreen(data) {
502
var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
503
console.log(duration);
504
var html = '';
372
- var sidebar = '';
505
+ var sidebar = '<ul class="nav dashboard-sidenav" id="sidebar_ul">';
506
+
507
+ function getMessage(id) {
508
+ if(typeof messages[id] !== 'undefined')
509
+ return messages[id];
510
+ else
511
+ return '';
512
+ }
513
514
// render the charts
515
$.each(options.categories, function(i, t) {
516
t.charts.sort(prioritySort);
517
378
- sidebar += '<li><a href="#section' + i + '">' + t.title + '</a></li>';
379
- html += '<h2 id="section' + i + '">' + t.title + '</h2>';
518
+ sidebar += '<li class="' + ((i === 0)?'active':'').toString() + '"><a href="#' + t.name + '">' + t.title + '</a>';
519
+ html += '<h1 id="' + t.name + '">' + t.title + '</h1><div id="' + t.name + '">';
520
381
- if(t.name === 'net') {
521
+ if(t.name === 'net' || t.name === 'tc') {
522
var interfaces = uniq_with_list(t.charts, function(c) { return c.family; });
383
- console.log(interfaces);
523
385
- $.each(interfaces, function(i, c) {
386
- html += '<div class="netdata-group-container" id="interface_' + c.name + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 class="netdata-chart-alignment">' + c.name + '</h2>';
524
+ sidebar += '<ul class="nav">';
525
+ $.each(interfaces, function(j, c) {
526
+ sidebar += '<li class><a href="#' + t.name + '_' + c.name + '">' + c.name + '</a></li>';
527
+ html += '<div class="netdata-group-container" id="interface_' + t.name + '_' + c.name + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + t.name + '_' + c.name + '" class="netdata-chart-alignment">' + c.name + '</h2>';
528
$.each(c.values, function(x, f) {
388
- if(f.type === 'net') {
389
- html += '<div data-netdata="' + f.id + '"'
390
- + ' data-width="100%"'
391
- + ' data-height="' + options.chartsHeight.toString() + 'px"'
392
- + ' data-before="0"'
393
- + ' data-after="-' + duration.toString() + '"'
394
- + '></div>';
395
- }
396
- else {
397
- html += '<div data-netdata="' + f.id + '"'
398
- + ' data-width="100%"'
399
- + ' data-height="' + (options.chartsHeight / 2).toString() + 'px"'
400
- + ' data-before="0"'
401
- + ' data-after="-' + duration.toString() + '"'
402
- + '></div>';
529
+ var c = null;
530
+ var h = options.chartsHeight / 2;
531
+ switch(f.type) {
532
+ case 'net' : h = options.chartsHeight; break;
533
+ case 'tc' : h = options.chartsHeight; break;
534
}
535
+
536
+ html += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
537
+ + ' data-width="100%"'
538
+ + ' data-height="' + h.toString() + 'px"'
539
+ + ' data-before="0"'
540
+ + ' data-after="-' + duration.toString() + '"'
541
+ + ' data-colors="' + c + '"'
542
+ + '></div>';
543
});
544
html += '</div>';
545
});
546
+ sidebar += '</ul>';
547
}
548
else if(t.name === 'disk') {
549
var disks = uniq_with_list(t.charts, function(c) { return c.family; });
410
- console.log(disks);
550
412
- $.each(disks, function(i, c) {
413
- html += '<div class="netdata-group-container" id="disk_' + c.name + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 class="netdata-chart-alignment">' + c.name + '</h2>';
551
+ sidebar += '<ul class="nav">';
552
+ $.each(disks, function(j, c) {
553
+ sidebar += '<li class><a href="#' + c.name + '">' + c.name + '</a></li>';
554
+ html += '<div class="netdata-group-container" id="disk_' + c.name + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + c.name + '" class="netdata-chart-alignment">' + c.name + '</h2>';
555
$.each(c.values, function(x, f) {
556
var c = null;
557
var h = options.chartsHeight / 2;
@@ -418,10 +559,10 @@ function prepareScreen(data) {
559
case 'disk' : h = options.chartsHeight; break;
560
case 'disk_backlog': c = '#DD4477'; break;
561
case 'disk_util' : c = '#109618'; break;
421
- case 'disk_qops' : c = '#8B0707'; break;
562
+ case 'disk_qops' : c = '#E67300'; break;
563
}
564
424
- html += '<div data-netdata="' + f.id + '"'
565
+ html += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
566
+ ' data-width="100%"'
567
+ ' data-height="' + h.toString() + 'px"'
568
+ ' data-before="0"'
@@ -431,10 +572,32 @@ function prepareScreen(data) {
572
});
573
html += '</div>';
574
});
575
+ sidebar += '</ul>';
576
+ }
577
+ else if(t.name === 'apps') {
578
+ $.each(t.charts, function(x, f) {
579
+ var c = null;
580
+ var h = options.chartsHeight / 2;
581
+ switch(f.id) {
582
+ case 'apps.cpu' : h = options.chartsHeight; break;
583
+ case 'apps.preads' : h = options.chartsHeight; break;
584
+ case 'apps.pwrites' : h = options.chartsHeight; break;
585
+ case 'apps.mem' : h = options.chartsHeight; break;
586
+ case 'apps.major_faults': h = options.chartsHeight; break;
587
+ }
588
+
589
+ html += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
590
+ + ' data-width="100%"'
591
+ + ' data-height="' + h.toString() + 'px"'
592
+ + ' data-before="0"'
593
+ + ' data-after="-' + duration.toString() + '"'
594
+ + ' data-colors="' + c + '"'
595
+ + '></div>';
596
+ });
597
}
598
else {
599
$.each(t.charts, function(x, c) {
437
- html += '<div data-netdata="' + c.id + '"'
600
+ html += getMessage(c.id) + '<div data-netdata="' + c.id + '"'
601
+ ' data-width="' + pcent_width.toString() + '%"'
602
+ ' data-height="' + options.chartsHeight.toString() + 'px"'
603
+ ' data-before="0"'
@@ -443,9 +606,12 @@ function prepareScreen(data) {
606
});
607
}
608
446
- html += '';
609
+ sidebar += '</li>';
610
+ html += '</div><hr/>';
611
});
612
+ sidebar += '</ul>';
613
614
+ // show the colors
615
html += '<br/>'
616
$.each(NETDATA.colors, function(i, c){
617
html += '<div style="display: inline-block;"><div style="display: inline-block; width: 100px; height: 100px; background: ' + c + ';"></div><br/>' + c + '</div>';
@@ -453,40 +619,50 @@ function prepareScreen(data) {
619
620
div.innerHTML = html;
621
document.getElementById('sidebar').innerHTML = sidebar;
456
- NETDATA.unpause();
622
458
- /* activate sidebar */
459
- $('#sidebar').affix({
460
- offset: {
461
- top: 200
462
- }
463
- });
623
+ // resize all charts - without starting the background thread
624
+ // this has to be done while NETDATA is paused
625
+ // if we ommit this, the affix menu will be wrong, since all
626
+ // the Dom elements are initially zero-sized
627
+ NETDATA.parseDom();
628
465
- // fix for jumping to proper anchor after ajax
466
- $(window).load(function(){
467
- // Remove the # from the hash, as different browsers may or may not include it
468
- var hash = location.hash.replace('#','');
629
+ // let it run (update the charts)
630
+ NETDATA.unpause();
631
470
- if(hash != '') {
471
- // Clear the hash in the URL
472
- // location.hash = ''; // delete front "//" if you want to change the address bar
473
- $('html, body').animate({ scrollTop: $(location.hash).offset().top - 55}, 0);
474
- }
475
- });
632
+ // check if we have to jump to a specific section
633
+ var hash = location.hash.replace('#','');
634
+ if(hash != '') {
635
+ // Clear the hash in the URL
636
+ // location.hash = ''; // delete front "//" if you want to change the address bar
637
+ $('html, body').animate({ scrollTop: $(location.hash).offset().top}, 0);
638
+ }
639
477
- /* activate scrollspy menu */
640
+ /* activate bootstrap scrollspy (needed for sidebar) */
641
$(document.body).scrollspy({
479
- target: '#leftCol',
480
- offset: -55
642
+ target: '#sidebar',
643
+ offset: $(window).height() / 3 // controls the diff of the <hX> element to the top, to select it
644
+ });
645
+
646
+ /* activate bootstrap sidebar (affix) */
647
+ $('#sidebar_ul').affix({
648
+ offset: {
649
+ top: 200
650
+ }
651
});
652
}
653
654
NETDATA.ready(function() {
655
+
656
+ // download all the charts the server knows
657
NETDATA.chartRegistry.downloadAll(NETDATA.serverDefault, function(data) {
486
- NETDATA.pause(function () {
658
+
659
+ // pause the NETDATA thread that updates the charts
660
+ NETDATA.pause(function() {
661
+
662
+ // prepare our DOM
663
+ // this will be called when NETDATA is paused
664
prepareScreen(data);
665
});
666
});
667
});
491
-
668
</script>