diff --git a/js/beestat/runtime_sensor.js b/js/beestat/runtime_sensor.js index bb5c981..59bab90 100644 --- a/js/beestat/runtime_sensor.js +++ b/js/beestat/runtime_sensor.js @@ -143,6 +143,7 @@ beestat.runtime_sensor.get_data = function(thermostat_id, range) { data.series['temperature_' + runtime_sensor.sensor_id].push(temperature_moving); y_min_max(temperature_moving); data.metadata.series['temperature_' + runtime_sensor.sensor_id].active = true; + data.metadata.series['temperature_' + runtime_sensor.sensor_id].data[current_m.valueOf()] = temperature_moving; if (runtime_sensor.occupancy === true) { let swimlane_properties = diff --git a/js/beestat/runtime_thermostat.js b/js/beestat/runtime_thermostat.js index 3070fe6..abd5b71 100644 --- a/js/beestat/runtime_thermostat.js +++ b/js/beestat/runtime_thermostat.js @@ -226,6 +226,9 @@ beestat.runtime_thermostat.get_data = function(thermostat_id, range) { runtime_thermostat.setpoint_heat ); data.series.setpoint_heat.push(setpoint_heat); + data.metadata.series.setpoint_heat.data[current_m.valueOf()] = setpoint_heat; + y_min_max(outdoor_temperature_moving); + y_min_max(setpoint_heat); data.metadata.series.setpoint_heat.active = true; @@ -242,6 +245,7 @@ beestat.runtime_thermostat.get_data = function(thermostat_id, range) { runtime_thermostat.setpoint_cool ); data.series.setpoint_cool.push(setpoint_cool); + data.metadata.series.setpoint_heat.data[current_m.valueOf()] = setpoint_cool; y_min_max(setpoint_cool); data.metadata.series.setpoint_cool.active = true; diff --git a/js/component/card/runtime_sensor_detail.js b/js/component/card/runtime_sensor_detail.js index 431599e..9831136 100644 --- a/js/component/card/runtime_sensor_detail.js +++ b/js/component/card/runtime_sensor_detail.js @@ -73,10 +73,8 @@ beestat.component.card.runtime_sensor_detail.prototype.decorate_contents_ = func // Sync extremes and crosshair. Object.values(this.charts_).forEach(function(source_chart) { Object.values(self.charts_).forEach(function(target_chart) { - if (source_chart !== target_chart) { - target_chart.sync_extremes(source_chart); - target_chart.sync_crosshair(source_chart); - } + target_chart.sync_extremes(source_chart); + target_chart.sync_crosshair(source_chart); }); }); @@ -154,25 +152,6 @@ beestat.component.card.runtime_sensor_detail.prototype.decorate_contents_ = func operator = 'between'; } -/* new beestat.api() - .add_call( - 'runtime_thermostat', - 'read', - { - 'attributes': { - 'thermostat_id': thermostat.thermostat_id, - 'timestamp': { - 'value': value, - 'operator': operator - } - } - } - ) - .set_callback(function(response) { - beestat.cache.set('runtime_thermostat', response); - }) - .send();*/ - var api_call = new beestat.api(); beestat.sensor.get_sorted().forEach(function(sensor) { if (sensor.thermostat_id === self.thermostat_id_) { diff --git a/js/component/card/runtime_thermostat_detail.js b/js/component/card/runtime_thermostat_detail.js index 365f2ea..178399e 100644 --- a/js/component/card/runtime_thermostat_detail.js +++ b/js/component/card/runtime_thermostat_detail.js @@ -67,10 +67,8 @@ beestat.component.card.runtime_thermostat_detail.prototype.decorate_contents_ = // Sync extremes and crosshair. Object.values(this.charts_).forEach(function(source_chart) { Object.values(self.charts_).forEach(function(target_chart) { - if (source_chart !== target_chart) { - target_chart.sync_extremes(source_chart); - target_chart.sync_crosshair(source_chart); - } + target_chart.sync_extremes(source_chart); + target_chart.sync_crosshair(source_chart); }); }); diff --git a/js/component/chart.js b/js/component/chart.js index 5e92983..4dfacd8 100644 --- a/js/component/chart.js +++ b/js/component/chart.js @@ -239,20 +239,6 @@ beestat.component.chart.prototype.get_options_chart_events_ = function() { return null; }; -/** - * Get the spacing for the chart. - * - * @return {number} The spacing for the chart. - */ -// beestat.component.chart.prototype.get_options_chart_spacing_ = function() { -// return [ -// beestat.style.size.gutter, -// 0, -// 0, -// 0 -// ]; -// }; - /** * Get the height of the chart. * @@ -401,17 +387,38 @@ beestat.component.chart.prototype.get_options_xAxis_ = function() { }, 'formatter': this.get_options_xAxis_labels_formatter_() }, + 'crosshair': { + 'width': this.get_options_xAxis_crosshair_width_(), + 'zIndex': 100, + 'color': 'rgba(255, 255, 255, 0.2)', + 'snap': this.get_options_xAxis_crosshair_snap_() + }, 'events': { 'afterSetExtremes': function() { - // Make sure the extremes are set prior to firing the event. - // setTimeout(function() { - self.dispatchEvent('after_set_extremes'); - // }, 0) + self.dispatchEvent('after_set_extremes'); } } }; }; +/** + * Get the crosshair width. + * + * @return {object} The crosshair width. + */ +beestat.component.chart.prototype.get_options_xAxis_crosshair_width_ = function() { + return 2; +}; + +/** + * Get the crosshair snap. + * + * @return {object} The crosshair snap. + */ +beestat.component.chart.prototype.get_options_xAxis_crosshair_snap_ = function() { + return false; +}; + /** * Get the xAxis label formatter options. Needs to be overridden. * @@ -452,13 +459,7 @@ beestat.component.chart.prototype.get_options_tooltip_ = function() { 'shadow': false, 'backgroundColor': null, 'followPointer': true, - 'crosshairs': { - 'width': 1, - 'zIndex': 100, - 'color': beestat.style.color.gray.light, - 'dashStyle': 'shortDot', - 'snap': false - }, + 'hideDelay': 1, 'positioner': this.get_options_tooltip_positioner_(), 'formatter': this.get_options_tooltip_formatter_() }; @@ -639,16 +640,22 @@ beestat.component.chart.prototype.sync_crosshair = function(source_chart) { event_type, function(e) { var point = self.get_chart().series[0].searchPoint( - self.get_chart().pointer.normalize(e), + source_chart.get_chart().pointer.normalize(e), true ); if (point !== undefined) { - point.onMouseOver(); - point.series.chart.xAxis[0].drawCrosshair(event, this); + self.get_chart().tooltip.refresh([point]); + self.get_chart().xAxis[0].drawCrosshair(e); } } ); }); + + // When I leave the source chart, hide the crosshair and tooltip in this chart. + source_chart.get_chart().container.addEventListener('mouseout', function() { + self.get_chart().xAxis[0].hideCrosshair(); + self.get_chart().tooltip.hide(1); + }); }; /** diff --git a/js/component/chart/runtime_sensor_detail_occupancy.js b/js/component/chart/runtime_sensor_detail_occupancy.js index fa417d9..8d86d48 100644 --- a/js/component/chart/runtime_sensor_detail_occupancy.js +++ b/js/component/chart/runtime_sensor_detail_occupancy.js @@ -96,10 +96,6 @@ beestat.component.chart.runtime_sensor_detail_occupancy.prototype.get_options_yA // Keeps the chart from ending on a multiple of whatever the tick interval gets set to. 'endOnTick': false, - // 'min': 0, - // 'minRange': 100, - // 'ceiling': 100 - 'reversed': true, 'gridLineWidth': 0, 'title': {'text': null}, @@ -148,11 +144,6 @@ beestat.component.chart.runtime_sensor_detail_occupancy.get_swimlane_properties // Make the lines slightly less tall to create space between them. line_width -= spacing; - // Center within the swimlane area. - // var occupied_space = (line_width * count) + (spacing * count); - // var empty_space = height - occupied_space; - // y += (empty_space / 2); - return { 'line_width': line_width, 'y': y diff --git a/js/component/chart/runtime_sensor_detail_temperature.js b/js/component/chart/runtime_sensor_detail_temperature.js index e88f003..382b038 100644 --- a/js/component/chart/runtime_sensor_detail_temperature.js +++ b/js/component/chart/runtime_sensor_detail_temperature.js @@ -161,64 +161,76 @@ beestat.component.chart.runtime_sensor_detail_temperature.prototype.get_options_ var self = this; return function() { + var points = []; + var x = this.x; + var sections = []; var group = []; - // Get all the point values and index them by series_code for reference. - var values = {}; - this.points.forEach(function(point) { - values[point.series.name] = point.y; - - var occupancy_key = point.series.name.replace('temperature', 'occupancy'); - if (self.data_.metadata.series[occupancy_key] !== undefined) { - values[occupancy_key] = - self.data_.metadata.series[occupancy_key].data[point.x.valueOf()]; + var visible_series = []; + self.get_chart().series.forEach(function(series) { + if (series.visible === true) { + visible_series.push(series.name); } }); - /** - * Get a couple of other properties and index them by series_code for - * reference. This dives up to the chart itself because the tooltip shows - * all series unless explicitly disabled and those aren't always in the - * points array. - */ - var colors = {}; - var visible = {}; - self.chart_.series.forEach(function(series) { - colors[series.name] = series.color; - visible[series.name] = series.visible; - }); - - for (var series_code in self.data_.series) { - var label; - var value; - var color; - - if (visible[series_code] === true) { - label = self.data_.metadata.series[series_code].name; - color = colors[series_code]; - if (values[series_code] === undefined) { - value = '-'; - } else { - value = beestat.temperature({ - 'temperature': values[series_code], - 'convert': false, - 'units': true - }); - } - - var occupancy_key = series_code.replace('temperature', 'occupancy'); - if (values[occupancy_key] !== undefined && values[occupancy_key] !== null) { - value += ' ●'; - } - - group.push({ - 'label': label, - 'value': value, - 'color': color + // Add points which can be toggled. + [ + 'indoor_temperature', + 'outdoor_temperature' + ].forEach(function(series_code) { + if ( + self.data_.metadata.series[series_code].data[x.valueOf()] !== undefined && + visible_series.includes(series_code) === true + ) { + points.push({ + 'series_code': series_code, + 'value': self.data_.metadata.series[series_code].data[x.valueOf()], + 'color': beestat.series[series_code].color }); } - } + }); + + var occupancy = {}; + self.get_chart().series.forEach(function(series) { + if (series.name.substring(0, 12) === 'temperature_') { + points.push({ + 'series_code': series.name, + 'value': self.data_.metadata.series[series.name].data[x.valueOf()], + 'color': series.color + }); + var occupancy_key = series.name.replace('temperature', 'occupancy'); + occupancy[occupancy_key] = + (self.data_.metadata.series[occupancy_key].data[x.valueOf()] !== undefined) + } + }); + + points.forEach(function(point) { + var label; + var value; + + label = self.data_.metadata.series[point.series_code].name; + if (point.value === undefined) { + value = '-'; + } else { + value = beestat.temperature({ + 'temperature': point.value, + 'convert': false, + 'units': true + }); + } + + var occupancy_key = point.series_code.replace('temperature', 'occupancy'); + if (occupancy[occupancy_key] === true) { + value += ' ●'; + } + + group.push({ + 'label': label, + 'value': value, + 'color': point.color + }); + }); if (group.length === 0) { group.push({ diff --git a/js/component/chart/runtime_thermostat_detail_temperature.js b/js/component/chart/runtime_thermostat_detail_temperature.js index 2306e55..0f68482 100644 --- a/js/component/chart/runtime_thermostat_detail_temperature.js +++ b/js/component/chart/runtime_thermostat_detail_temperature.js @@ -182,7 +182,8 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti var self = this; return function() { - var self2 = this; + var points = []; + var x = this.x; var sections = []; var groups = { @@ -191,7 +192,34 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti 'equipment': [] }; - // Add a bunch of fake points so they appear in the tooltip. + var visible_series = []; + self.get_chart().series.forEach(function(series) { + if (series.visible === true) { + visible_series.push(series.name); + } + }); + + // Add points which can be toggled. + [ + 'indoor_temperature', + 'outdoor_temperature', + 'setpoint_heat', + 'setpoint_cool', + 'indoor_humidity', + 'outdoor_humidity' + ].forEach(function(series_code) { + if ( + self.data_.metadata.series[series_code].data[x.valueOf()] !== undefined && + visible_series.includes(series_code) === true + ) { + points.push({ + 'series_code': series_code, + 'value': self.data_.metadata.series[series_code].data[x.valueOf()] + }); + } + }); + + // Add points which are, more or less, always present. [ 'compressor_heat_1', 'compressor_heat_2', @@ -216,23 +244,14 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti 'calendar_event_other', 'calendar_event_custom' ].forEach(function(series_code) { - if (self.data_.metadata.series[series_code].data[self2.x.valueOf()] !== undefined) { - self2.points.push({ - 'series': { - 'name': series_code, - 'color': beestat.series[series_code].color - }, - 'x': self2.x, - 'y': self.data_.metadata.series[series_code].data[self2.x.valueOf()] + if (self.data_.metadata.series[series_code].data[x.valueOf()] !== undefined) { + points.push({ + 'series_code': series_code, + 'value': self.data_.metadata.series[series_code].data[x.valueOf()] }); } }); - var values = {}; - this.points.forEach(function(point) { - values[point.series.name] = point.y; - }); - // HVAC Mode var system_mode; var system_mode_color; @@ -268,72 +287,56 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti }); } - this.points.forEach(function(point) { + points.forEach(function(point) { var label; var value; var color; var group; if ( - point.series.name.includes('temperature') === true || - point.series.name.includes('setpoint') === true + point.series_code.includes('temperature') === true || + point.series_code.includes('setpoint') === true ) { group = 'data'; - label = beestat.series[point.series.name].name; - color = point.series.color; - - if ( - point.series.name === 'indoor_temperature' || - point.series.name === 'outdoor_temperature' - ) { - value = self.data_.metadata.series[point.series.name].data[point.x.valueOf()]; - } else { - value = values[point.series.name]; - } + label = beestat.series[point.series_code].name; + color = beestat.series[point.series_code].color; + value = self.data_.metadata.series[point.series_code].data[x.valueOf()]; value = beestat.temperature({ 'temperature': value, 'convert': false, 'units': true }); - } else if (point.series.name.includes('humidity') === true) { + } else if (point.series_code.includes('humidity') === true) { group = 'data'; - label = beestat.series[point.series.name].name; - color = point.series.color; - - if ( - point.series.name === 'indoor_humidity' || - point.series.name === 'outdoor_humidity' - ) { - value = self.data_.metadata.series[point.series.name].data[point.x.valueOf()]; - } else { - value = values[point.series.name]; - } + label = beestat.series[point.series_code].name; + color = beestat.series[point.series_code].color; + value = self.data_.metadata.series[point.series_code].data[x.valueOf()]; value = Math.round(value) + '%'; } else if ( - point.series.name === 'fan' || - point.series.name === 'compressor_heat_1' || - point.series.name === 'auxiliary_heat_1' || - point.series.name === 'compressor_cool_1' || - point.series.name === 'dehumidifier' || - point.series.name === 'economizer' || - point.series.name === 'humidifier' || - point.series.name === 'ventilator' + point.series_code === 'fan' || + point.series_code === 'compressor_heat_1' || + point.series_code === 'auxiliary_heat_1' || + point.series_code === 'compressor_cool_1' || + point.series_code === 'dehumidifier' || + point.series_code === 'economizer' || + point.series_code === 'humidifier' || + point.series_code === 'ventilator' ) { group = 'equipment'; - label = beestat.series[point.series.name].name; - color = point.series.color; + label = beestat.series[point.series_code].name; + color = beestat.series[point.series_code].color; value = beestat.time( - self.data_.metadata.series[point.series.name].durations[point.x.valueOf()] + self.data_.metadata.series[point.series_code].durations[x.valueOf()] ); } else if ( - point.series.name.includes('calendar_event') + point.series_code.includes('calendar_event') ) { group = 'mode'; label = 'Comfort Profile'; - color = point.series.color; - value = self.data_.metadata.series.calendar_event_name[point.x.valueOf()]; + color = beestat.series[point.series_code].color; + value = self.data_.metadata.series.calendar_event_name[x.valueOf()]; } else { return; } @@ -346,39 +349,39 @@ beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_opti // Show stage 2 duration on stage 1, if applicable. if ( - point.series.name === 'compressor_heat_1' && - self.data_.metadata.series.compressor_heat_2.durations[point.x.valueOf()].seconds > 0 + point.series_code === 'compressor_heat_1' && + self.data_.metadata.series.compressor_heat_2.durations[x.valueOf()].seconds > 0 ) { groups.equipment.push({ 'label': beestat.series.compressor_heat_2.name, 'value': beestat.time( - self.data_.metadata.series.compressor_heat_2.durations[point.x.valueOf()] + self.data_.metadata.series.compressor_heat_2.durations[x.valueOf()] ), 'color': beestat.series.compressor_heat_2.color }); } if ( - point.series.name === 'auxiliary_heat_1' && - self.data_.metadata.series.auxiliary_heat_2.durations[point.x.valueOf()].seconds > 0 + point.series_code === 'auxiliary_heat_1' && + self.data_.metadata.series.auxiliary_heat_2.durations[x.valueOf()].seconds > 0 ) { groups.equipment.push({ 'label': beestat.series.auxiliary_heat_2.name, 'value': beestat.time( - self.data_.metadata.series.auxiliary_heat_2.durations[point.x.valueOf()] + self.data_.metadata.series.auxiliary_heat_2.durations[x.valueOf()] ), 'color': beestat.series.auxiliary_heat_2.color }); } if ( - point.series.name === 'compressor_cool_1' && - self.data_.metadata.series.compressor_cool_2.durations[point.x.valueOf()].seconds > 0 + point.series_code === 'compressor_cool_1' && + self.data_.metadata.series.compressor_cool_2.durations[x.valueOf()].seconds > 0 ) { groups.equipment.push({ 'label': beestat.series.compressor_cool_2.name, 'value': beestat.time( - self.data_.metadata.series.compressor_cool_2.durations[point.x.valueOf()] + self.data_.metadata.series.compressor_cool_2.durations[x.valueOf()] ), 'color': beestat.series.compressor_cool_2.color }); diff --git a/js/component/chart/runtime_thermostat_summary.js b/js/component/chart/runtime_thermostat_summary.js index 52436d5..694ac09 100755 --- a/js/component/chart/runtime_thermostat_summary.js +++ b/js/component/chart/runtime_thermostat_summary.js @@ -305,3 +305,21 @@ beestat.component.chart.runtime_thermostat_summary.prototype.get_options_tooltip ); }; }; + +/** + * Remove the crosshair width so it is one series wide. + * + * @return {object} The crosshair width. + */ +beestat.component.chart.runtime_thermostat_summary.prototype.get_options_xAxis_crosshair_width_ = function() { + return undefined; +}; + +/** + * Get the crosshair snap. + * + * @return {object} The crosshair snap. + */ +beestat.component.chart.runtime_thermostat_summary.prototype.get_options_xAxis_crosshair_snap_ = function() { + return true; +};