2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-13 17:26:34 +00:00

chartingfrontend: some bugfixes, introducing multicharts / statusview

git-svn-id: https://svn.fhem.de/fhem/trunk@4630 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
johannnes 2014-01-12 14:02:15 +00:00
parent 389b718fbe
commit f5c4cbcc48
9 changed files with 854 additions and 152 deletions

View File

@ -3,6 +3,7 @@ DIR www/frontend/app/model
DIR www/frontend/app/store
DIR www/frontend/app/view
DIR www/frontend/app/controller
DIR www/frontend/app/imagecache
DIR www/frontend/app/resources
DIR www/frontend/app/resources/icons
DIR www/frontend/lib
@ -28,7 +29,7 @@ DIR www/frontend/lib/ext-4.2.0.663/images/window
DIR www/frontend/lib/ext-4.2.0.663/images/grid
DIR www/frontend/lib/ext-4.2.0.663/images/util
DIR www/frontend/lib/ext-4.2.0.663/images/util/splitter
UPD 2013-12-26_09:59:17 1054 www/frontend/index.html
UPD 2014-01-11_09:31:08 1170 www/frontend/index.html
UPD 2013-04-01_07:03:30 260475 www/frontend/lib/ext-4.2.0.663/ext-theme-gray-all.css
UPD 2013-12-07_02:00:26 1497654 www/frontend/lib/ext-4.2.0.663/ext-all.js
UPD 2013-04-01_07:03:33 1981 www/frontend/lib/ext-4.2.0.663/images/tools/tools-sprites-trans.gif
@ -272,14 +273,16 @@ UPD 2013-03-02_01:53:05 524 www/frontend/app/resources/icons/resultset_last.png
UPD 2013-04-03_07:27:17 733 www/frontend/app/resources/icons/add.png
UPD 2013-04-03_07:27:17 389 www/frontend/app/resources/icons/resultset_previous.png
UPD 2013-06-30_11:47:12 101 www/frontend/app/resources/application.css
UPD 2014-01-03_12:47:07 2714 www/frontend/app/app.js
UPD 2014-01-12_11:31:30 3028 www/frontend/app/app.js
UPD 2013-04-28_02:00:20 1205 www/frontend/app/view/ChartGridPanel.js
UPD 2013-07-07_12:12:08 16201 www/frontend/app/view/DevicePanel.js
UPD 2013-12-26_08:39:37 10257 www/frontend/app/view/TableDataGridPanel.js
UPD 2014-01-03_01:24:06 65039 www/frontend/app/view/LineChartPanel.js
UPD 2013-12-27_01:39:11 9980 www/frontend/app/view/Viewport.js
UPD 2014-01-03_01:38:11 19171 www/frontend/app/controller/MainController.js
UPD 2014-01-03_01:30:11 107834 www/frontend/app/controller/ChartController.js
UPD 2014-01-12_12:09:17 5144 www/frontend/app/view/StatusPanel.js
UPD 2014-01-12_12:55:22 10486 www/frontend/app/view/Viewport.js
UPD 2014-01-12_02:42:27 21844 www/frontend/app/controller/MainController.js
UPD 2014-01-12_02:49:58 16562 www/frontend/app/controller/StatusController.js
UPD 2014-01-12_02:51:54 109250 www/frontend/app/controller/ChartController.js
UPD 2013-06-30_11:46:54 5415 www/frontend/app/controller/TableDataController.js
UPD 2013-04-01_07:04:35 202 www/frontend/app/model/ReadingsModel.js
UPD 2013-04-01_07:04:36 338 www/frontend/app/model/SavedChartsModel.js

View File

