From 2c8e4667079212b62bd504e6e9ab821d51e5b1c0 Mon Sep 17 00:00:00 2001 From: johannnes Date: Sun, 12 Jan 2014 14:02:15 +0000 Subject: [PATCH] chartingfrontend: some bugfixes, introducing multicharts / statusview git-svn-id: https://svn.fhem.de/fhem/trunk@4630 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/www/frontend/controls_frontend.txt | 13 +- fhem/www/frontend/www/frontend/app/app.js | 7 + .../app/controller/ChartController.js | 280 ++++++----- .../frontend/app/controller/MainController.js | 74 ++- .../app/controller/StatusController.js | 454 ++++++++++++++++++ .../www/frontend/app/view/StatusPanel.js | 123 +++++ .../www/frontend/app/view/Viewport.js | 53 +- fhem/www/frontend/www/frontend/index.html | 2 + 8 files changed, 854 insertions(+), 152 deletions(-) create mode 100644 fhem/www/frontend/www/frontend/app/controller/StatusController.js create mode 100644 fhem/www/frontend/www/frontend/app/view/StatusPanel.js diff --git a/fhem/www/frontend/controls_frontend.txt b/fhem/www/frontend/controls_frontend.txt index 5978c6dec..77c81978f 100644 --- a/fhem/www/frontend/controls_frontend.txt +++ b/fhem/www/frontend/controls_frontend.txt @@ -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 diff --git a/fhem/www/frontend/www/frontend/app/app.js b/fhem/www/frontend/www/frontend/app/app.js index e7324b71a..9d3b2384c 100644 --- a/fhem/www/frontend/www/frontend/app/app.js +++ b/fhem/www/frontend/www/frontend/app/app.js @@ -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; diff --git a/fhem/www/frontend/www/frontend/app/controller/ChartController.js b/fhem/www/frontend/www/frontend/app/controller/ChartController.js index c27b7dd1a..2896e0b01 100644 --- a/fhem/www/frontend/www/frontend/app/controller/ChartController.js +++ b/fhem/www/frontend/www/frontend/app/controller/ChartController.js @@ -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) + - '
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) + + '
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:
" + chartdata); diff --git a/fhem/www/frontend/www/frontend/app/controller/MainController.js b/fhem/www/frontend/www/frontend/app/controller/MainController.js index 7aa693801..f6b8d1628 100644 --- a/fhem/www/frontend/www/frontend/app/controller/MainController.js +++ b/fhem/www/frontend/www/frontend/app/controller/MainController.js @@ -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:

" + 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:

" + 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!"); + } + + } }); \ No newline at end of file diff --git a/fhem/www/frontend/www/frontend/app/controller/StatusController.js b/fhem/www/frontend/www/frontend/app/controller/StatusController.js new file mode 100644 index 000000000..ef338c1ac --- /dev/null +++ b/fhem/www/frontend/www/frontend/app/controller/StatusController.js @@ -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.
' + + 'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you
' + + 'can find in the tree on the left side.
' + + 'Add as much charts as you want, configure their size and update options and save your
' + + 'settings by clicking on "Save configuration".
' + + '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:

" + 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:

" + response.statusText); + } else { + Ext.Msg.alert("Error", "The Chart-Image could not be saved!"); + } + } + }); + }); + } +}); \ No newline at end of file diff --git a/fhem/www/frontend/www/frontend/app/view/StatusPanel.js b/fhem/www/frontend/www/frontend/app/view/StatusPanel.js new file mode 100644 index 000000000..ede456710 --- /dev/null +++ b/fhem/www/frontend/www/frontend/app/view/StatusPanel.js @@ -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.
' + + 'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you
' + + 'can find in the tree on the left side.
' + + 'Add as much charts as you want, configure their size and update options and save your
' + + 'settings by clicking on "Save configuration".
' + + 'The first time you add a new chart you need to reload it, before you can see it!' + } + ]; + me.callParent(arguments); + } +}); diff --git a/fhem/www/frontend/www/frontend/app/view/Viewport.js b/fhem/www/frontend/www/frontend/app/view/Viewport.js index 16b2b1ad8..911c6afed 100644 --- a/fhem/www/frontend/www/frontend/app/view/Viewport.js +++ b/fhem/www/frontend/www/frontend/app/view/Viewport.js @@ -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: '
Welcome to the new FHEM Frontend.
For Informations, Problems and discussion, visit the FHEM Forums' - } - ], - 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: '
Welcome to the new FHEM Frontend.
For Informations, Problems and discussion, visit the FHEM Forums' +// } +// ], +// height: '100%' +// } ] }); diff --git a/fhem/www/frontend/www/frontend/index.html b/fhem/www/frontend/www/frontend/index.html index cfb2aea6e..2e400eb93 100644 --- a/fhem/www/frontend/www/frontend/index.html +++ b/fhem/www/frontend/www/frontend/index.html @@ -28,5 +28,7 @@ +
+