From 0df4aa6117195191d38746c67d318a32200f5591 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Wed, 21 Mar 2018 17:35:16 -0400 Subject: [PATCH] Use new light HS API for the color picker (#982) --- src/components/ha-color-picker.html | 166 ++++-------------- .../more-info/controls/more-info-light.html | 24 ++- 2 files changed, 49 insertions(+), 141 deletions(-) diff --git a/src/components/ha-color-picker.html b/src/components/ha-color-picker.html index 1f7346b6e7..4154b4a91b 100644 --- a/src/components/ha-color-picker.html +++ b/src/components/ha-color-picker.html @@ -82,23 +82,14 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { static get properties() { return { - hsvColor: { - type: Object, - }, - - rgbColor: { + hsColor: { type: Object, }, // use these properties to update the state via attributes - desiredHsvColor: { + desiredHsColor: { type: Object, - observer: 'applyHsvColor' - }, - - desiredRgbColor: { - type: Object, - observer: 'applyRgbColor' + observer: 'applyHsColor' }, // width, height and radius apply to the coordinates of @@ -157,7 +148,6 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { ready() { super.ready(); - this.applyRgbColor = this.applyRgbColor.bind(this); this.setupLayers(); this.drawColorWheel(); this.drawMarker(); @@ -250,18 +240,18 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { // Process user input to color processUserSelect(ev) { var canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY); - var hsv = this.getColor(canvasXY.x, canvasXY.y); - this.onColorSelect(hsv); + var hs = this.getColor(canvasXY.x, canvasXY.y); + this.onColorSelect(hs); } // apply color to marker position and canvas - onColorSelect(hsv) { - this.setMarkerOnColor(hsv); // marker always follows mounse 'raw' hsv value (= mouse position) + onColorSelect(hs) { + this.setMarkerOnColor(hs); // marker always follows mounse 'raw' hs value (= mouse position) if (!this.ignoreSegments) { // apply segments if needed - hsv = this.applySegmentFilter(hsv); + hs = this.applySegmentFilter(hs); } // always apply the new color to the interface / canvas - this.applyColorToCanvas(hsv); + this.applyColorToCanvas(hs); // throttling is applied to updating the exposed colors (properties) // and firing of events if (this.colorSelectIsThrottled) { @@ -269,11 +259,11 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { // eventually after throttle limit has passed clearTimeout(this.ensureFinalSelect); this.ensureFinalSelect = setTimeout(() => { - this.fireColorSelected(hsv); // do it for the final time + this.fireColorSelected(hs); // do it for the final time }, this.throttle); return; } - this.fireColorSelected(hsv); // do it + this.fireColorSelected(hs); // do it this.colorSelectIsThrottled = true; setTimeout(() => { this.colorSelectIsThrottled = false; @@ -281,10 +271,9 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { } // set color values and fire colorselected event - fireColorSelected(hsv) { - this.hsvColor = hsv; - this.rgbColor = this.HSVtoRGB(this.hsvColor); - this.fire('colorselected', { rgb: this.rgbColor, hsv: this.hsvColor }); + fireColorSelected(hs) { + this.hsColor = hs; + this.fire('colorselected', { hs: { h: hs.h, s: hs.s } }); } @@ -293,9 +282,9 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { */ // set marker position to the given color - setMarkerOnColor(hsv) { - var dist = hsv.s * this.radius; - var theta = ((hsv.h - 180) / 180) * Math.PI; + setMarkerOnColor(hs) { + var dist = hs.s * this.radius; + var theta = ((hs.h - 180) / 180) * Math.PI; var markerdX = -dist * Math.cos(theta); var markerdY = -dist * Math.sin(theta); var translateString = `translate(${markerdX},${markerdY})`; @@ -304,49 +293,27 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { } // apply given color to interface elements - applyColorToCanvas(hsv) { - // we're not really converting hsv to hsl here, but we keep it cheap + applyColorToCanvas(hs) { + // we're not really converting hs to hsl here, but we keep it cheap // setting the color on the interactionLayer, the svg elements can inherit - this.interactionLayer.style.color = `hsl(${hsv.h}, ${hsv.v * 100}%, ${100 - (hsv.s * 50)}%)`; + this.interactionLayer.style.color = `hsl(${hs.h}, 100%, ${100 - (hs.s * 50)}%)`; } - /* - * applyRgbColor and applyHsvColor are used for external updates - * (to prevent observer loops on this.hsvColor and this.rgbColor) - */ - - applyRgbColor(rgb) { - if (!rgb) { - return; - } + applyHsColor(hs) { // do nothing is we already have the same color - if (this.rgbColor && - this.rgbColor.r === rgb.r && - this.rgbColor.g === rgb.g && - this.rgbColor.b === rgb.b) { + if (this.hsColor && + this.hsColor.h === hs.h && + this.hsColor.s === hs.s) { return; } - var hsv = this.RGBtoHSV(rgb); - this.applyHsvColor(hsv); // marker is always set on 'raw' hsv position - } - - applyHsvColor(hsv) { - // do nothing is we already have the same color - if (this.hsvColor && - this.hsvColor.h === hsv.h && - this.hsvColor.s === hsv.s && - this.hsvColor.v === hsv.v) { - return; - } - this.setMarkerOnColor(hsv); // marker is always set on 'raw' hsv position + this.setMarkerOnColor(hs); // marker is always set on 'raw' hs position if (!this.ignoreSegments) { // apply segments if needed - hsv = this.applySegmentFilter(hsv); + hs = this.applySegmentFilter(hs); } - this.hsvColor = hsv; - this.rgbColor = this.HSVtoRGB(hsv); + this.hsColor = hs; // always apply the new color to the interface / canvas - this.applyColorToCanvas(hsv); + this.applyColorToCanvas(hs); } @@ -380,32 +347,32 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { var hue = this.getAngle(x, y); // degrees, clockwise from right var relativeDistance = this.getDistance(x, y); // edge of radius = 1 var sat = Math.min(relativeDistance, 1); // Distance from center - return { h: hue, s: sat, v: 1 }; + return { h: hue, s: sat }; } - applySegmentFilter(hsv) { + applySegmentFilter(hs) { // apply hue segment steps if (this.hueSegments) { const angleStep = 360 / this.hueSegments; const halfAngleStep = angleStep / 2; - hsv.h -= halfAngleStep; // take the 'centered segemnts' into account - if (hsv.h < 0) { hsv.h += 360; } // don't end up below 0 - const rest = hsv.h % angleStep; - hsv.h -= rest - angleStep; + hs.h -= halfAngleStep; // take the 'centered segemnts' into account + if (hs.h < 0) { hs.h += 360; } // don't end up below 0 + const rest = hs.h % angleStep; + hs.h -= rest - angleStep; } // apply saturation segment steps if (this.saturationSegments) { if (this.saturationSegments === 1) { - hsv.s = 1; + hs.s = 1; } else { var segmentSize = 1 / this.saturationSegments; var saturationStep = 1 / (this.saturationSegments - 1); - var calculatedSat = Math.floor(hsv.s / segmentSize) * saturationStep; - hsv.s = Math.min(calculatedSat, 1); + var calculatedSat = Math.floor(hs.s / segmentSize) * saturationStep; + hs.s = Math.min(calculatedSat, 1); } } - return hsv; + return hs; } /* @@ -557,63 +524,6 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) { this.tooltip = svgElement.tooltip; svgElement.appendChild(svgElement.tooltip); } - - /** - * Color conversion helpers - * - * modified from: - * http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c - * these take/return h = hue (0-360), s = saturation (0-1), v = value (0-1) - */ - - /* eslint-disable */ - HSVtoRGB(hsv) { - var r, g, b, i, f, p, q, t; - var h = hsv.h, s = hsv.s, v = hsv.v; - h /= 360; - i = Math.floor(h * 6); - f = h * 6 - i; - p = v * (1 - s); - q = v * (1 - f * s); - t = v * (1 - (1 - f) * s); - switch (i % 6) { - case 0: r = v, g = t, b = p; break; - case 1: r = q, g = v, b = p; break; - case 2: r = p, g = v, b = t; break; - case 3: r = p, g = q, b = v; break; - case 4: r = t, g = p, b = v; break; - case 5: r = v, g = p, b = q; break; - } - return { - r: Math.round(r * 255), - g: Math.round(g * 255), - b: Math.round(b * 255) - }; - } - - RGBtoHSV(rgb) { - var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, v = max; - var d = max - min; - s = max === 0 ? 0 : d / max; - if (max === min) { - h = 0; // achromatic - } else { - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h *= 60; // hue values 0-360 - } - return { - h: h, - s: s, - v: v - }; - } - /* eslint-enable */ } customElements.define(HaColorPicker.is, HaColorPicker); diff --git a/src/dialogs/more-info/controls/more-info-light.html b/src/dialogs/more-info/controls/more-info-light.html index 043142562d..cc561c285f 100644 --- a/src/dialogs/more-info/controls/more-info-light.html +++ b/src/dialogs/more-info/controls/more-info-light.html @@ -45,7 +45,7 @@ max-height: 84px; } - .has-rgb_color.is-on ha-color-picker { + .has-color.is-on ha-color-picker { max-height: 500px; overflow: visible; --ha-color-picker-wheel-borderwidth: 5; @@ -89,7 +89,7 @@ - + @@ -118,7 +118,7 @@ 1: 'has-brightness', 2: 'has-color_temp', 4: 'has-effect_list', - 16: 'has-rgb_color', + 16: 'has-color', 128: 'has-white_value', }; class MoreInfoLight extends window.hassMixins.EventsMixin(Polymer.Element) { @@ -171,8 +171,11 @@ props.brightnessSliderValue = newVal.attributes.brightness; props.ctSliderValue = newVal.attributes.color_temp; props.wvSliderValue = newVal.attributes.white_value; - if (newVal.attributes.rgb_color) { - props.colorPickerColor = this.rgbArrToObj(newVal.attributes.rgb_color); + if (newVal.attributes.hs_color) { + props.colorPickerColor = { + h: newVal.attributes.hs_color[0], + s: newVal.attributes.hs_color[1] / 100, + }; } if (newVal.attributes.effect_list) { props.effectIndex = newVal.attributes.effect_list.indexOf(newVal.attributes.effect); @@ -254,21 +257,16 @@ serviceChangeColor(hass, entityId, color) { hass.callService('light', 'turn_on', { entity_id: entityId, - rgb_color: [color.r, color.g, color.b], + hs_color: [color.h, color.s * 100], }); } - rgbArrToObj(rgbArr) { - return { r: rgbArr[0], g: rgbArr[1], b: rgbArr[2] }; - } - /** * Called when a new color has been picked. * should be throttled with the 'throttle=' attribute of the color picker */ colorPicked(ev) { - this.color = ev.detail.rgb; - this.serviceChangeColor(this.hass, this.stateObj.entity_id, this.color); + this.serviceChangeColor(this.hass, this.stateObj.entity_id, ev.detail.hs); } }