mrtg/htdocs/js/rrdGraphCtrl.js
2016-02-10 12:53:09 +01:00

391 lines
15 KiB
JavaScript

/* *********************************************************************
rrdGraphCtrl - control panel for rrdGraphPng charts
Copyright:
2015 OETIKER+PARTNER AG http://www.oetiker.ch
License:
Gnu GPL Version 2
Version: #VERSION#, #DATE#
Authors:
* Tobias Oetiker (oetiker)
* **********************************************************************/
/**
* The rrdGraphCtrl control turns attaches to a rrdGraphPng object and lets
* select start time and range of the graphs.
*/
qxWeb.define('rrdGraphCtrl',{
extend: qxWeb.$$qx.ui.website.Widget,
statics: {
_config : {
timeRanges: {
"Last 60 Minutes": { order: 0, len: 60, end: 'minute' },
"Last 24 Hours": { order: 1, len: 24, end: 'hour' },
"Last 7 Days": { order: 2, len: 7, end: 'day' },
"Last 31 Days": { order: 3, len: 31, end: 'day' },
"Last 12 Months": { order: 4, len: 12, end: 'month' },
"Today": { order: 5, len: 1, end: 'day' },
"This Week": { order: 6, len: 1, end: 'week' },
"This Month": { order: 7, len: 1, end: 'month' },
"This Year": { order: 8, len: 1, end: 'year' },
"60 Minutes": { order: 9, len: 3600},
"12 Hours": { order: 10, len: 12*3600},
"24 Hours": { order: 11, len: 24*3600},
"7 Days": { order: 12, len: 7*24*3600},
"4 Weeks": { order: 13, len: 4*7*24*3600},
"12 Months": { order: 13, len: 365*24*3600}
},
initialTimeRange: 'Today',
rangeMatchPrecision: 0.05,
showTimeBox: true,
resetTimeOnDateChange: false,
switchToCustomOnStartChange: true,
momentTz: null
},
rrdGraphCtrl: function(rrdGraphPng,cfg){
var ctrl = new rrdGraphCtrl(this);
ctrl.init(rrdGraphPng,cfg);
return ctrl;
}
},
construct : function(selector, context) {
this.base(arguments, selector, context);
},
members : {
init: function(rrdGraphPng,cfg){
if (!this.base(arguments)) {
return false;
};
if (cfg){
for (var key in cfg){
this.setConfig(key,cfg[key])
}
}
this._forEachElementWrapped(function(div,idx) {
div.setProperty('rrdGraphPng',rrdGraphPng);
div.__addDatePicker();
div.__addRangePicker();
});
return true;
},
rebind: function(rrdGraphPng){
this._forEachElementWrapped(function(div,idx) {
div.setProperty('rrdGraphPng',rrdGraphPng);
div.emit('rebindRrdGraphPng');
rrdGraphPng.setStartRange(div.getProperty('start'),div.getProperty('range'));
});
},
__addDatePicker: function(){
var rrdGraphPng = this.getProperty('rrdGraphPng');
var start = qxWeb.create('<input type="text"/>');
start.appendTo(this);
var picker = start.datepicker().setConfig('format', function(date) {
return date.toDateString();
});
var calendar = picker.getCalendar();
calendar.setValue(new Date());
var timeBox = qxWeb.create('<input class="qx-datepicker" size="10" type="text" value="00:00:00" />');
if (! this.getConfig('showTimeBox')){
timeBox.hide();
}
timeBox.appendTo(this);
var that = this;
var propagateDateTime = function(){
var time = timeBox.getValue().split(':');
[0,1,2].forEach(function(i){
time[i] = parseInt(time[i]);
if (isNaN(time[i])){
time[i] = 0;
}
});
timeBox.setValue([0,1,2].map(function(i){return ('0'+time[i]).slice(-2)}).join(':'));
var start;
var momentTz = that.getConfig('momentTz');
if (momentTz){
start = parseInt(moment.tz(moment(calendar.getValue()).format("YYYY-MM-DD"),momentTz).format('X'));
}
else {
start = calendar.getValue().getTime()/1000
}
start += time[0]*3600+time[1]*60+time[2];
rrdGraphPng.setStart(start);
that.setProperty('start',start);
that.emit('syncRrdGraphCtrlRange',start);
};
var blockDate = false;
var onChangeValueCal = function(){
if (blockDate){
blockDate = false;
return;
}
if (this.getConfig('resetTimeOnDateChange')){
timeBox.setValue('00:00:00');
}
propagateDateTime();
};
calendar.on('changeValue',onChangeValueCal,this);
var blockTime = false;
timeBox.on('change',propagateDateTime,this);
var onKeyPressTbox = function(e){
if (e.key == "Enter") {
propagateDateTime();
}
};
timeBox.on('keypress',onKeyPressTbox,this);
var lastDate;
var that = this;
var onChangeStartRange = function(e){
var start = e.start;
var range = e.range;
if (isNaN(start)) return;
var momentTz = this.getConfig('momentTz');
var date;
if (momentTz){
date = new Date(moment.tz(start * 1000,momentTz).format("YYYY/MM/DD HH:mm:ss"));
}
else {
date = new Date(start * 1000);
}
if (date != lastDate){
blockDate = true;
calendar.setValue(new Date(date.getTime()));
var newTime = date.getHours()+':'+('0'+date.getMinutes()).slice(-2)+':'+('0'+date.getSeconds()).slice(-2);
timeBox.setValue(newTime);
lastDate = date;
}
that.setProperty('start',start);
};
rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
var onRebindRrdGraphPng = function(){
rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
rrdGraphPng = this.getProperty('rrdGraphPng');
rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
};
this.on('rebindRrdGraphPng',onRebindRrdGraphPng,this);
this.once('qxRrdDispose',function(){
this.off('rebindRrdGraphPng',onRebindRrdGraphPng,this);
rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
timeBox.off('change',propagateDateTime,this);
timeBox.off('keypress',onKeyPressTbox,this);
timeBox.remove();
calendar.off('changeValue',onChangeValueCal,this);
picker.dispose();
picker.remove();
},this);
},
__getRangeMoment: function(item){
var l = item.len;
var end = moment().tz(this.getConfig('momentTz'));
if (item.end) {
end.endOf(item.end).add(1,'second');
}
var start = end.clone().subtract(item.len,item.end ? item.end : 'second');
return {
end: end.unix(),
range: end.unix() - start.unix()
};
},
__getRange: function(item){
if (this.getConfig('momentTz')){
return this.__getRangeMoment(item)
}
var d = item.end;
var l = item.len;
var now = new Date;
var start;
now.setMilliseconds(0);
now.setSeconds(0);
if (d == 'minute'){
now.setMinutes(now.getMinutes()+1)
start = new Date(now.getTime());
start.setMinutes(start.getMinutes()-l);
}
else {
now.setMinutes(0);
if (d == 'hour'){
now.setHours(now.getHours()+1)
start = new Date(now.getTime());
start.setHours(start.getHours()-l);
}
else {
now.setHours(0);
if (d == 'day'){
now.setDate(now.getDate()+1)
start = new Date(now.getTime());
start.setDate(start.getDate()-l);
}
else {
if (d == 'week'){
now.setDate(now.getDate()-now.getDay()+8);
start = new Date(now.getTime());
start.setDate(start.getDate()-l*7);
}
else {
now.setDate(1);
if (d == 'month'){
now.setMonth(now.getMonth()+1);
start = new Date(now.getTime());
start.setMonth(start.getMonth()-l);
}
else {
now.setMonth(0);
if (d == 'year'){
now.setYear(now.getFullYear()+1);
start = new Date(now.getTime());
start.setYear(start.getFullYear()-l);
}
}
}
}
}
}
var end = now.getTime()/1000;
return {
range: Math.round(end-start.getTime()/1000),
end: Math.round(end)
};
},
__addRangePicker: function(){
var rrdGraphPng = this.getProperty('rrdGraphPng');
var rangeSelector = qxWeb.create('<select class="qx-widget qx-selectbox"/>');
this.setProperty('rangeSelector',rangeSelector);
rangeSelector.appendTo(this);
var keys = [];
var tr = this.getConfig('timeRanges');
for (var prop in tr){
keys.push(prop);
}
keys.sort(function(a,b){ return tr[a].order - tr[b].order })
.forEach(function(x){
rangeSelector.append(
qxWeb.create('<option/>')
.setProperties({
value: x,
text: x
})
);
});
var custom = qxWeb.create('<option value="0">Custom</option>');
rangeSelector.append(custom);
var blockStart = false;
var that = this;
var onRangeSelectorChange = function(e){
var item = tr[rangeSelector.getValue()];
if (item){
if (item.end){
var info = that.__getRange(item);
if (info){
var range = info.range;
var start = info.end - range;
that.setProperty('range',range);
rrdGraphPng.setStartRange(start,range);
rrdGraphPng.emit('changeStartRange',{start:start,range:null});
}
else {
console.log("unknown end type "+item.end);
return;
}
}
else {
rrdGraphPng.setStartRange(rrdGraphPng.getStart(),item.len);
that.setProperty('range',item.len);
}
}
};
rangeSelector.setValue(this.getConfig('initialTimeRange'));
rangeSelector.on('change',onRangeSelectorChange,this);
onRangeSelectorChange();
var precision = this.getConfig('rangeMatchPrecision');
var that = this;
var onChangeStartRange = function(e){
var start = e.start;
var range = e.range;
if (range == null) return;
that.setProperty('range',range);
for (var key in tr){
var item = tr[key];
if (item.end){
var info = that.__getRange(item);
if (info){
var newRange = info.range;
var newStart = info.end - range;
if (Math.abs(newRange - range) / range <= precision
&& Math.abs(newStart - start) / range <= precision ) {
rangeSelector.setValue(key);
return;
}
}
else {
console.log("unknown end type "+item.end);
break;
}
}
else {
var newRange = item.len;
if (Math.abs(newRange - range) / range < 0.05){
rangeSelector.setValue(key);
return;
}
}
}
rangeSelector.setValue("0");
};
var onSyncRange = function(start){
onChangeStartRange({start:start,range:this.getProperty('range')});
};
this.on('syncRrdGraphCtrlRange',onSyncRange,this);
rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
var onRebindRrdGraphPng = function(){
rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
rrdGraphPng = this.getProperty('rrdGraphPng');
rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
rrdGraphPng.setRange(this.getProperty('range'));
};
this.on('rebindRrdGraphPng',onRebindRrdGraphPng,this);
this.once('qxRrdDispose',function(){
this.off('rebindRrdGraphPng',onRebindRrdGraphPng,this);
this.off('syncRrdGraphCtrlRange',onSyncRange,this);
rangeSelector.off('change',onRangeChange,this);
rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
rangeSelector.remove();
},this);
},
dispose: function(){
this._forEachElementWrapped(function(ctrl) {
ctrl.emit('qxRrdDispose');
});
return this.base(arguments);
}
},
defer : function(statics) {
qxWeb.$attach({rrdGraphCtrl : statics.rrdGraphCtrl});
},
});