diff --git a/js/component/card/floor_plan_editor.js b/js/component/card/floor_plan_editor.js index 53a5a36..26da4ba 100644 --- a/js/component/card/floor_plan_editor.js +++ b/js/component/card/floor_plan_editor.js @@ -666,11 +666,10 @@ beestat.component.card.floor_plan_editor.prototype.decorate_top_right_ = functio } } -/* menu.add_menu_item(new beestat.component.menu_item() + menu.add_menu_item(new beestat.component.menu_item() .set_text('Help') .set_icon('help_circle') .set_callback(function() { - // TODO - // window.open('https://doc.beestat.io/???'); - }));*/ + window.open('https://doc.beestat.io/86f6e4c44fc84c3cb4e8fb7b16d3d160'); + })); }; diff --git a/js/component/card/visualize_settings.js b/js/component/card/visualize_settings.js index 4adde6c..da45d79 100644 --- a/js/component/card/visualize_settings.js +++ b/js/component/card/visualize_settings.js @@ -145,10 +145,21 @@ beestat.component.card.visualize_settings.prototype.decorate_heat_map_type_ = fu min_max_container.style.marginTop = `${beestat.style.size.gutter}px`; parent.appendChild(min_max_container); + let type; + let inputmode; + if (beestat.setting('visualize.data_type') === 'temperature') { + type = 'decimal'; + inputmode = 'decimal'; + } else { + type = 'integer'; + inputmode = 'numeric'; + } + const min = new beestat.component.input.text() .set_maxlength('5') + .set_inputmode(inputmode) .set_requirements({ - 'type': 'decimal', + 'type': type, 'required': true }) .set_value( @@ -159,10 +170,14 @@ beestat.component.card.visualize_settings.prototype.decorate_heat_map_type_ = fu .set_width(50); min.addEventListener('change', function() { if (min.meets_requirements() === true) { + // Round to one decimal. + const value = Math.round(min.get_value() * 10) / 10; + min.set_value(value, false); + beestat.setting( 'visualize.heat_map_absolute.' + beestat.setting('visualize.data_type') + '.min', beestat.temperature({ - 'temperature': min.get_value(), + 'temperature': value, 'input_temperature_unit': beestat.setting('temperature_unit'), 'output_temperature_unit': '°F' }) @@ -171,25 +186,32 @@ beestat.component.card.visualize_settings.prototype.decorate_heat_map_type_ = fu min.set_value( beestat.temperature(beestat.setting( 'visualize.heat_map_absolute.' + beestat.setting('visualize.data_type') + '.min' - )) + )), + false ); } }); const max = new beestat.component.input.text() .set_maxlength('5') + .set_inputmode(inputmode) .set_requirements({ - 'type': 'decimal', + 'type': type, 'required': true }) .set_value( beestat.temperature(beestat.setting( 'visualize.heat_map_absolute.' + beestat.setting('visualize.data_type') + '.max' - )) + )), + false ) .set_width(50); max.addEventListener('change', function() { if (max.meets_requirements() === true) { + // Round to one decimal. + const value = Math.round(max.get_value() * 10) / 10; + max.set_value(value, false); + beestat.setting( 'visualize.heat_map_absolute.' + beestat.setting('visualize.data_type') + '.max', beestat.temperature({ @@ -202,7 +224,8 @@ beestat.component.card.visualize_settings.prototype.decorate_heat_map_type_ = fu max.set_value( beestat.temperature(beestat.setting( 'visualize.heat_map_absolute.' + beestat.setting('visualize.data_type') + '.max' - )) + )), + false ); } }); @@ -371,15 +394,14 @@ beestat.component.card.visualize_settings.prototype.get_title_ = function() { * * @param {rocket.Elements} parent */ -/*beestat.component.card.visualize_settings.prototype.decorate_top_right_ = function(parent) { +beestat.component.card.visualize_settings.prototype.decorate_top_right_ = function(parent) { var menu = (new beestat.component.menu()).render(parent); menu.add_menu_item(new beestat.component.menu_item() .set_text('Help') .set_icon('help_circle') .set_callback(function() { - // TODO - // window.open('https://doc.beestat.io/596040eadd014928830b4d1d54692761'); + window.open('https://doc.beestat.io/24f548ddd7fc464d846e113470f80c35'); })); }; -*/ + diff --git a/js/component/floor_plan.js b/js/component/floor_plan.js index 620e2d0..80af2ad 100644 --- a/js/component/floor_plan.js +++ b/js/component/floor_plan.js @@ -531,7 +531,7 @@ beestat.component.floor_plan.prototype.update_toolbar = function() { // Redo const redo_button = new beestat.component.tile() .set_icon('redo') - .set_title('redo [Ctrl+Y]') + .set_title('Redo [Ctrl+Y]') .set_background_color(beestat.style.color.bluegray.base); this.tile_group_.add_tile(redo_button); diff --git a/js/component/input/text.js b/js/component/input/text.js index ef0fc68..8b45845 100644 --- a/js/component/input/text.js +++ b/js/component/input/text.js @@ -36,15 +36,17 @@ beestat.extend(beestat.component.input.text, beestat.component.input); * @param {rocket.Elements} parent */ beestat.component.input.text.prototype.decorate_ = function(parent) { - this.input_.style.border = 'none'; - this.input_.style.background = beestat.style.color.bluegray.light; - this.input_.style.borderRadius = beestat.style.size.border_radius + 'px'; - this.input_.style.padding = (beestat.style.size.gutter / 2) + 'px'; - this.input_.style.color = '#fff'; - this.input_.style.outline = 'none'; - this.input_.style.transition = 'background 200ms ease'; - this.input_.style.marginBottom = beestat.style.size.gutter + 'px'; - this.input_.style.borderBottom = '2px solid ' + beestat.style.color.lightblue.base; + Object.assign(this.input_.style, { + 'border': 'none', + 'background': beestat.style.color.bluegray.light, + 'border-radius': `${beestat.style.size.border_radius}px`, + 'padding': `${beestat.style.size.gutter / 2}px`, + 'color': '#ffffff', + 'outline': 'none', + 'transition': 'background 200ms ease', + 'margin-bottom': `${beestat.style.size.gutter}px`, + 'border-bottom': `2px solid ${beestat.style.color.lightblue.base}` + }); // Set input width; interpret string widths literally (ex: 100%) if (this.width_ !== undefined) { @@ -62,13 +64,19 @@ beestat.component.input.text.prototype.decorate_ = function(parent) { parent[0].appendChild(label_container); } + if (this.inputmode_ !== undefined) { + this.input_.setAttribute('inputmode', this.inputmode_); + } + // If we want an icon just drop one on top of the input and add some padding. if (this.icon_ !== undefined) { const icon_container = document.createElement('div'); - icon_container.style.position = 'absolute'; - icon_container.style.top = (this.label_ !== undefined) ? '25px' : '7px'; - icon_container.style.left = '6px'; + Object.assign(icon_container.style, { + 'position': 'absolute', + 'top': (this.label_ !== undefined) ? '25px' : '7px', + 'left': '6px' + }); parent[0].appendChild(icon_container); @@ -175,6 +183,23 @@ beestat.component.input.text.prototype.set_width = function(width) { return this; }; +/** + * Set the inputmode of the input field. + * + * @param {string} inputmode + * + * @return {beestat.component.input.text} This. + */ +beestat.component.input.text.prototype.set_inputmode = function(inputmode) { + this.inputmode_ = inputmode; + + if (this.rendered_ === true) { + this.rerender(); + } + + return this; +}; + /** * Set the max length attribute of the input field. * diff --git a/js/component/scene.js b/js/component/scene.js index 245de48..e515fb9 100644 --- a/js/component/scene.js +++ b/js/component/scene.js @@ -421,13 +421,26 @@ beestat.component.scene.prototype.update_ = function() { ) { const value = self.data_.series[self.data_type_][room.sensor_id][time]; - const percentage = Math.min( - 1, - Math.max( - 0, - (value - self.heat_map_min_) / (self.heat_map_max_ - self.heat_map_min_) - ) - ); + /** + * Set the percentage between the min and max. Special case for if min + * and max are equal to avoid math issues. + */ + let percentage; + if ( + self.heat_map_min_ === self.heat_map_max_ && + value === self.heat_map_min_ + ) { + percentage = 0.5; + } else { + percentage = Math.min( + 1, + Math.max( + 0, + (value - self.heat_map_min_) / (self.heat_map_max_ - self.heat_map_min_) + ) + ); + } + color = beestat.style.rgb_to_hex( self.gradient_[Math.floor((self.gradient_.length - 1) * percentage)] );