@ -17,6 +17,7 @@ Ext.application({
],
controllers: [
'FHEM.controller.StatusController',
'FHEM.controller.MainController',
'FHEM.controller.ChartController',
'FHEM.controller.TableDataController'
@ -38,6 +39,12 @@ Ext.application({
try {
FHEM.info = Ext.decode(response.responseText);
FHEM.version = FHEM.info.Results[0].devices[0].ATTR.version;
if (window.location.href.indexOf("frontenddev") > 0) {
FHEM.appPath = 'www/frontenddev/app/';
} else {
FHEM.appPath = 'www/frontend/app/';
}
Ext.each(FHEM.info.Results, function(result) {
if (result.list === "DbLog" && result.devices[0].NAME) {
FHEM.dblogname = result.devices[0].NAME;

View File

@ -123,6 +123,12 @@ Ext.define('FHEM.controller.ChartController', {
},
'radiogroup[name=datasourceradio]': {
change: this.dataSourceChanged
},
'button[name=updatepreviewchart]': {
loadhiddenchart: this.loadsavedchart
},
'button[name=loadfullchart]': {
loadchart: this.loadsavedchart
}
});
@ -291,8 +297,8 @@ Ext.define('FHEM.controller.ChartController', {
/**
* Triggers a request to FHEM Module to get the data from Database
*/
requestChartData: function(stepchangecalled) {
requestChartData: function(stepchangecalled, hidden) {
var me = this;
//show loadmask
@ -314,7 +320,7 @@ Ext.define('FHEM.controller.ChartController', {
dbendtime = Ext.Date.format(endtime, 'Y-m-d_H:i:s'),
dynamicradio = Ext.ComponentQuery.query('radiogroup[name=dynamictime]')[0],
chartpanel = me.getLinechartpanel(),
chart = me.getChart();
hiddenchartdiv = Ext.get("hiddenchart");
//cleanup chartpanel
var existingchartgrid = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
@ -334,9 +340,16 @@ Ext.define('FHEM.controller.ChartController', {
existingchart.destroy();
}
var store = Ext.create('FHEM.store.ChartStore'),
proxy = store.getProxy();
chart = me.createChart(store);
chartpanel.add(chart);
proxy = store.getProxy(),
chart;
if (hidden === true) {
chart = me.createChart(store, hiddenchartdiv);
} else {
chart = me.createChart(store);
chartpanel.add(chart);
}
//reset zoomValues
chartpanel.setLastYmax(null);
@ -455,14 +468,12 @@ Ext.define('FHEM.controller.ChartController', {
* resize the chart to fit the centerpanel
*/
resizeChart: function() {
var lcp = Ext.ComponentQuery.query('linechartpanel')[0];
var lcv = Ext.ComponentQuery.query('chart')[0];
var cfp = Ext.ComponentQuery.query('form[name=chartformpanel]')[0];
var cdg = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
if (lcv) {
if (lcp && lcv && cfp && cdg) {
var lcph = lcp.getHeight(),
lcpw = lcp.getWidth(),
@ -493,7 +504,7 @@ Ext.define('FHEM.controller.ChartController', {
/**
* create the base chart
*/
createChart: function(store) {
createChart: function(store, hidden) {
var me = this;
var chart = Ext.create('Ext.panel.Panel', {
@ -502,6 +513,9 @@ Ext.define('FHEM.controller.ChartController', {
collapsible: true,
titleCollapse: true,
animCollapse: false,
width: hidden ? 1 : false,
height: hidden ? 1 : false,
renderTo: hidden ? hidden : false,
items: [
{
xtype: 'toolbar',
@ -531,46 +545,51 @@ Ext.define('FHEM.controller.ChartController', {
var chart = btn.up().up().down('chart'),
cp = chart.up().up();
chart.restoreZoom();
chart.axes.get(0).minimum = cp.getLastYmin();
chart.axes.get(0).maximum = cp.getLastYmax();
chart.axes.get(1).minimum = cp.getLastY2min();
chart.axes.get(1).maximum = cp.getLastY2max();
chart.axes.get(2).minimum = cp.getLastXmin();
chart.axes.get(2).maximum = cp.getLastXmax();
//helper to reshow the hidden items after zooming back out
if (cp.artifactSeries && cp.artifactSeries.length > 0) {
Ext.each(cp.artifactSeries, function(serie) {
serie.showAll();
var showMarkers = false;
Ext.each(serie.group.items, function(item) {
// make sure we hit the points
if (item.radius && item.radius > 0) {
item.show();
item.redraw();
showMarkers = true;
//only reset zoom when chart was really zoomed, else will break layout
if (cp.timesZoomed !== 0) {
chart.restoreZoom();
chart.axes.get(0).minimum = cp.getLastYmin();
chart.axes.get(0).maximum = cp.getLastYmax();
chart.axes.get(1).minimum = cp.getLastY2min();
chart.axes.get(1).maximum = cp.getLastY2max();
chart.axes.get(2).minimum = cp.getLastXmin();
chart.axes.get(2).maximum = cp.getLastXmax();
//helper to reshow the hidden items after zooming back out
if (cp.artifactSeries && cp.artifactSeries.length > 0) {
Ext.each(cp.artifactSeries, function(serie) {
serie.showAll();
var showMarkers = false;
Ext.each(serie.group.items, function(item) {
// make sure we hit the points
if (item.radius && item.radius > 0) {
item.show();
item.redraw();
showMarkers = true;
}
});
if (showMarkers) {
serie.showMarkers = true;
}
});
if (showMarkers) {
serie.showMarkers = true;
}
});
cp.artifactSeries = [];
cp.artifactSeries = [];
}
chart.redraw();
// restore the counter as we have zoomed out
cp.timesZoomed = 0;
}
chart.redraw();
// restore the counter as we have zoomed out
cp.timesZoomed = 0;
}
}
]
},
{
xtype: 'chart',
isPreviewChart: hidden ? true : false,
legend: {
position: 'right',
visible: hidden ? false : true,
labelFont: '10px Helvetica, sans-serif',
padding: 4
},
@ -605,35 +624,6 @@ Ext.define('FHEM.controller.ChartController', {
store: store,
enableMask: true,
mask: true,//'vertical',//true, //'horizontal',
gradients: [{
id: 'gradientId',
angle: 90,
stops: {
0: {
color: '#FF0000'
},
50: {
color: '#FFFF00'
},
100: {
color: '#079400'
}
}
}, {
id: 'gradientId2',
angle: 0,
stops: {
0: {
color: '#590'
},
20: {
color: '#599'
},
100: {
color: '#ddd'
}
}
}],
listeners: {
mousedown: function(evt) {
// fix for firefox, not dragging images
@ -687,7 +677,7 @@ Ext.define('FHEM.controller.ChartController', {
*/
createBaseLine: function(index, basestart, baseend, basefill, basecolor) {
var me = this,
chart = me.getChart(),
chart = Ext.ComponentQuery.query('chart')[0],
store = chart.getStore(),
yfield = "VALUEBASE" + index;
@ -743,7 +733,7 @@ Ext.define('FHEM.controller.ChartController', {
populateAxis: function(i, axeslength, device, yaxis, yaxisindex, styleConfig, axisside, yaxisstatistics, dbstarttime, dbendtime, logtype) {
var me = this,
chart = me.getChart(),
chart = Ext.ComponentQuery.query('chart')[0],
store = chart.getStore(),
proxy = store.getProxy(),
yseries,
@ -773,14 +763,42 @@ Ext.define('FHEM.controller.ChartController', {
// as the get command wont support absolute pathes by default...
currentlogfile = "../../../../../../../../" + currentlogfile;
}
// get the conversions keys and values from userconfig
var queryString;
if (Ext.isDefined(FHEM) && Ext.isDefined(FHEM.userconfig)) {
var count = 0;
Ext.iterate(FHEM.userconfig.chartkeys, function(k, v) {
if (count === 0) {
queryString = '$fld[' + (yaxisindex - 1) + ']=~"' + k + '"?' + v + ':';
} else {
queryString += '($fld[' + (yaxisindex - 1) + ']=~"' + k + '"?' + v + ':';
}
count++;
});
// last fallback, similar to parseint
queryString += '$fld[3]*1';
// add closing brackets
for (bracket = 1; bracket < count; bracket++) {
queryString += ")";
}
}
cmd = 'get Logfile ' +
currentlogfile + ' - ' + dbstarttime +
' ' + dbendtime + ' ' + yaxisindex + ':' + yaxis +
'\\x3a::$fld[' + (yaxisindex - 1) +
']=~"ok|on|open|active|true"?1:($fld[' +
(yaxisindex - 1) +
']=~"low|off|closed|inactive|false"?0:$fld[' +
(yaxisindex - 1) + ']*1)';
'\\x3a::' + queryString;
// '\\x3a::$fld[' + (yaxisindex - 1) +
// ']=~"ok|on|open|active|true"?1:($fld[' +
// (yaxisindex - 1) +
// ']=~"low|off|closed|inactive|false"?0:$fld[' +
// (yaxisindex - 1) + ']*1)';
} else if (!Ext.isDefined(yaxisstatistics) || yaxisstatistics === "none" || Ext.isEmpty(yaxisstatistics)) {
cmd = 'get ' + FHEM.dblogname + ' - webchart ' + dbstarttime + ' ' + dbendtime + ' ';
cmd +=device + ' timerange ' + "TIMESTAMP" + ' ' + yaxis;
@ -993,7 +1011,6 @@ Ext.define('FHEM.controller.ChartController', {
}
chart.series.add(yseries);
}
},
failure: function() {
@ -1138,9 +1155,10 @@ Ext.define('FHEM.controller.ChartController', {
chart.axes.get(2).processView();
me.resizeChart();
chart.show();
// only call resize function when not a hidden chart
if (chart.isPreviewChart === false) {
me.resizeChart();
}
me.getLinechartpanel().setLoading(false);
},
@ -1151,7 +1169,7 @@ Ext.define('FHEM.controller.ChartController', {
createSeries: function(yfield, title, styleConfig, axisside) {
//setting axistitle and fontsize
var chart = this.getChart(),
var chart = Ext.ComponentQuery.query('chart')[0],
axis;
if (axisside === "left") {
@ -1188,46 +1206,59 @@ Ext.define('FHEM.controller.ChartController', {
//adding linked yfield to axis fields
axis.fields.push(yfield);
var series = {
type : 'line',
axis : axisside,
xField : 'TIMESTAMP',
yField : yfield,
title: title,
showInLegend: (styleConfig.yaxislegendcheck === "false" || styleConfig.yaxislegendcheck === false) ? false : true,
smooth: (styleConfig.yaxisstepcheck === "true" || styleConfig.yaxisstepcheck === true)? 0 : styleConfig.yaxissmoothing,
highlight: {
size: 5,
radius: 5
chart.surface.addGradient({
id: 'gradientId',
angle: 90,
stops: {
10: {
color: '#FFFFFF'
},
fill: (styleConfig.yaxisfillcheck === "false" || styleConfig.yaxisfillcheck === false) ? false : true,
style: {
fill: '#' + styleConfig.fillcolorhexcode,
// fill: 'url(#gradientId)',
opacity: styleConfig.fillopacity,
stroke: '#' + styleConfig.linecolorhexcode,
'stroke-width': styleConfig.linestrokewidth
},
markerConfig: {
type: styleConfig.pointshape,
radius: styleConfig.pointradius,
stroke: '#' + styleConfig.pointcolorhexcode,
fill: '#' + styleConfig.pointcolorhexcode
},
showMarkers: (styleConfig.yaxisshowpoints === "false" || styleConfig.yaxisshowpoints === false) ? false : true,
selectionTolerance: 5,
tips : {
trackMouse : true,
mouseOffset: [1,1],
showDelay: 1000,
width : 280,
height : 50,
renderer : function(storeItem, item) {
this.setTitle(' Value: : ' + storeItem.get(yfield) +
'<br> Time: ' + storeItem.get('TIMESTAMP'));
}
100: {
color: '#' + styleConfig.fillcolorhexcode
}
};
}
});
var series = {
type : 'line',
axis : axisside,
xField : 'TIMESTAMP',
yField : yfield,
title: title,
showInLegend: (styleConfig.yaxislegendcheck === "false" || styleConfig.yaxislegendcheck === false) ? false : true,
smooth: (styleConfig.yaxisstepcheck === "true" || styleConfig.yaxisstepcheck === true)? 0 : styleConfig.yaxissmoothing,
highlight: {
size: 5,
radius: 5
},
fill: (styleConfig.yaxisfillcheck === "false" || styleConfig.yaxisfillcheck === false) ? false : true,
style: {
// fill: '#' + styleConfig.fillcolorhexcode,
fill: 'url(#gradientId)',
opacity: styleConfig.fillopacity,
stroke: '#' + styleConfig.linecolorhexcode,
'stroke-width': styleConfig.linestrokewidth
},
markerConfig: {
type: styleConfig.pointshape,
radius: styleConfig.pointradius,
stroke: '#' + styleConfig.pointcolorhexcode,
fill: '#' + styleConfig.pointcolorhexcode
},
showMarkers: (styleConfig.yaxisshowpoints === "false" || styleConfig.yaxisshowpoints === false) ? false : true,
selectionTolerance: 5,
tips : {
trackMouse : true,
mouseOffset: [1,1],
showDelay: 1000,
width : 280,
height : 50,
renderer : function(storeItem, item) {
this.setTitle(' Value: : ' + storeItem.get(yfield) +
'<br> Time: ' + storeItem.get('TIMESTAMP'));
}
}
};
return series;
},
@ -1249,7 +1280,7 @@ Ext.define('FHEM.controller.ChartController', {
*/
generalizeChartData: function(generalizationfactor, index) {
var store = this.getChart().getStore();
var store = Ext.ComponentQuery.query('chart')[0].getStore();
this.factorpositive = 1 + (generalizationfactor / 100),
this.factornegative = 1 - (generalizationfactor / 100),
@ -1625,8 +1656,7 @@ Ext.define('FHEM.controller.ChartController', {
// preapre the string for the file
var finalstring = "FHEM.filelogcharts = " + Ext.encode(FHEM.filelogcharts) + ";;";
var cmd = "{ `echo '" + finalstring + "' > www/frontend/app/filelogcharts.js`}";
// var cmd = "{ `echo '" + finalstring + "' > www/frontenddev/app/filelogcharts.js`}";
var cmd = "{ `echo '" + finalstring + "' > " + FHEM.appPath + "filelogcharts.js`}";
Ext.Ajax.request({
method: 'POST',
@ -1669,7 +1699,8 @@ Ext.define('FHEM.controller.ChartController', {
/**
* loading saved chart data and trigger the load of the chart
*/
loadsavedchart: function(treeview, record) {
loadsavedchart: function(treeview, record, hidden) {
if (!record.raw.data) {
record.raw.data = record.raw;
}
@ -1691,7 +1722,10 @@ Ext.define('FHEM.controller.ChartController', {
//cleanup the form before loading
this.resetFormFields();
this.getChartformpanel().collapse();
// no collapsing when hidden chart, will break the panel if done hidden
if (hidden !== true) {
this.getChartformpanel().collapse();
}
if (chartdata && !Ext.isEmpty(chartdata)) {
@ -1912,7 +1946,7 @@ Ext.define('FHEM.controller.ChartController', {
me.getChartformpanel().down('textfield[name=leftaxistitle]').setValue(leftaxistitle);
}
this.requestChartData();
this.requestChartData(false, hidden);
this.getLinechartpanel().setTitle(name);
} else {
Ext.Msg.alert("Error", "The Chart could not be loaded! RawChartdata was: <br>" + chartdata);

View File

@ -41,6 +41,9 @@ Ext.define('FHEM.controller.MainController', {
'panel[name=fhemaccordion]': {
expand: this.showFHEMPanel
},
'panel[name=fhemstatusaccordion]': {
expand: this.showFHEMStatusPanel
},
'panel[name=tabledataaccordionpanel]': {
expand: this.showDatabaseTablePanel
},
@ -68,6 +71,9 @@ Ext.define('FHEM.controller.MainController', {
},
'button[name=sortedtree]': {
click: this.setupTree
},
'panel[name=statuspanel]': {
saveconfig: this.saveObjectToUserConfig
}
});
},
@ -84,6 +90,8 @@ Ext.define('FHEM.controller.MainController', {
me.createLineChartPanel();
me.createDatabaseTablePanel();
me.showFHEMStatusPanel();
me.getMainviewport().show();
me.getMainviewport().getEl().setOpacity(0);
me.getMainviewport().getEl().animate({
@ -95,7 +103,7 @@ Ext.define('FHEM.controller.MainController', {
if (Ext.isDefined(FHEM.version)) {
var sp = this.getStatustextfield();
sp.setText(FHEM.version + "; Frontend Version: 1.0.7 - 2014-01-03");
sp.setText(FHEM.version + "; Frontend Version: 1.0.8 - 2014-01-12");
}
this.setupTree(false);
@ -192,8 +200,10 @@ Ext.define('FHEM.controller.MainController', {
//add the charts to the tree
store.on("load", function() {
var rootNode = me.getMaintreepanel().getRootNode(),
chartfolder = {text: "Charts", expanded: true, children: []};
chartfolder = {text: "Charts", expanded: true, children: []},
statusfolder = {text: "StatusRoom", expanded: true, children: []};
rootNode.appendChild(chartfolder);
rootNode.appendChild(statusfolder);
var chartfoldernode = rootNode.findChild("text", "Charts", true);
//add the filelogcharts to the store
@ -226,6 +236,7 @@ Ext.define('FHEM.controller.MainController', {
chartchild = {text: 'Create new Chart', leaf: true, data: {template: true}, iconCls:'x-tree-icon-leaf-chart'};
chartfoldernode.appendChild(chartchild);
me.getMaintreepanel().fireEvent('treeloaded');
});
},
@ -455,6 +466,15 @@ Ext.define('FHEM.controller.MainController', {
}
},
/**
*
*/
showFHEMStatusPanel: function() {
var panel = Ext.ComponentQuery.query('statuspanel')[0];
this.hideCenterPanels();
panel.show();
},
/**
*
*/
@ -572,6 +592,54 @@ Ext.define('FHEM.controller.MainController', {
var panel = Ext.ComponentQuery.query('tabledatagridpanel')[0];
this.hideCenterPanels();
panel.show();
}
},
/**
* Method appending and saving a given object to the file userconfig.js, which is loaded on page load
* The location names the accesible part where the object should be saved in
*/
saveObjectToUserConfig: function(objectToSave, location) {
var me = this;
if (FHEM.userconfig && objectToSave && !Ext.isEmpty(location)) {
FHEM.userconfig[location] = objectToSave;
// preapre the string for the file
var finalstring = "FHEM = {};;FHEM.userconfig = " + Ext.encode(FHEM.userconfig) + ";;";
var cmd = "{ `echo '" + finalstring + "' > " + FHEM.appPath + "userconfig.js`}";
Ext.Ajax.request({
method: 'POST',
disableCaching: false,
url: '../../../fhem?',
params: {
cmd: cmd,
XHR: 1
},
success: function(response){
if (response.status === 200) {
Ext.Msg.alert("Success", "Changes successfully saved!");
} else if (response.statusText) {
Ext.Msg.alert("Error", "The Changes could not be saved, error Message is:<br><br>" + response.statusText);
} else {
Ext.Msg.alert("Error", "The Changes could not be saved!");
}
},
failure: function(response) {
if (response.statusText) {
Ext.Msg.alert("Error", "The Changes could not be saved, error Message is:<br><br>" + response.statusText);
} else {
Ext.Msg.alert("Error", "The Changes could not be saved!");
}
}
});
} else {
Ext.Msg.alert("Error", "A save attempt was made without enough parameters!");
}
}
});

View File

@ -0,0 +1,454 @@
/**
* The Controller handling Status Panel
*/
Ext.define('FHEM.controller.StatusController', {
extend: 'Ext.app.Controller',
requires: [
'FHEM.view.StatusPanel'
],
refs: [
],
/**
* boolean indicating when the charts tree is loaded
*/
treeloaded: false,
/**
* boolean indicating when the statuspanel is rendered
*/
statuspanelrendered: false,
/**
* boolean indicating that we are currently updating a preview chart
*/
updateRunning: false,
/**
* boolean indicating that we are currently updating via global autoupdater
*/
autoUpdateRunning: false,
/**
* init function to register listeners
*/
init: function() {
this.control({
'button[name=updatepreviewchart]': {
click: this.updatePreviewChart
},
'button[name=loadfullchart]': {
click: this.loadFullChart
},
'panel[name=statuspanel]': {
afterrender: function() {
this.statuspanelrendered = true;
this.setupPanelsFromTreeContent();
},
show: this.setupGlobalUpdateTask,
hide: function() {
Ext.each(Ext.TaskManager.tasks, function(task) {
if (task.name === 'countdowntask') {
Ext.TaskManager.stop(task);
}
});
}
},
'panel[name=maintreepanel]': {
treeloaded: function() {
this.treeloaded = true;
this.setupPanelsFromTreeContent();
}
},
'button[name=applypreviewchartsize]': {
click: function() {
this.destroyAllPreviewPanels();
this.setupPanelsFromTreeContent();
}
},
'button[name=reloadallpreviews]': {
click: this.triggerUpdateForAllPreviews
},
'treeview': {
drop: function() {
this.destroyAllPreviewPanels();
this.setupPanelsFromTreeContent();
}
},
'button[name=savepreviewchartsconfig]': {
click: function() {
var panel = Ext.ComponentQuery.query('panel[name=statuspanel]')[0],
location = 'previewchartsconfig',
objectToSave = {};
objectToSave.width = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue();
objectToSave.height = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue();
objectToSave.autoUpdate = Ext.ComponentQuery.query('checkbox[name=autoupdatecheckbox]')[0].getValue();
objectToSave.updateInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue();
// delegate to maincontroller
panel.fireEvent("saveconfig", objectToSave, location);
}
},
'checkbox[name=autoupdatecheckbox]': {
change: this.setupGlobalUpdateTask
}
});
},
/**
*
*/
setupGlobalUpdateTask: function() {
var me = this,
autoUpdate = Ext.ComponentQuery.query('checkbox[name=autoupdatecheckbox]')[0].getValue(),
updateInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue(),
txt = Ext.ComponentQuery.query('text[name=countdowntext]')[0];
if (autoUpdate === true && !Ext.isEmpty(updateInterval)) {
txt.setDisabled(false);
// stop all old tasks
Ext.each(Ext.TaskManager.tasks, function(task) {
if (task.name === 'countdowntask') {
Ext.TaskManager.stop(task);
}
});
// start the countdown
Ext.ComponentQuery.query('text[name=countdowntext]')[0].counter = updateInterval;
var countdownTask = Ext.TaskManager.start({
run: function() {
var txt = Ext.ComponentQuery.query('text[name=countdowntext]')[0];
if (txt.counter > 0) {
txt.setText('Next Update in ' + (txt.counter - 1) + 's');
txt.counter--;
} else if (txt.counter === 0 && !me.autoUpdateRunning){
me.autoUpdateRunning = true;
me.triggerUpdateForAllPreviews();
txt.setText('Updating...');
txt.counter--;
} else if (!me.autoUpdateRunning){
var currentInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue();
txt.setText('Next Update in ' + currentInterval + 's');
txt.counter = currentInterval;
}
},
name: 'countdowntask',
interval: 900
});
} else {
Ext.each(Ext.TaskManager.tasks, function(task) {
if (task.name === 'countdowntask') {
Ext.TaskManager.stop(task);
}
});
txt.setText('Update disabled');
txt.setDisabled(true);
}
},
/**
*
*/
createPreviewChartPanel: function(record) {
var me = this,
desiredWidth = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue(),
desiredHeight = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue(),
savename;
if (record.raw.ID) {
savename = record.raw.ID + '.svg';
} else {
savename = record.raw.data.ID + '.svg';
}
var previewchartcontainer = Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0],
previewpanel = Ext.create('Ext.panel.Panel', {
width: desiredWidth,
height: desiredHeight,
title: record.raw.text ? record.raw.text : 'No title found...',
record: record,
name: 'chartpreviewpanel',
items: [
{
xtype: 'toolbar',
ui: 'footer',
enableOverflow: true,
items: [
{
xtype: 'text',
name: 'lastupdatedtext',
text: "Last Updated: not yet"
},
'->',
{
text: 'Open Full Chart',
name: 'loadfullchart'
},
{
text: 'Reload',
name: 'updatepreviewchart'
}
]
},
{
xtype: 'image',
layout: 'fit',
// add date to path to avoid cached images from browser
src: 'app/imagecache/' + savename + '?_' + new Date(),
width: desiredWidth,
height: desiredHeight - 53
}
]
});
previewchartcontainer.add(previewpanel);
},
/**
*
*/
loadFullChart: function(btn) {
var rec = btn.up('panel[name=chartpreviewpanel]').record;
var centerpanels = Ext.ComponentQuery.query('panel[region=center]');
Ext.each(centerpanels, function(panel) {
panel.hide();
});
Ext.ComponentQuery.query('linechartpanel')[0].show();
Ext.ComponentQuery.query('treepanel')[0].expand();
btn.fireEvent('loadchart', null, rec, false);
},
/**
*
*/
destroyAllPreviewPanels: function() {
Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].removeAll();
},
/**
*
*/
setupPanelsFromTreeContent: function() {
var me = this;
if (me.statuspanelrendered && me.treeloaded) {
var root = Ext.ComponentQuery.query('treepanel')[0].getRootNode(),
statusfoldernode = root.findChild("text", "StatusRoom", true);
if (statusfoldernode.childNodes.length > 0) {
Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].update('');
} else {
Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].update(
'This panel gives you an overview of your Charts by displaying them as small windows here.<br>' +
'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you<br>' +
'can find in the tree on the left side.<br>' +
'Add as much charts as you want, configure their size and update options and save your<br>' +
'settings by clicking on "Save configuration".<br>' +
'The first time you add a new chart you need to reload it, before you can see it!');
}
Ext.each(statusfoldernode.childNodes, function(node) {
me.createPreviewChartPanel(node);
});
//initialize auto update
me.setupGlobalUpdateTask();
}
},
/**
*
*/
updatePreviewChart: function(btn, panel) {
var me = this;
if (panel && panel.down) {
btn = panel.down('button[name=updatepreviewchart]');
}
if (me.updateRunning === true) {
window.setTimeout(function() {
me.updatePreviewChart(btn);
}, 500);
return;
}
me.updateRunning = true;
// destroy all old charts
me.destroyAllCharts();
var imgcontainer = btn.up('panel').down('image');
imgcontainer.setLoading(true);
// get record from panel
var record = btn.up('panel').record;
// event will get caught in chartcontroller
btn.fireEvent('loadhiddenchart', null, record, true);
// now we wait till the chart is rendered
var task = Ext.TaskManager.start({
run: function() {
me.checkForRenderedChart(imgcontainer, task);
},
name: 'hiddenchart',
interval: 500
});
},
/**
*
*/
triggerUpdateForAllPreviews: function() {
var me = this,
allPanels = Ext.ComponentQuery.query('panel[name=chartpreviewpanel]');
Ext.each(allPanels, function(panel) {
me.updatePreviewChart(false, panel);
});
},
/**
* method destroys all rendered charts
*/
destroyAllCharts: function() {
var charts = Ext.ComponentQuery.query('chart');
Ext.each(charts, function(chart) {
chart.destroy();
});
},
/**
*
*/
checkForRenderedChart: function(imgcontainer, task){
var me = this,
desiredWidth = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue(),
desiredHeight = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue();
var chart = Ext.ComponentQuery.query('chart')[0];
if (chart && chart.surface && chart.surface.el && chart.surface.el.dom) {
chart.setHeight(desiredHeight - 53); // removing the panels title and toolbar from height
chart.setWidth(desiredWidth);
data = chart.surface.el.dom;
// we need to cleanup the "ext"-invisible items because they will get rendered
textArray = data.getElementsByTagName("text");
Ext.each(textArray, function(text) {
if (text.getAttribute("class") && text.getAttribute("class").indexOf("x-hide-visibility") >= 0 ) {
text.remove();
}
});
var serializer = new XMLSerializer(),
svgstring = serializer.serializeToString(data),
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
DOMURL = self.URL || self.webkitURL || self,
img = new Image(),
svg = new Blob([svgstring], {type: "image/svg+xml;charset=utf-8"}),
url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
};
img.src = url;
imgcontainer.setSrc(img.src);
imgcontainer.setLoading(false);
Ext.TaskManager.stop(task);
me.destroyAllCharts();
var rec = imgcontainer.up('panel').record;
imgcontainer.up('panel').down('text[name=lastupdatedtext]').setText(Ext.Date.format(new Date(), 'Y-m-d H:i:s'));
me.saveImageToDisk(svgstring, rec);
me.updateRunning = false;
// check if an autoupdate has completed
var sp = imgcontainer.up('panel[name=previewchartcontainer]');
if (me.autoUpdateRunning && imgcontainer.up('panel').title === sp.items.items[sp.items.items.length - 1].title) {
me.autoUpdateRunning = false;
}
}
},
/**
*
*/
saveImageToDisk: function(svgstring, rec) {
var savename;
if (rec.raw.ID) {
savename = rec.raw.ID + '.svg';
} else {
savename = rec.raw.data.ID + '.svg';
}
//fhem specific fixes ...
svgstring = svgstring.replace(/;/g, ";;");
svgstring = svgstring.replace(/\#/g, "\\x23");
var svgArr = [],
lastMax = 0;
// we split up the string in onehundredthousands-packages, so fhem will accept those posts...
while (svgstring.length > lastMax) {
svgArr.push(svgstring.slice(lastMax, lastMax + 100000));
lastMax = lastMax + 100000;
}
var i = 0,
cmd;
Ext.each(svgArr, function(part) {
if (i === 0) {
cmd = "{ `echo '" + part + "' > " + FHEM.appPath + "imagecache/" + savename + "`}";
} else {
cmd = "{ `echo -n '" + part + "' >> " + FHEM.appPath + "imagecache/" + savename + "`}";
}
i++;
Ext.Ajax.request({
method: 'POST',
disableCaching: false,
async: false,
url: '../../../fhem?',
params: {
cmd: cmd,
XHR: 1
},
success: function(response){
if (response.status === 200) {
// no feedback
} else if (response.statusText) {
Ext.Msg.alert("Error", "The Chart-Image could not be saved, error Message is:<br><br>" + response.statusText);
} else {
Ext.Msg.alert("Error", "The Chart-Image could not be saved!");
}
},
failure: function(response) {
if (response.statusText) {
Ext.Msg.alert("Error", "The Chart-Image could not be saved, error Message is:<br><br>" + response.statusText);
} else {
Ext.Msg.alert("Error", "The Chart-Image could not be saved!");
}
}
});
});
}
});

View File

@ -0,0 +1,123 @@
/**
* A Panel containing FHEM status information
*/
Ext.define('FHEM.view.StatusPanel', {
extend: 'Ext.panel.Panel',
alias : 'widget.statuspanel',
name: 'statuspanel',
/**
*
*/
title: 'FHEM Status',
/**
*
*/
region: 'center',
/**
*
*/
autoScroll: true,
/**
* init function
*/
initComponent: function() {
var me = this;
me.items = [
{
xtype: 'toolbar',
ui: 'footer',
enableOverflow: true,
items: [
{
xtype: 'numberfield',
fieldLabel: "Width",
labelWidth: 30,
width: 120,
padding: '0 20px 0 5px',
name: 'previewchartwidth',
value: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.width) ?
FHEM.userconfig.previewchartsconfig.width : 459
},
{
xtype: 'numberfield',
fieldLabel: "Height",
labelWidth: 30,
width: 120,
padding: '0 20px 0 5px',
name: 'previewchartheight',
value: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.height) ?
FHEM.userconfig.previewchartsconfig.height : 280
},
{
text: 'Apply Size',
name: 'applypreviewchartsize'
},
{
xtype: 'tbseparator'
},
{
xtype: 'checkbox',
fieldLabel: "Auto Update?",
labelWidth: 70,
name: 'autoupdatecheckbox',
checked: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.autoUpdate === false) ?
false : true
},
{
xtype: 'numberfield',
fieldLabel: "Update Interval",
labelWidth: 80,
name: 'updateinterval',
width: 150,
minValue: 60,
editable: false,
value: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.updateInterval) ?
FHEM.userconfig.previewchartsconfig.updateInterval : 120
},
{
xtype: 'text',
name: 'countdowntext',
width: 100,
counter: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.updateInterval) ?
FHEM.userconfig.previewchartsconfig.updateInterval - 2 : 118,
text: 'Updates disabled',
disabled: (FHEM.userconfig.previewchartsconfig &&
FHEM.userconfig.previewchartsconfig.autoUpdate === false) ?
true : false
},
{
text: 'Reload all now!',
name: 'reloadallpreviews',
cls:'x-btn-default-small'
},
{
text: 'Save configuration',
name: 'savepreviewchartsconfig'
}
]
},
{
xtype: 'panel',
name: 'previewchartcontainer',
layout: 'column',
html: 'This panel gives you an overview of your Charts by displaying them as small windows here.<br>' +
'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you<br>' +
'can find in the tree on the left side.<br>' +
'Add as much charts as you want, configure their size and update options and save your<br>' +
'settings by clicking on "Save configuration".<br>' +
'The first time you add a new chart you need to reload it, before you can see it!'
}
];
me.callParent(arguments);
}
});

View File

@ -9,6 +9,7 @@ Ext.define('FHEM.view.Viewport', {
requires: [
'FHEM.view.LineChartPanel',
'FHEM.view.TableDataGridPanel',
'FHEM.view.StatusPanel',
'FHEM.controller.ChartController',
'FHEM.store.SavedChartsStore',
'Ext.layout.container.Border',
@ -107,6 +108,13 @@ Ext.define('FHEM.view.Viewport', {
type: 'accordion'
},
items: [
{
title: 'FHEM Status',
name: 'fhemstatusaccordion',
expanded: true,
bodyPadding: '5 5 5 5',
html: 'See your current FHEM Status / Overview Information here.'
},
{
title: 'FHEM',
name: 'fhemaccordion',
@ -198,28 +206,31 @@ Ext.define('FHEM.view.Viewport', {
minHeight: 30
},
{
region: 'center',
title: 'Welcome',
layout: 'hbox',
bodyStyle: 'padding:5px 5px 0',
items: [
{
xtype: 'image',
src: '../../fhem/images/default/fhemicon.png',
height: 132,
width: 120
},
{
xtype: 'text',
name: 'statustextfield',
padding: '50 0 0 20',
width: 400,
height: 130,
html: '<br>Welcome to the new FHEM Frontend.<br>For Informations, Problems and discussion, visit the <a href="http://forum.fhem.de/index.php?t=msg&th=10439&start=0&rid=0">FHEM Forums</a>'
}
],
height: '100%'
xtype: 'statuspanel'
}
// {
// region: 'center',
// title: 'Welcome',
// layout: 'hbox',
// bodyStyle: 'padding:5px 5px 0',
// items: [
// {
// xtype: 'image',
// src: '../../fhem/images/default/fhemicon.png',
// height: 132,
// width: 120
// },
// {
// xtype: 'text',
// name: 'statustextfield',
// padding: '50 0 0 20',
// width: 400,
// height: 130,
// html: '<br>Welcome to the new FHEM Frontend.<br>For Informations, Problems and discussion, visit the <a href="http://forum.fhem.de/index.php?t=msg&th=10439&start=0&rid=0">FHEM Forums</a>'
// }
// ],
// height: '100%'
// }
]
});

View File

@ -28,5 +28,7 @@
</head>
<body>
<div id=hiddenchart width=1 height=1"></div>
<canvas id=canvas width=200 height=200></canvas>
</body>
</html>