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
}