@cryptotaxi247 / netdata-1 / commits / f808f0fab

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>