@cryptotaxi247 / netdata-1 / commits / 7e5bdc312

chart sizes are now stored in browser local storage

Costa Tsaousis (ktsaou) committed Dec 26, 2015 at 04:17 UTC 7e5bdc312c806ab6db34ebcb478cc409dd3c63ba
2 files changed +171 -117
web/dashboard.js
+163 -114
@@ -233,102 +233,137 @@
233 // ----------------------------------------------------------------------------------------------------------------
234 // local storage options
235
236 - NETDATA.objectToLocalStorage = function(obj, prefix) {
236 + NETDATA.localStorage = {
237 + default: {},
238 + current: {},
239 + callback: {} // only used for resetting back to defaults
240 + };
241 +
242 + NETDATA.localStorageGet = function(key, def, callback) {
243 + var ret = def;
244 +
245 + if(typeof NETDATA.localStorage.default[key.toString()] === 'undefined') {
246 + NETDATA.localStorage.default[key.toString()] = def;
247 + NETDATA.localStorage.callback[key.toString()] = callback;
248 + }
249 +
250 if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
238 - for(var i in obj) {
239 - if(typeof obj[i] === 'object') {
240 - //console.log('object ' + prefix + '.' + i.toString());
241 - NETDATA.objectToLocalStorage(obj[i], prefix + '.' + i.toString());
242 - continue;
251 + try {
252 + // console.log('localStorage: loading "' + key.toString() + '"');
253 + ret = localStorage.getItem(key.toString());
254 + if(ret === null || ret === 'undefined') {
255 + // console.log('localStorage: cannot load it, saving "' + key.toString() + '" with value "' + JSON.stringify(def) + '"');
256 + localStorage.setItem(key.toString(), JSON.stringify(def));
257 + ret = def;
258 }
244 -
245 - var value = localStorage.getItem(prefix + '.' + i.toString());
246 - if(value === null) {
247 - switch(typeof obj[i]) {
248 - case 'boolean':
249 - case 'number':
250 - //console.log('write ' + prefix + '.' + i.toString() + ' = ' + obj[i].toString());
251 - localStorage.setItem(prefix + '.' + i.toString(), obj[i].toString())
252 - break;
253 - }
254 - continue;
259 + else {
260 + // console.log('localStorage: got "' + key.toString() + '" with value "' + ret + '"');
261 + ret = JSON.parse(ret);
262 + // console.log('localStorage: loaded "' + key.toString() + '" as value ' + ret + ' of type ' + typeof(ret));
263 }
264 + }
265 + catch(error) {
266 + console.log('localStorage: failed to read "' + key.toString() + '", using default: "' + def.toString() + '"');
267 + ret = def;
268 + }
269 + }
270
257 - switch(typeof obj[i]) {
258 - case 'boolean':
259 - if(value === 'true' || value === 'false') {
260 - obj[i] = (value === 'false')?false:true;
261 - //console.log('read ' + prefix + '.' + i.toString() + ' = ' + obj[i].toString());
262 - }
263 - //else console.log('ignoring ' + i.toString());
264 - break;
265 -
266 - case 'number':
267 - var n = parseFloat(value);
268 - if(isNaN(n) === false) {
269 - obj[i] = n;
270 - // console.log('read ' + prefix + '.' + i.toString() + ' = ' + obj[i].toString());
271 - }
272 - // else console.log('ignoring ' + i.toString());
273 - break;
274 - }
271 + if(typeof ret === 'undefined' || ret === 'undefined') {
272 + console.log('localStorage: LOADED UNDEFINED "' + key.toString() + '" as value ' + ret + ' of type ' + typeof(ret));
273 + ret = def;
274 + }
275 +
276 + NETDATA.localStorage.current[key.toString()] = ret;
277 + return ret;
278 + }
279 +
280 + NETDATA.localStorageSet = function(key, value, callback) {
281 + if(typeof value === 'undefined' || value === 'undefined') {
282 + console.log('localStorage: ATTEMPT TO SET UNDEFINED "' + key.toString() + '" as value ' + value + ' of type ' + typeof(value));
283 + }
284 +
285 + if(typeof NETDATA.localStorage.default[key.toString()] === 'undefined') {
286 + NETDATA.localStorage.default[key.toString()] = value;
287 + NETDATA.localStorage.current[key.toString()] = value;
288 + NETDATA.localStorage.callback[key.toString()] = callback;
289 + }
290 +
291 + if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
292 + // console.log('localStorage: saving "' + key.toString() + '" with value "' + JSON.stringify(value) + '"');
293 + try {
294 + localStorage.setItem(key.toString(), JSON.stringify(value));
295 + }
296 + catch(e) {
297 + console.log('localStorage: failed to save "' + key.toString() + '" with value: "' + value.toString() + '"');
298 }
299 }
300 +
301 + NETDATA.localStorage.current[key.toString()] = value;
302 + return value;
303 + }
304 +
305 + NETDATA.localStorageGetRecursive = function(obj, prefix, callback) {
306 + for(var i in obj) {
307 + if(typeof obj[i] === 'object') {
308 + //console.log('object ' + prefix + '.' + i.toString());
309 + NETDATA.localStorageGetRecursive(obj[i], prefix + '.' + i.toString(), callback);
310 + continue;
311 + }
312 +
313 + obj[i] = NETDATA.localStorageGet(prefix + '.' + i.toString(), obj[i], callback);
314 + }
315 }
316
317 NETDATA.setOption = function(key, value) {
280 - var ret = false;
281 -
282 - switch(typeof NETDATA.options.current[key]) {
283 - case 'boolean':
284 - if(value) NETDATA.options.current[key] = true;
285 - else NETDATA.options.current[key] = false;
286 - localStorage.setItem('options.' + key.toString(), NETDATA.options.current[key].toString());
287 - ret = true;
288 - break;
318 + if(key.toString() === 'setOptionCallback') {
319 + if(typeof NETDATA.options.current.setOptionCallback === 'function') {
320 + NETDATA.options.current[key.toString()] = value;
321 + NETDATA.options.current.setOptionCallback();
322 + }
323 + }
324 + else if(NETDATA.options.current[key.toString()] !== value) {
325 + var name = 'options.' + key.toString();
326
290 - case 'number':
291 - if(typeof value === 'number') {
292 - NETDATA.options.current[key] = value;
293 - localStorage.setItem('options.' + key.toString(), NETDATA.options.current[key].toString());
294 - ret = true;
295 - }
296 - //else
297 - // console.log('invalid number given for option key ' + key.toString);
298 - break;
327 + if(typeof NETDATA.localStorage.default[name.toString()] === 'undefined')
328 + console.log('localStorage: setOption() on unsaved option: "' + name.toString() + '", value: ' + value);
329
300 - case 'function':
301 - if(typeof value === 'function') {
302 - NETDATA.options.current[key] = value;
303 - ret = true;
304 - }
305 - //else
306 - // console.log('invalid function given for option key ' + key.toString);
307 - break;
330 + //console.log(NETDATA.localStorage);
331 + //console.log('setOption: setting "' + key.toString() + '" to "' + value + '" of type ' + typeof(value) + ' original type ' + typeof(NETDATA.options.current[key.toString()]));
332 + //console.log(NETDATA.options);
333 + NETDATA.options.current[key.toString()] = NETDATA.localStorageSet(name.toString(), value, null);
334
309 - default:
310 - // console.log('cannot find option key ' + key.toString());
311 - break;
335 + if(typeof NETDATA.options.current.setOptionCallback === 'function')
336 + NETDATA.options.current.setOptionCallback();
337 }
338
314 - if(ret === true)
315 - NETDATA.options.current.setOptionCallback();
316 -
317 - return ret;
339 + return true;
340 }
341
342 NETDATA.getOption = function(key) {
321 - return NETDATA.options.current[key];
343 + return NETDATA.options.current[key.toString()];
344 }
345
346 + // read settings from local storage
347 + NETDATA.localStorageGetRecursive(NETDATA.options.current, 'options', null);
348 +
349 + // always start with this option enabled.
350 + NETDATA.setOption('stop_updates_when_focus_is_lost', true);
351 +
352 NETDATA.resetOptions = function() {
325 - // console.log('will reset all');
326 - for(var i in NETDATA.options.defaults) {
327 - if(i.toString() === 'setOptionCallback') continue;
353 + for(var i in NETDATA.localStorage.default) {
354 + var a = i.split('.');
355 +
356 + if(a[0] === 'options') {
357 + if(a[1] === 'options.setOptionCallback') continue;
358 + if(typeof NETDATA.localStorage.default[i] === 'undefined') continue;
359 + if(NETDATA.options.current[i] === NETDATA.localStorage.default[i]) continue;
360
329 - if(NETDATA.options.current[i] !== NETDATA.options.defaults[i]) {
330 - // console.log('reseting ' + i.toString() + ' to ' + NETDATA.options.defaults[i].toString());
331 - NETDATA.setOption(i, NETDATA.options.defaults[i]);
361 + NETDATA.setOption(a[1], NETDATA.localStorage.default[i]);
362 + }
363 + else if(a[0] === 'chart_heights') {
364 + if(typeof NETDATA.localStorage.callback[i] === 'function' && typeof NETDATA.localStorage.default[i] !== 'undefined') {
365 + NETDATA.localStorage.callback[i](NETDATA.localStorage.default[i]);
366 + }
367 }
368 }
369 }
@@ -744,17 +779,37 @@
779 // ----------------------------------------------------------------------------------------------------------------
780 // Our state object, where all per-chart values are stored
781
782 + resizeCallback = function(state) {
783 + this.state = state;
784 + this.resize = function(height) {
785 + this.state
786 + }
787 + }
788 +
789 chartState = function(element) {
790 var self = $(element);
791
750 - $.extend(this, {
751 - uuid: NETDATA.guid(), // GUID - a unique identifier for the chart
752 - id: self.data('netdata'), // string - the name of chart
792 + // GUID - a unique identifier for the chart
793 + this.uuid = NETDATA.guid();
794
754 - // the user given dimensions of the element
755 - width: self.data('width') || NETDATA.chartDefaults.width,
756 - height: self.data('height') || NETDATA.chartDefaults.height,
795 + // string - the name of chart
796 + this.id = self.data('netdata');
797 +
798 + // string - the key for localStorage settings
799 + this.settings_id = self.data('id') || null;
800 +
801 + // the user given dimensions of the element
802 + this.width = self.data('width') || NETDATA.chartDefaults.width;
803 + this.height = self.data('height') || NETDATA.chartDefaults.height;
804 +
805 + if(this.settings_id !== null) {
806 + var me = this;
807 + this.height = NETDATA.localStorageGet('chart_heights.' + this.settings_id, this.height, function(height) {
808 + me.resizeAndRedrawChart(height);
809 + });
810 + }
811
812 + $.extend(this, {
813 // string - the netdata server URL, without any path
814 host: self.data('host') || NETDATA.chartDefaults.host,
815
@@ -883,6 +938,30 @@
938 // ----------------------------------------------------------------------------------------------------------------
939 // Chart Resize
940
941 + // this is actual chart resize algorithm
942 + // it will:
943 + // - resize the entire container
944 + // - update the internal states
945 + // - resize the chart as the div changes height
946 + // - update the scrollbar of the legend
947 + chartState.prototype.resizeAndRedrawChart = function(h) {
948 + this.element.style.height = h;
949 +
950 + if(this.settings_id !== null)
951 + NETDATA.localStorageSet('chart_heights.' + this.settings_id, h);
952 +
953 + var now = new Date().getTime();
954 + NETDATA.options.last_page_scroll = now;
955 + NETDATA.options.last_resized = now;
956 + NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.stop_updates_while_resizing;
957 +
958 + if(typeof this.library.resize === 'function' && this.element_chart !== null)
959 + this.library.resize(this);
960 +
961 + if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
962 + $(this.element_legend_childs.nano).nanoScroller();
963 + };
964 +
965 chartState.prototype.resizeHandler = function(e) {
966 e.preventDefault();
967
@@ -909,27 +988,6 @@
988 this.event_resize.chart_last_w = this.element.clientWidth;
989 this.event_resize.chart_last_h = this.element.clientHeight;
990
912 - // this is actual chart resize algorithm
913 - // it will:
914 - // - resize the entire container
915 - // - update the internal states
916 - // - resize the chart as the div changes height
917 - // - update the scrollbar of the legend
918 - var resize_height_and_update_chart = function(state, h) {
919 - state.element.style.height = h.toString() + 'px';
920 -
921 - var now = new Date().getTime();
922 - NETDATA.options.last_page_scroll = now;
923 - NETDATA.options.last_resized = now;
924 - NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.stop_updates_while_resizing;
925 -
926 - if(typeof state.library.resize === 'function')
927 - state.library.resize(state);
928 -
929 - if(state.element_legend_childs.nano !== null && state.element_legend_childs.nano_options !== null)
930 - $(state.element_legend_childs.nano).nanoScroller();
931 - };
932 -
991 var now = new Date().getTime();
992 if(now - this.event_resize.last <= NETDATA.options.current.double_click_speed) {
993 // double click / double tap event
@@ -942,12 +1000,12 @@
1000
1001 // if we are not optimal, be optimal
1002 if(this.event_resize.chart_last_h != optimal)
945 - resize_height_and_update_chart(this, optimal);
1003 + this.resizeAndRedrawChart(optimal.toString() + 'px');
1004
1005 // else if we do not have the original height
1006 // reset to the original height
1007 else if(this.event_resize.chart_last_h != this.event_resize.chart_original_h)
950 - resize_height_and_update_chart(this, this.event_resize.chart_original_h);
1008 + this.resizeAndRedrawChart(this.event_resize.chart_original_h.toString() + 'px');
1009 }
1010 else {
1011 this.event_resize.last = now;
@@ -970,7 +1028,7 @@
1028 var newH = self.event_resize.chart_start_h + y - self.event_resize.mouse_start_y;
1029
1030 if(newH >= 70 && newH !== self.event_resize.chart_last_h) {
973 - resize_height_and_update_chart(self, newH);
1031 + self.resizeAndRedrawChart(newH.toString() + 'px');
1032 self.event_resize.chart_last_h = newH;
1033 }
1034 }
@@ -4126,15 +4184,6 @@
4184
4185 NETDATA._loadjQuery(function() {
4186 NETDATA.loadRequiredJs(0, function() {
4129 - // keep a copy of the default settings
4130 - NETDATA.options.defaults = $.extend({}, NETDATA.options.current);
4131 -
4132 - // read settings from local storage
4133 - NETDATA.objectToLocalStorage(NETDATA.options.current, 'options');
4134 -
4135 - // always start with this option enabled.
4136 - NETDATA.setOption('stop_updates_when_focus_is_lost', true);
4137 -
4187 if(typeof netdataDontStart === 'undefined' || !netdataDontStart) {
4188 if(NETDATA.options.debug.main_loop === true)
4189 console.log('starting chart refresh thread');
web/index.html
+8 -3
@@ -421,7 +421,7 @@
421 <center>
422 <small style="color: #BBBBBB;">Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
423 <br/>
424 - To reset all options to their defaults, click <a href="#" onclick="NETDATA.resetOptions(); return false;">here</a>.</small>
424 + To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="NETDATA.resetOptions(); return false;">here</a>.</small>
425 </center>
426
427 <table>
@@ -861,6 +861,7 @@ function prepareScreen(data) {
861 + ' data-before="0"'
862 + ' data-after="-' + duration.toString() + '"'
863 + ' data-colors="' + c + '"'
864 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
865 + ' role="application"></div>';
866 });
867 html += '</div>'; // netdata-group-container
@@ -893,6 +894,7 @@ function prepareScreen(data) {
894 + ' data-before="0"'
895 + ' data-after="-' + duration.toString() + '"'
896 + ' data-colors="' + c + '"'
897 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
898 + ' role="application"></div>';
899 });
900 html += '</div>'; // netdata-group-container
@@ -922,6 +924,7 @@ function prepareScreen(data) {
924 + ' data-before="0"'
925 + ' data-after="-' + duration.toString() + '"'
926 + ' data-colors="' + c + '"'
927 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
928 + ' role="application"></div>';
929 });
930 html += '</div>'; // netdata-group-container
@@ -946,16 +949,18 @@ function prepareScreen(data) {
949 + ' data-before="0"'
950 + ' data-after="-' + duration.toString() + '"'
951 + ' data-colors="' + c + '"'
952 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
953 + ' role="application"></div>';
954 });
955 }
956 else {
953 - $.each(t.charts, function(x, c) {
954 - html += getMessage(c.id) + '<div data-netdata="' + c.id + '"'
957 + $.each(t.charts, function(x, f) {
958 + html += getMessage(f.id) + '<div data-netdata="' + f.id + '"'
959 + ' data-width="' + pcent_width.toString() + '%"'
960 + ' data-height="' + options.chartsHeight.toString() + 'px"'
961 + ' data-before="0"'
962 + ' data-after="-' + duration.toString() + '"'
963 + + ' data-id="' + name2id(options.hostname + '/' + f.id) + '"'
964 + ' role="application"></div>';
965 });
966 }