From aca4c697203108a407d84dd9942864e6dc628997 Mon Sep 17 00:00:00 2001 From: Jon Ziebell Date: Sat, 15 Feb 2020 21:45:17 -0500 Subject: [PATCH] Fixed #241 - Thermostat Detail zoom gets out of sync when humidity is enabled --- .../card/runtime_thermostat_detail.js | 35 +++++++++++++++ js/component/chart.js | 45 ++++++++++++++++++- .../chart/runtime_sensor_detail_occupancy.js | 2 +- .../runtime_sensor_detail_temperature.js | 19 ++++---- .../runtime_thermostat_detail_equipment.js | 2 +- .../runtime_thermostat_detail_temperature.js | 9 ++++ js/lib/highcharts/highcharts.js | 2 +- 7 files changed, 100 insertions(+), 14 deletions(-) diff --git a/js/component/card/runtime_thermostat_detail.js b/js/component/card/runtime_thermostat_detail.js index eb1f0e0..365f2ea 100644 --- a/js/component/card/runtime_thermostat_detail.js +++ b/js/component/card/runtime_thermostat_detail.js @@ -74,6 +74,41 @@ beestat.component.card.runtime_thermostat_detail.prototype.decorate_contents_ = }); }); + /* + * Keep consistent right margins when a secondary y-axis is toggled on the + * temperature chart. + */ + this.charts_.temperature.addEventListener('legend_item_click', function() { + var need_equipment_margin_right = false; + this.get_chart().series.forEach(function(series) { + if ( + series.yAxis.opposite === true && + series.visible === true + ) { + need_equipment_margin_right = true; + } + }); + + var options; + if (need_equipment_margin_right === true) { + options = { + 'chart': { + 'marginRight': 45 + } + }; + self.charts_.equipment.update(options); + self.charts_.temperature.update(options); + } else { + options = { + 'chart': { + 'marginRight': 0 + } + }; + self.charts_.equipment.update(options); + self.charts_.temperature.update(options); + } + }); + var thermostat = beestat.cache.thermostat[this.thermostat_id_]; var required_begin; diff --git a/js/component/chart.js b/js/component/chart.js index 6c22225..5e92983 100644 --- a/js/component/chart.js +++ b/js/component/chart.js @@ -6,7 +6,7 @@ beestat.component.chart = function() { var self = this; this.addEventListener('render', function() { - self.chart_.reflow(); + self.reflow(); }); beestat.component.apply(this, arguments); @@ -102,6 +102,8 @@ beestat.component.chart.prototype.get_options_legend_enabled_ = function() { * @return {object} The plotOptions. */ beestat.component.chart.prototype.get_options_plotOptions_ = function() { + var self = this; + return { 'series': { 'animation': false, @@ -116,7 +118,15 @@ beestat.component.chart.prototype.get_options_plotOptions_ = function() { 'opacity': 1 } }, - 'connectNulls': this.get_options_plotOptions_series_connectNulls_() + 'connectNulls': this.get_options_plotOptions_series_connectNulls_(), + 'events': { + 'legendItemClick': function() { + // Delay the event dispatch so the series is actually toggled to the correct visibility. + setTimeout(function() { + self.dispatchEvent('legend_item_click'); + }, 0); + } + } }, 'column': { 'pointPadding': 0, @@ -173,6 +183,7 @@ beestat.component.chart.prototype.get_options_chart_ = function() { 'spacing': this.get_options_chart_spacing_(), // For consistent left spacing on charts with no y-axis values 'marginLeft': this.get_options_chart_marginLeft_(), + 'marginRight': this.get_options_chart_marginRight_(), 'zoomType': this.get_options_chart_zoomType_(), 'panning': true, 'panKey': 'ctrl', @@ -196,6 +207,15 @@ beestat.component.chart.prototype.get_options_chart_marginLeft_ = function() { return undefined; }; +/** + * Get the right margin for the chart. + * + * @return {number} The right margin for the chart. + */ +beestat.component.chart.prototype.get_options_chart_marginRight_ = function() { + return undefined; +}; + /** * Get the spacing for the chart. * @@ -630,3 +650,24 @@ beestat.component.chart.prototype.sync_crosshair = function(source_chart) { ); }); }; + +/** + * Reflow the chart; useful if the GUI changes and the chart needs resized. + * + * @link https://api.highcharts.com/class-reference/Highcharts.Chart#reflow + */ +beestat.component.chart.prototype.reflow = function() { + this.chart_.reflow(); +}; + +/** + * A generic function to update any element of the chart. Elements can be + * enabled and disabled, moved, re-styled, re-formatted etc. + * + * @param {object} options The options to change. + * + * @link https://api.highcharts.com/class-reference/Highcharts.Chart#update + */ +beestat.component.chart.prototype.update = function(options) { + this.chart_.update(options); +}; diff --git a/js/component/chart/runtime_sensor_detail_occupancy.js b/js/component/chart/runtime_sensor_detail_occupancy.js index 69d786d..fa417d9 100644 --- a/js/component/chart/runtime_sensor_detail_occupancy.js +++ b/js/component/chart/runtime_sensor_detail_occupancy.js @@ -184,5 +184,5 @@ beestat.component.chart.runtime_sensor_detail_occupancy.prototype.get_options_le * @return {number} The left margin for the chart. */ beestat.component.chart.runtime_sensor_detail_occupancy.prototype.get_options_chart_marginLeft_ = function() { - return 40; + return 45; }; diff --git a/js/component/chart/runtime_sensor_detail_temperature.js b/js/component/chart/runtime_sensor_detail_temperature.js index bed3417..a586cef 100644 --- a/js/component/chart/runtime_sensor_detail_temperature.js +++ b/js/component/chart/runtime_sensor_detail_temperature.js @@ -95,15 +95,7 @@ beestat.component.chart.runtime_sensor_detail_temperature.prototype.get_options_ 'color': colors[i], 'yAxis': 0, 'type': 'spline', - 'lineWidth': 1, - 'events': { - 'legendItemClick': function() { - // Delay the event dispatch so the series is actually toggled to the correct visibility. - setTimeout(function() { - self.dispatchEvent('legend_item_click'); - }, 0); - } - } + 'lineWidth': 1 }); }); @@ -267,3 +259,12 @@ beestat.component.chart.runtime_sensor_detail_temperature.prototype.get_options_ beestat.component.chart.runtime_sensor_detail_temperature.prototype.get_options_chart_height_ = function() { return 300; }; + +/** + * Get the left margin for the chart. + * + * @return {number} The left margin for the chart. + */ +beestat.component.chart.runtime_sensor_detail_temperature.prototype.get_options_chart_marginLeft_ = function() { + return 45; +}; diff --git a/js/component/chart/runtime_thermostat_detail_equipment.js b/js/component/chart/runtime_thermostat_detail_equipment.js index 13d0cff..62bf981 100644 --- a/js/component/chart/runtime_thermostat_detail_equipment.js +++ b/js/component/chart/runtime_thermostat_detail_equipment.js @@ -127,5 +127,5 @@ beestat.component.chart.runtime_thermostat_detail_equipment.prototype.get_option * @return {number} The left margin for the chart. */ beestat.component.chart.runtime_thermostat_detail_equipment.prototype.get_options_chart_marginLeft_ = function() { - return 40; + return 45; }; diff --git a/js/component/chart/runtime_thermostat_detail_temperature.js b/js/component/chart/runtime_thermostat_detail_temperature.js index 2236ea7..2306e55 100644 --- a/js/component/chart/runtime_thermostat_detail_temperature.js +++ b/js/component/chart/runtime_thermostat_detail_temperature.js @@ -409,3 +409,12 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti ); }; }; + +/** + * Get the left margin for the chart. + * + * @return {number} The left margin for the chart. + */ +beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_chart_marginLeft_ = function() { + return 45; +}; diff --git a/js/lib/highcharts/highcharts.js b/js/lib/highcharts/highcharts.js index 6a40b2e..881e9fc 100755 --- a/js/lib/highcharts/highcharts.js +++ b/js/lib/highcharts/highcharts.js @@ -359,7 +359,7 @@ function(b,c){var d={};n(b,function(f,g){if(e(b[g],!0)&&!b.nodeType&&c[g]){var m isX:c});c=new C(this,a);g[d]=E(g[d]||{});g[d].push(a);l(e,!0)&&this.redraw(f);return c},showLoading:function(a){var b=this,c=b.options,e=b.loadingDiv,f=c.loading,m=function(){e&&p(e,{left:b.plotLeft+"px",top:b.plotTop+"px",width:b.plotWidth+"px",height:b.plotHeight+"px"})};e||(b.loadingDiv=e=g("div",{className:"highcharts-loading highcharts-loading-hidden"},null,b.container),b.loadingSpan=g("span",{className:"highcharts-loading-inner"},null,e),B(b,"redraw",m));e.className="highcharts-loading";b.loadingSpan.innerHTML= a||c.lang.loading;b.styledMode||(p(e,r(f.style,{zIndex:10})),p(b.loadingSpan,f.labelStyle),b.loadingShown||(p(e,{opacity:0,display:""}),F(e,{opacity:f.style.opacity||.5},{duration:f.showDuration||0})));b.loadingShown=!0;m()},hideLoading:function(){var a=this.options,b=this.loadingDiv;b&&(b.className="highcharts-loading highcharts-loading-hidden",this.styledMode||F(b,{opacity:0},{duration:a.loading.hideDuration||100,complete:function(){p(b,{display:"none"})}}));this.loadingShown=!1},propsRequireDirtyBox:"backgroundColor borderColor borderWidth borderRadius plotBackgroundColor plotBackgroundImage plotBorderColor plotBorderWidth plotShadow shadow".split(" "), propsRequireReflow:"margin marginTop marginRight marginBottom marginLeft spacing spacingTop spacingRight spacingBottom spacingLeft".split(" "),propsRequireUpdateSeries:"chart.inverted chart.polar chart.ignoreHiddenSeries chart.type colors plotOptions time tooltip".split(" "),collectionsWithUpdate:"xAxis yAxis zAxis series colorAxis pane".split(" "),update:function(e,d,g,m){var k=this,q={credits:"addCredits",title:"setTitle",subtitle:"setSubtitle"},h,u,w,r=[];f(k,"update",{options:e});e.isResponsiveOptions|| -k.setResponsive(!1,!0);e=a.cleanRecursively(e,k.options);b(!0,k.userOptions,e);if(h=e.chart){b(!0,k.options.chart,h);"className"in h&&k.setClassName(h.className);"reflow"in h&&k.setReflow(h.reflow);if("inverted"in h||"polar"in h||"type"in h){k.propFromSeries();var p=!0}"alignTicks"in h&&(p=!0);n(h,function(a,b){-1!==k.propsRequireUpdateSeries.indexOf("chart."+b)&&(u=!0);-1!==k.propsRequireDirtyBox.indexOf(b)&&(k.isDirtyBox=!0);-1!==k.propsRequireReflow.indexOf(b)&&(w=!0)});!k.styledMode&&"style"in +k.setResponsive&&k.setResponsive(!1,!0);e=a.cleanRecursively(e,k.options);b(!0,k.userOptions,e);if(h=e.chart){b(!0,k.options.chart,h);"className"in h&&k.setClassName(h.className);"reflow"in h&&k.setReflow(h.reflow);if("inverted"in h||"polar"in h||"type"in h){k.propFromSeries();var p=!0}"alignTicks"in h&&(p=!0);n(h,function(a,b){-1!==k.propsRequireUpdateSeries.indexOf("chart."+b)&&(u=!0);-1!==k.propsRequireDirtyBox.indexOf(b)&&(k.isDirtyBox=!0);-1!==k.propsRequireReflow.indexOf(b)&&(w=!0)});!k.styledMode&&"style"in h&&k.renderer.setStyle(h.style)}!k.styledMode&&e.colors&&(this.options.colors=e.colors);e.plotOptions&&b(!0,this.options.plotOptions,e.plotOptions);e.time&&this.time===a.time&&(this.time=new a.Time(e.time));n(e,function(a,b){if(k[b]&&"function"===typeof k[b].update)k[b].update(a,!1);else if("function"===typeof k[q[b]])k[q[b]](a);"chart"!==b&&-1!==k.propsRequireUpdateSeries.indexOf(b)&&(u=!0)});this.collectionsWithUpdate.forEach(function(a){if(e[a]){if("series"===a){var b=[];k[a].forEach(function(a, c){a.options.isInternal||b.push(l(a.options.index,c))})}E(e[a]).forEach(function(c,d){var e=v(c.id)&&k.get(c.id)||k[a][b?b[d]:d];e&&e.coll===a&&(e.update(c,!1),g&&(e.touched=!0));!e&&g&&k.collectionsWithInit[a]&&(k.collectionsWithInit[a][0].apply(k,[c].concat(k.collectionsWithInit[a][1]||[]).concat([!1])).touched=!0)});g&&k[a].forEach(function(a){a.touched||a.options.isInternal?delete a.touched:r.push(a)})}});r.forEach(function(a){a.remove&&a.remove(!1)});p&&k.axes.forEach(function(a){a.update({}, !1)});u&&k.series.forEach(function(a){a.update({},!1)});e.loading&&b(!0,k.options.loading,e.loading);p=h&&h.width;h=h&&h.height;a.isString(h)&&(h=a.relativeLength(h,p||k.chartWidth));w||c(p)&&p!==k.chartWidth||c(h)&&h!==k.chartHeight?k.setSize(p,h,m):l(d,!0)&&k.redraw(m);f(k,"afterUpdate",{options:e,redraw:d,animation:m})},setSubtitle:function(a){this.setTitle(void 0,a)}});k.prototype.collectionsWithInit={xAxis:[k.prototype.addAxis,[!0]],yAxis:[k.prototype.addAxis,[!1]],series:[k.prototype.addSeries]};