mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Use new light HS API for the color picker (#982)
This commit is contained in:
parent
6bdf1c8b80
commit
0df4aa6117
@ -82,23 +82,14 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hsvColor: {
|
hsColor: {
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
rgbColor: {
|
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
|
|
||||||
// use these properties to update the state via attributes
|
// use these properties to update the state via attributes
|
||||||
desiredHsvColor: {
|
desiredHsColor: {
|
||||||
type: Object,
|
type: Object,
|
||||||
observer: 'applyHsvColor'
|
observer: 'applyHsColor'
|
||||||
},
|
|
||||||
|
|
||||||
desiredRgbColor: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'applyRgbColor'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// width, height and radius apply to the coordinates of
|
// width, height and radius apply to the coordinates of
|
||||||
@ -157,7 +148,6 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
|
|
||||||
ready() {
|
ready() {
|
||||||
super.ready();
|
super.ready();
|
||||||
this.applyRgbColor = this.applyRgbColor.bind(this);
|
|
||||||
this.setupLayers();
|
this.setupLayers();
|
||||||
this.drawColorWheel();
|
this.drawColorWheel();
|
||||||
this.drawMarker();
|
this.drawMarker();
|
||||||
@ -250,18 +240,18 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
// Process user input to color
|
// Process user input to color
|
||||||
processUserSelect(ev) {
|
processUserSelect(ev) {
|
||||||
var canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
|
var canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
|
||||||
var hsv = this.getColor(canvasXY.x, canvasXY.y);
|
var hs = this.getColor(canvasXY.x, canvasXY.y);
|
||||||
this.onColorSelect(hsv);
|
this.onColorSelect(hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply color to marker position and canvas
|
// apply color to marker position and canvas
|
||||||
onColorSelect(hsv) {
|
onColorSelect(hs) {
|
||||||
this.setMarkerOnColor(hsv); // marker always follows mounse 'raw' hsv value (= mouse position)
|
this.setMarkerOnColor(hs); // marker always follows mounse 'raw' hs value (= mouse position)
|
||||||
if (!this.ignoreSegments) { // apply segments if needed
|
if (!this.ignoreSegments) { // apply segments if needed
|
||||||
hsv = this.applySegmentFilter(hsv);
|
hs = this.applySegmentFilter(hs);
|
||||||
}
|
}
|
||||||
// always apply the new color to the interface / canvas
|
// always apply the new color to the interface / canvas
|
||||||
this.applyColorToCanvas(hsv);
|
this.applyColorToCanvas(hs);
|
||||||
// throttling is applied to updating the exposed colors (properties)
|
// throttling is applied to updating the exposed colors (properties)
|
||||||
// and firing of events
|
// and firing of events
|
||||||
if (this.colorSelectIsThrottled) {
|
if (this.colorSelectIsThrottled) {
|
||||||
@ -269,11 +259,11 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
// eventually after throttle limit has passed
|
// eventually after throttle limit has passed
|
||||||
clearTimeout(this.ensureFinalSelect);
|
clearTimeout(this.ensureFinalSelect);
|
||||||
this.ensureFinalSelect = setTimeout(() => {
|
this.ensureFinalSelect = setTimeout(() => {
|
||||||
this.fireColorSelected(hsv); // do it for the final time
|
this.fireColorSelected(hs); // do it for the final time
|
||||||
}, this.throttle);
|
}, this.throttle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.fireColorSelected(hsv); // do it
|
this.fireColorSelected(hs); // do it
|
||||||
this.colorSelectIsThrottled = true;
|
this.colorSelectIsThrottled = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.colorSelectIsThrottled = false;
|
this.colorSelectIsThrottled = false;
|
||||||
@ -281,10 +271,9 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set color values and fire colorselected event
|
// set color values and fire colorselected event
|
||||||
fireColorSelected(hsv) {
|
fireColorSelected(hs) {
|
||||||
this.hsvColor = hsv;
|
this.hsColor = hs;
|
||||||
this.rgbColor = this.HSVtoRGB(this.hsvColor);
|
this.fire('colorselected', { hs: { h: hs.h, s: hs.s } });
|
||||||
this.fire('colorselected', { rgb: this.rgbColor, hsv: this.hsvColor });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -293,9 +282,9 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// set marker position to the given color
|
// set marker position to the given color
|
||||||
setMarkerOnColor(hsv) {
|
setMarkerOnColor(hs) {
|
||||||
var dist = hsv.s * this.radius;
|
var dist = hs.s * this.radius;
|
||||||
var theta = ((hsv.h - 180) / 180) * Math.PI;
|
var theta = ((hs.h - 180) / 180) * Math.PI;
|
||||||
var markerdX = -dist * Math.cos(theta);
|
var markerdX = -dist * Math.cos(theta);
|
||||||
var markerdY = -dist * Math.sin(theta);
|
var markerdY = -dist * Math.sin(theta);
|
||||||
var translateString = `translate(${markerdX},${markerdY})`;
|
var translateString = `translate(${markerdX},${markerdY})`;
|
||||||
@ -304,49 +293,27 @@ class HaColorPicker extends window.hassMixins.EventsMixin(Polymer.Element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply given color to interface elements
|
// apply given color to interface elements
|
||||||
applyColorToCanvas(hsv) {
|
applyColorToCanvas(hs) {
|
||||||
// we're not really converting hsv to hsl here, but we keep it cheap
|
// 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
|
// 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)}%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
applyHsColor(hs) {
|
||||||
* applyRgbColor and applyHsvColor are used for external updates
|
|
||||||
* (to prevent observer loops on this.hsvColor and this.rgbColor)
|
|
||||||
*/
|
|
||||||
|
|
||||||
applyRgbColor(rgb) {
|
|
||||||
if (!rgb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// do nothing is we already have the same color
|
// do nothing is we already have the same color
|
||||||
if (this.rgbColor &&
|
if (this.hsColor &&
|
||||||
this.rgbColor.r === rgb.r &&
|
this.hsColor.h === hs.h &&
|
||||||
this.rgbColor.g === rgb.g &&
|
this.hsColor.s === hs.s) {
|
||||||
this.rgbColor.b === rgb.b) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var hsv = this.RGBtoHSV(rgb);
|
this.setMarkerOnColor(hs); // marker is always set on 'raw' hs position
|
||||||
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
|
|
||||||
if (!this.ignoreSegments) { // apply segments if needed
|
if (!this.ignoreSegments) { // apply segments if needed
|
||||||
hsv = this.applySegmentFilter(hsv);
|
hs = this.applySegmentFilter(hs);
|
||||||
}
|
}
|
||||||
this.hsvColor = hsv;
|
this.hsColor = hs;
|
||||||
this.rgbColor = this.HSVtoRGB(hsv);
|
|
||||||
// always apply the new color to the interface / canvas
|
// 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 hue = this.getAngle(x, y); // degrees, clockwise from right
|
||||||
var relativeDistance = this.getDistance(x, y); // edge of radius = 1
|
var relativeDistance = this.getDistance(x, y); // edge of radius = 1
|
||||||
var sat = Math.min(relativeDistance, 1); // Distance from center
|
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
|
// apply hue segment steps
|
||||||
if (this.hueSegments) {
|
if (this.hueSegments) {
|
||||||
const angleStep = 360 / this.hueSegments;
|
const angleStep = 360 / this.hueSegments;
|
||||||
const halfAngleStep = angleStep / 2;
|
const halfAngleStep = angleStep / 2;
|
||||||
hsv.h -= halfAngleStep; // take the 'centered segemnts' into account
|
hs.h -= halfAngleStep; // take the 'centered segemnts' into account
|
||||||
if (hsv.h < 0) { hsv.h += 360; } // don't end up below 0
|
if (hs.h < 0) { hs.h += 360; } // don't end up below 0
|
||||||
const rest = hsv.h % angleStep;
|
const rest = hs.h % angleStep;
|
||||||
hsv.h -= rest - angleStep;
|
hs.h -= rest - angleStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply saturation segment steps
|
// apply saturation segment steps
|
||||||
if (this.saturationSegments) {
|
if (this.saturationSegments) {
|
||||||
if (this.saturationSegments === 1) {
|
if (this.saturationSegments === 1) {
|
||||||
hsv.s = 1;
|
hs.s = 1;
|
||||||
} else {
|
} else {
|
||||||
var segmentSize = 1 / this.saturationSegments;
|
var segmentSize = 1 / this.saturationSegments;
|
||||||
var saturationStep = 1 / (this.saturationSegments - 1);
|
var saturationStep = 1 / (this.saturationSegments - 1);
|
||||||
var calculatedSat = Math.floor(hsv.s / segmentSize) * saturationStep;
|
var calculatedSat = Math.floor(hs.s / segmentSize) * saturationStep;
|
||||||
hsv.s = Math.min(calculatedSat, 1);
|
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;
|
this.tooltip = svgElement.tooltip;
|
||||||
svgElement.appendChild(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);
|
customElements.define(HaColorPicker.is, HaColorPicker);
|
||||||
</script>
|
</script>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
max-height: 84px;
|
max-height: 84px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-rgb_color.is-on ha-color-picker {
|
.has-color.is-on ha-color-picker {
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
--ha-color-picker-wheel-borderwidth: 5;
|
--ha-color-picker-wheel-borderwidth: 5;
|
||||||
@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
<ha-color-picker
|
<ha-color-picker
|
||||||
on-colorselected='colorPicked'
|
on-colorselected='colorPicked'
|
||||||
desired-rgb-color='{{colorPickerColor}}'
|
desired-hs-color='{{colorPickerColor}}'
|
||||||
throttle='500'
|
throttle='500'
|
||||||
hue-segments='24'
|
hue-segments='24'
|
||||||
saturation-segments='8'
|
saturation-segments='8'
|
||||||
@ -107,7 +107,7 @@
|
|||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ha-attributes state-obj="[[stateObj]]" extra-filters="brightness,color_temp,white_value,effect_list,effect,rgb_color,xy_color,min_mireds,max_mireds"></ha-attributes>
|
<ha-attributes state-obj="[[stateObj]]" extra-filters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds"></ha-attributes>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
@ -118,7 +118,7 @@
|
|||||||
1: 'has-brightness',
|
1: 'has-brightness',
|
||||||
2: 'has-color_temp',
|
2: 'has-color_temp',
|
||||||
4: 'has-effect_list',
|
4: 'has-effect_list',
|
||||||
16: 'has-rgb_color',
|
16: 'has-color',
|
||||||
128: 'has-white_value',
|
128: 'has-white_value',
|
||||||
};
|
};
|
||||||
class MoreInfoLight extends window.hassMixins.EventsMixin(Polymer.Element) {
|
class MoreInfoLight extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||||
@ -171,8 +171,11 @@
|
|||||||
props.brightnessSliderValue = newVal.attributes.brightness;
|
props.brightnessSliderValue = newVal.attributes.brightness;
|
||||||
props.ctSliderValue = newVal.attributes.color_temp;
|
props.ctSliderValue = newVal.attributes.color_temp;
|
||||||
props.wvSliderValue = newVal.attributes.white_value;
|
props.wvSliderValue = newVal.attributes.white_value;
|
||||||
if (newVal.attributes.rgb_color) {
|
if (newVal.attributes.hs_color) {
|
||||||
props.colorPickerColor = this.rgbArrToObj(newVal.attributes.rgb_color);
|
props.colorPickerColor = {
|
||||||
|
h: newVal.attributes.hs_color[0],
|
||||||
|
s: newVal.attributes.hs_color[1] / 100,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (newVal.attributes.effect_list) {
|
if (newVal.attributes.effect_list) {
|
||||||
props.effectIndex = newVal.attributes.effect_list.indexOf(newVal.attributes.effect);
|
props.effectIndex = newVal.attributes.effect_list.indexOf(newVal.attributes.effect);
|
||||||
@ -254,21 +257,16 @@
|
|||||||
serviceChangeColor(hass, entityId, color) {
|
serviceChangeColor(hass, entityId, color) {
|
||||||
hass.callService('light', 'turn_on', {
|
hass.callService('light', 'turn_on', {
|
||||||
entity_id: entityId,
|
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.
|
* Called when a new color has been picked.
|
||||||
* should be throttled with the 'throttle=' attribute of the color picker
|
* should be throttled with the 'throttle=' attribute of the color picker
|
||||||
*/
|
*/
|
||||||
colorPicked(ev) {
|
colorPicked(ev) {
|
||||||
this.color = ev.detail.rgb;
|
this.serviceChangeColor(this.hass, this.stateObj.entity_id, ev.detail.hs);
|
||||||
this.serviceChangeColor(this.hass, this.stateObj.entity_id, this.color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user