[BasicUI] Implement new sitemap element Colortemperaturepicker (#2851)
Related to openhab/openhab-core#3891 Signed-off-by: Laurent Garnier <lg.hc@free.fr>pull/2863/head
parent
1e4e69e018
commit
9e1a25df68
|
@ -0,0 +1,37 @@
|
|||
<div class="mdl-form__row mdl-cell mdl-cell--%cells%-col mdl-cell--%cells_tablet%-col-tablet %visibility_class%">
|
||||
<span class="mdl-form__icon">
|
||||
%icon_snippet%
|
||||
</span>
|
||||
<span class="mdl-form__label">
|
||||
%label%
|
||||
</span>
|
||||
<span class="mdl-form__value mdl-form__value--colortemppicker">
|
||||
%value%
|
||||
</span>
|
||||
<div
|
||||
class="mdl-form__control mdl-form__colortemppicker"
|
||||
data-control-type="colortemppicker"
|
||||
data-item="%item%"
|
||||
data-has-value="%has_value%"
|
||||
data-state="%currentKelvin%"
|
||||
data-color="%currentRGB%"
|
||||
data-widget-id="%widget_id%"
|
||||
data-icon-with-state="%icon_with_state%"
|
||||
data-label-color="%label_color%"
|
||||
data-value-color="%value_color%"
|
||||
data-icon-color="%icon_color%"
|
||||
data-min="%minValue%"
|
||||
data-max="%maxValue%"
|
||||
data-gradient-colors="%gradientColors%"
|
||||
>
|
||||
<button class="mdl-button mdl-button--raised mdl-js-button mdl-js-ripple-effect mdl-form__colortemppicker--pick">
|
||||
<!-- colorize -->
|
||||
<i class="material-icons"></i>
|
||||
</button>
|
||||
<span class="mdl-form__colortemppicker--preview">
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="50" cy="50" r="44" fill="Gray" stroke="LightGray" stroke-width="6" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
|
@ -53,6 +53,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="template-colortemppicker">
|
||||
<div class="colortemppicker">
|
||||
<div class="colortemppicker__controls">
|
||||
<input class="colortemppicker__input" type="range" min="1000" max="10000" tabindex="0"/>
|
||||
</div>
|
||||
<div class="colortemppicker__buttons">
|
||||
<button class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="template-offline-notify">
|
||||
<div class="mdl-notify">
|
||||
<div class="mdl-notify__text">
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.ui.basic.internal.render;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.emf.common.util.ECollections;
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.items.ItemNotFoundException;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.model.sitemap.sitemap.Colortemperaturepicker;
|
||||
import org.openhab.core.model.sitemap.sitemap.Widget;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.util.UnitUtils;
|
||||
import org.openhab.core.ui.items.ItemUIRegistry;
|
||||
import org.openhab.core.util.ColorUtil;
|
||||
import org.openhab.ui.basic.render.RenderException;
|
||||
import org.openhab.ui.basic.render.WidgetRenderer;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an implementation of the {@link WidgetRenderer} interface, which can produce HTML code for
|
||||
* Colortemperaturepicker widgets.
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@Component(service = WidgetRenderer.class)
|
||||
@NonNullByDefault
|
||||
public class ColortemppickerRenderer extends AbstractWidgetRenderer {
|
||||
|
||||
private static final BigDecimal MIN_TEMPERATURE_KELVIN = BigDecimal.valueOf(1000);
|
||||
private static final BigDecimal MAX_TEMPERATURE_KELVIN = BigDecimal.valueOf(10000);
|
||||
private static final double GRADIENT_INCREMENT_PERCENT = 2.5;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ColortemppickerRenderer.class);
|
||||
|
||||
@Activate
|
||||
public ColortemppickerRenderer(final BundleContext bundleContext, final @Reference TranslationProvider i18nProvider,
|
||||
final @Reference ItemUIRegistry itemUIRegistry, final @Reference LocaleProvider localeProvider) {
|
||||
super(bundleContext, i18nProvider, itemUIRegistry, localeProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRender(Widget w) {
|
||||
return w instanceof Colortemperaturepicker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EList<Widget> renderWidget(Widget w, StringBuilder sb, String sitemap) throws RenderException {
|
||||
Colortemperaturepicker ctp = (Colortemperaturepicker) w;
|
||||
|
||||
BigDecimal currentK = null;
|
||||
String currentRGB = null;
|
||||
Unit<?> unit = UnitUtils.parseUnit(getUnitForWidget(w));
|
||||
BigDecimal minK = MIN_TEMPERATURE_KELVIN;
|
||||
BigDecimal maxK = MAX_TEMPERATURE_KELVIN;
|
||||
String[] colorsRGB = null;
|
||||
String itemType = null;
|
||||
String itemName = w.getItem();
|
||||
if (itemName != null) {
|
||||
try {
|
||||
Item item = itemUIRegistry.getItem(itemName);
|
||||
itemType = item.getType();
|
||||
if ((CoreItemFactory.NUMBER + ":Temperature").equals(itemType)) {
|
||||
State state = itemUIRegistry.getState(w);
|
||||
if (state instanceof QuantityType<?> quantity) {
|
||||
if (unit == null) {
|
||||
unit = quantity.getUnit();
|
||||
}
|
||||
quantity = quantity.toInvertibleUnit(Units.KELVIN);
|
||||
if (quantity != null) {
|
||||
currentK = quantity.toBigDecimal();
|
||||
try {
|
||||
int[] rgb = ColorUtil
|
||||
.hsbToRgb(ColorUtil.xyToHsb(ColorUtil.kelvinToXY(currentK.doubleValue())));
|
||||
logger.debug("Current {} K => RGB {} {} {}", currentK, rgb[0], rgb[1], rgb[2]);
|
||||
currentRGB = "#%02x%02x%02x".formatted(rgb[0], rgb[1], rgb[2]);
|
||||
} catch (IllegalArgumentException | IndexOutOfBoundsException e) {
|
||||
logger.debug("Can't get RGB for {} Kelvin, bypassing color gradient!", currentK);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unit == Units.KELVIN || unit == Units.MIRED) {
|
||||
minK = getMinimumInKelvin(ctp, unit, item.getStateDescription());
|
||||
maxK = getMaximumInKelvin(ctp, unit, item.getStateDescription());
|
||||
logger.debug("ColortemppickerRenderer current={} unit={} min={} max={}", currentK, unit, minK,
|
||||
maxK);
|
||||
|
||||
double valueKelvin = 0d;
|
||||
try {
|
||||
colorsRGB = new String[(int) Math.round(100 / GRADIENT_INCREMENT_PERCENT) + 1];
|
||||
for (int i = 0; Math.round(i * GRADIENT_INCREMENT_PERCENT) <= 100; i++) {
|
||||
valueKelvin = (maxK.doubleValue() - minK.doubleValue()) * i * GRADIENT_INCREMENT_PERCENT
|
||||
/ 100.0 + minK.doubleValue();
|
||||
int[] rgb = ColorUtil.hsbToRgb(ColorUtil.xyToHsb(ColorUtil.kelvinToXY(valueKelvin)));
|
||||
logger.debug("Gradient {}%: {} K => RGB {} {} {}", i * GRADIENT_INCREMENT_PERCENT,
|
||||
valueKelvin, rgb[0], rgb[1], rgb[2]);
|
||||
colorsRGB[i] = "#%02x%02x%02x".formatted(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
} catch (IllegalArgumentException | IndexOutOfBoundsException e) {
|
||||
logger.debug("Can't get RGB for {} Kelvin, bypassing color gradient!", valueKelvin);
|
||||
colorsRGB = null;
|
||||
}
|
||||
} else {
|
||||
logger.warn("Invalid unit {} for Colortemperaturepicker element", unit);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Invalid item type {} for Colortemperaturepicker element", itemType);
|
||||
}
|
||||
} catch (ItemNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
String snippet = getSnippet((CoreItemFactory.NUMBER + ":Temperature").equals(itemType)
|
||||
&& (unit == Units.KELVIN || unit == Units.MIRED) ? "colortemppicker" : "text");
|
||||
|
||||
snippet = preprocessSnippet(snippet, w, true);
|
||||
snippet = snippet.replace("%currentKelvin%", currentK == null ? "" : String.valueOf(currentK.doubleValue()));
|
||||
snippet = snippet.replace("%currentRGB%", currentRGB == null ? "" : currentRGB);
|
||||
snippet = snippet.replace("%minValue%", String.valueOf(minK.doubleValue()));
|
||||
snippet = snippet.replace("%maxValue%", String.valueOf(maxK.doubleValue()));
|
||||
snippet = snippet.replace("%gradientColors%", colorsRGB == null ? "" : String.join(",", colorsRGB));
|
||||
|
||||
// Process the color tags
|
||||
snippet = processColor(w, snippet);
|
||||
|
||||
sb.append(snippet);
|
||||
return ECollections.emptyEList();
|
||||
}
|
||||
|
||||
private BigDecimal getMinimumInKelvin(Colortemperaturepicker widget, Unit<?> widgetUnit,
|
||||
@Nullable StateDescription stateDescription) {
|
||||
BigDecimal min = null;
|
||||
BigDecimal val;
|
||||
if (widgetUnit == Units.KELVIN) {
|
||||
min = widget.getMinValue();
|
||||
} else {
|
||||
val = widget.getMaxValue();
|
||||
QuantityType<?> quantity = val == null ? null
|
||||
: QuantityType.valueOf(val.doubleValue(), Units.MIRED).toInvertibleUnit(Units.KELVIN);
|
||||
min = quantity == null ? null : quantity.toBigDecimal();
|
||||
}
|
||||
// Search the min in the item state description if not defined in the widget
|
||||
if (min == null && stateDescription != null) {
|
||||
if (isUnitInKelvin(stateDescription)) {
|
||||
min = stateDescription.getMinimum();
|
||||
} else {
|
||||
val = stateDescription.getMaximum();
|
||||
QuantityType<?> quantity = val == null ? null
|
||||
: QuantityType.valueOf(val.doubleValue(), Units.MIRED).toInvertibleUnit(Units.KELVIN);
|
||||
min = quantity == null ? null : quantity.toBigDecimal();
|
||||
}
|
||||
}
|
||||
return min != null ? min : MIN_TEMPERATURE_KELVIN;
|
||||
}
|
||||
|
||||
private BigDecimal getMaximumInKelvin(Colortemperaturepicker widget, Unit<?> widgetUnit,
|
||||
@Nullable StateDescription stateDescription) {
|
||||
BigDecimal max = null;
|
||||
BigDecimal val;
|
||||
if (widgetUnit == Units.KELVIN) {
|
||||
max = widget.getMaxValue();
|
||||
} else {
|
||||
val = widget.getMinValue();
|
||||
QuantityType<?> quantity = val == null ? null
|
||||
: QuantityType.valueOf(val.doubleValue(), Units.MIRED).toInvertibleUnit(Units.KELVIN);
|
||||
max = quantity == null ? null : quantity.toBigDecimal();
|
||||
}
|
||||
// Search the max in the item state description if not defined in the widget
|
||||
if (max == null && stateDescription != null) {
|
||||
if (isUnitInKelvin(stateDescription)) {
|
||||
max = stateDescription.getMaximum();
|
||||
} else {
|
||||
val = stateDescription.getMinimum();
|
||||
QuantityType<?> quantity = val == null ? null
|
||||
: QuantityType.valueOf(val.doubleValue(), Units.MIRED).toInvertibleUnit(Units.KELVIN);
|
||||
max = quantity == null ? null : quantity.toBigDecimal();
|
||||
}
|
||||
}
|
||||
return max != null ? max : MAX_TEMPERATURE_KELVIN;
|
||||
}
|
||||
|
||||
private boolean isUnitInKelvin(StateDescription stateDescription) {
|
||||
// If no pattern or pattern with no unit, assume unit for min and max is Kelvin
|
||||
Unit<?> unit = UnitUtils.parseUnit(stateDescription.getPattern());
|
||||
return unit == null || unit == Units.KELVIN;
|
||||
}
|
||||
}
|
|
@ -174,7 +174,7 @@ public class WebAppServlet extends HttpServlet {
|
|||
String label = sitemap.getLabel() != null ? sitemap.getLabel() : sitemapName;
|
||||
EList<Widget> children = renderer.getItemUIRegistry().getChildren(sitemap);
|
||||
result.append(renderer.processPage(sitemapName, sitemapName, label, children, async));
|
||||
} else if (!"Colorpicker".equals(widgetId)) {
|
||||
} else if (!"Colorpicker".equals(widgetId) && !"Colortemperaturepicker".equals(widgetId)) {
|
||||
// we are on some subpage, so we have to render the children of the widget that has been selected
|
||||
if (subscriptionId != null) {
|
||||
if (subscriptions.exists(subscriptionId)) {
|
||||
|
|
|
@ -341,12 +341,20 @@
|
|||
}
|
||||
&__setpoint,
|
||||
&__colorpicker,
|
||||
&__colortemppicker,
|
||||
&__rollerblind {
|
||||
.mdl-button {
|
||||
min-width: 0;
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
&__colortemppicker--preview {
|
||||
svg {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
&__header {
|
||||
padding-left: 8px;
|
||||
padding-right: $form-row-desktop-padding;
|
||||
|
@ -458,7 +466,8 @@
|
|||
text-transform: uppercase;
|
||||
}
|
||||
&--setpoint,
|
||||
&--rollerblind {
|
||||
&--rollerblind,
|
||||
&--colortemppicker {
|
||||
padding: 0 10px 0 5px;
|
||||
}
|
||||
&--group {
|
||||
|
@ -755,6 +764,84 @@ $colorpicker-mobile-size: 270px;
|
|||
position: relative;
|
||||
}
|
||||
|
||||
// Colortemppicker
|
||||
$colortemppicker-thumb-width: 20px;
|
||||
$colortemppicker-slider-height: 200px;
|
||||
$colortemppicker-desktop-size: 500px;
|
||||
$colortemppicker-mobile-size: 270px;
|
||||
|
||||
@mixin colortemppicker-slider-track() {
|
||||
display: block;
|
||||
height: $colortemppicker-slider-height;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@mixin colortemppicker-slider-thumb() {
|
||||
-webkit-appearance: none;
|
||||
width: $colortemppicker-thumb-width;
|
||||
height: $colortemppicker-slider-height;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
border: 3px solid #aaa;
|
||||
}
|
||||
|
||||
.colortemppicker {
|
||||
&__input {
|
||||
-webkit-appearance: none;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 1px solid $item-separator-color;
|
||||
width: $colortemppicker-desktop-size - 30px;
|
||||
@media screen and (max-width: $layout-mobile-size-threshold) {
|
||||
width: $colortemppicker-mobile-size - 30px;
|
||||
}
|
||||
height: $colortemppicker-slider-height;
|
||||
&::-ms-track {
|
||||
@include colortemppicker-slider-track();
|
||||
}
|
||||
&::-webkit-slider-runnable-track {
|
||||
@include colortemppicker-slider-track();
|
||||
}
|
||||
&::-moz-range-track {
|
||||
@include colortemppicker-slider-track();
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
@include colortemppicker-slider-thumb();
|
||||
}
|
||||
&::-webkit-slider-thumb {
|
||||
@include colortemppicker-slider-thumb();
|
||||
}
|
||||
&::-ms-thumb {
|
||||
@include colortemppicker-slider-thumb();
|
||||
}
|
||||
&::-ms-fill-upper {
|
||||
background: none;
|
||||
}
|
||||
&::-ms-fill-lower {
|
||||
background: none;
|
||||
}
|
||||
&::-ms-ticks {
|
||||
background: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&__controls {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid $item-separator-color;
|
||||
}
|
||||
&__buttons {
|
||||
padding: 5px;
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h4 {
|
||||
html.ui-bigger-font & {
|
||||
font-size: 28px;
|
||||
|
@ -805,6 +892,12 @@ h5 {
|
|||
max-width: $colorpicker-mobile-size;
|
||||
}
|
||||
}
|
||||
&--colortemppicker {
|
||||
max-width: $colortemppicker-desktop-size;
|
||||
@media screen and (max-width: $layout-mobile-size-threshold) {
|
||||
max-width: $colortemppicker-mobile-size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mdl-notify {
|
||||
|
|
|
@ -2251,6 +2251,199 @@
|
|||
|
||||
smarthome.eventMapper.map(eventMap);
|
||||
}
|
||||
|
||||
/* class Colortemppicker */
|
||||
function Colortemppicker(parentNode, min, max, current, gradientColors, callback) {
|
||||
var
|
||||
_t = this,
|
||||
lastColorTemperatureSent = null;
|
||||
|
||||
_t.container = parentNode;
|
||||
_t.isBeingChanged = false;
|
||||
|
||||
_t.colortemppicker = _t.container.querySelector(o.colortemppicker.colortemppicker);
|
||||
_t.slider = _t.container.querySelector(o.colortemppicker.slider);
|
||||
if (gradientColors !== "") {
|
||||
_t.slider.style.background = "linear-gradient(to right, " + gradientColors + ")";
|
||||
}
|
||||
_t.slider.min = Math.round(min);
|
||||
_t.slider.max = Math.round(max);
|
||||
|
||||
function setCorTemperature(value) {
|
||||
if (isNaN(value)) {
|
||||
_t.value = NaN;
|
||||
_t.slider.value = _t.slider.min;
|
||||
} else {
|
||||
if (value < _t.slider.min) {
|
||||
_t.value = _t.slider.min;
|
||||
} else if (value > _t.slider.max) {
|
||||
_t.value = _t.slider.max;
|
||||
} else {
|
||||
_t.value = value;
|
||||
}
|
||||
_t.slider.value = _t.value;
|
||||
}
|
||||
if (_t.slider.MaterialSlider) {
|
||||
_t.slider.MaterialSlider.change();
|
||||
}
|
||||
}
|
||||
|
||||
setCorTemperature(current);
|
||||
|
||||
_t.button = _t.container.querySelector(o.controlButton);
|
||||
|
||||
componentHandler.upgradeElement(_t.button, "MaterialButton");
|
||||
componentHandler.upgradeElement(_t.button, "MaterialRipple");
|
||||
|
||||
_t.debounceProxy = new DebounceProxy(function() {
|
||||
if (_t.value !== lastColorTemperatureSent) {
|
||||
callback(_t.value);
|
||||
lastColorTemperatureSent = _t.value;
|
||||
}
|
||||
}, 200);
|
||||
|
||||
_t.updateColorTemperature = function(value) {
|
||||
if (_t.isBeingChanged) {
|
||||
return;
|
||||
}
|
||||
setCorTemperature(value);
|
||||
};
|
||||
|
||||
function onSliderChangeStart() {
|
||||
lastColorTemperatureSent = null;
|
||||
}
|
||||
|
||||
function onSliderChange() {
|
||||
_t.debounceProxy.finish();
|
||||
_t.value = _t.slider.value;
|
||||
if (_t.value !== lastColorTemperatureSent) {
|
||||
callback(_t.value);
|
||||
lastColorTemperatureSent = _t.value;
|
||||
}
|
||||
}
|
||||
|
||||
function onSliderInput() {
|
||||
_t.value = _t.slider.value;
|
||||
_t.debounceProxy.call();
|
||||
}
|
||||
|
||||
var
|
||||
eventMap = [
|
||||
[ _t.slider, "touchstart", onSliderChangeStart ],
|
||||
[ _t.slider, "mousedown", onSliderChangeStart ],
|
||||
[ _t.slider, "input", onSliderInput ],
|
||||
[ _t.slider, "change", onSliderChange ]
|
||||
];
|
||||
|
||||
_t.destroy = function() {
|
||||
smarthome.eventMapper.unmap(eventMap);
|
||||
componentHandler.downgradeElements([ _t.button ]);
|
||||
};
|
||||
|
||||
smarthome.eventMapper.map(eventMap);
|
||||
}
|
||||
|
||||
/* class ControlColortemppicker extends Control */
|
||||
function ControlColortemppicker(parentNode) {
|
||||
Control.call(this, parentNode);
|
||||
|
||||
var
|
||||
_t = this,
|
||||
color;
|
||||
|
||||
_t.valueNode = _t.parentNode.parentNode.querySelector(o.formValue);
|
||||
_t.hasValue = _t.parentNode.getAttribute("data-has-value") === "true";
|
||||
_t.value = _t.parentNode.getAttribute("data-state") === "" ? NaN : parseFloat(_t.parentNode.getAttribute("data-state"));
|
||||
_t.min = parseFloat(_t.parentNode.getAttribute("data-min"));
|
||||
_t.max = parseFloat(_t.parentNode.getAttribute("data-max"));
|
||||
_t.gradientColors = _t.parentNode.getAttribute("data-gradient-colors");
|
||||
_t.colors = (_t.gradientColors === "" ? "Gray" : _t.gradientColors).split(",");
|
||||
_t.modalControl = null;
|
||||
_t.buttonPick = _t.parentNode.querySelector(o.colortemppicker.pick);
|
||||
_t.circle = _t.parentNode.querySelector(o.colortemppicker.circle);
|
||||
color = _t.parentNode.getAttribute("data-color");
|
||||
if (color !== "") {
|
||||
_t.circle.setAttribute("fill", color);
|
||||
}
|
||||
|
||||
_t.setValuePrivate = function(value, itemState) {
|
||||
if (_t.hasValue) {
|
||||
_t.valueNode.innerHTML = value;
|
||||
}
|
||||
|
||||
// itemState contains value + unit in the display unit (in case unit is set in label pattern)
|
||||
if (itemState === "NULL" || itemState === "UNDEF") {
|
||||
_t.value = NaN;
|
||||
} else if (itemState.indexOf(" ") > 0) {
|
||||
var stateAndUnit = itemState.split(" ");
|
||||
_t.value = parseFloat(stateAndUnit[0]);
|
||||
_t.value = isNaN(_t.value) ? NaN : (stateAndUnit[1] === "K" ? _t.value : 1000000.0 / _t.value);
|
||||
} else {
|
||||
_t.value = itemState * 1;
|
||||
}
|
||||
|
||||
// Set the color in the preview circle with the most approaching color used to generate the gradient
|
||||
_t.circle.setAttribute("fill", (isNaN(_t.value) || _t.value < _t.min || _t.value > _t.max)
|
||||
? "Gray"
|
||||
: _t.colors[Math.round((_t.value - _t.min) * (_t.colors.length - 1) / (_t.max - _t.min))]);
|
||||
|
||||
if (_t.modalControl !== null) {
|
||||
_t.modalControl.updateColorTemperature(_t.value);
|
||||
}
|
||||
};
|
||||
|
||||
function emitEvent(valueKelvin) {
|
||||
var
|
||||
command = valueKelvin + " K";
|
||||
|
||||
_t.parentNode.dispatchEvent(createEvent(
|
||||
"control-change", {
|
||||
item: _t.item,
|
||||
value: command
|
||||
}));
|
||||
}
|
||||
|
||||
function onPick() {
|
||||
var
|
||||
button;
|
||||
|
||||
function onClick() {
|
||||
_t.modal.hide();
|
||||
}
|
||||
|
||||
_t.modal = new Modal(renderTemplate("template-colortemppicker"));
|
||||
_t.modal.show();
|
||||
_t.modal.container.classList.add(o.colortemppicker.modalClass);
|
||||
_t.modal.onHide = function() {
|
||||
button.removeEventListener("click", onClick);
|
||||
_t.modalControl.destroy();
|
||||
_t.modalControl = null;
|
||||
_t.modal = null;
|
||||
};
|
||||
|
||||
_t.modalControl = new Colortemppicker(_t.modal.container, _t.min, _t.max, _t.value, _t.gradientColors,
|
||||
function(valueKelvin) {
|
||||
emitEvent(valueKelvin);
|
||||
}
|
||||
);
|
||||
|
||||
button = _t.modal.container.querySelector(o.colortemppicker.button);
|
||||
button.addEventListener("click", onClick);
|
||||
}
|
||||
|
||||
var
|
||||
eventMap = [
|
||||
[ _t.buttonPick, "click", onPick ]
|
||||
];
|
||||
|
||||
_t.destroy = function() {
|
||||
smarthome.eventMapper.unmap(eventMap);
|
||||
componentHandler.downgradeElements([ _t.buttonPick ]);
|
||||
};
|
||||
|
||||
smarthome.eventMapper.map(eventMap);
|
||||
}
|
||||
|
||||
/* class ControlSwitch extends Control */
|
||||
function ControlSwitch(parentNode) {
|
||||
Control.call(this, parentNode);
|
||||
|
@ -2968,6 +3161,7 @@
|
|||
case "setpoint":
|
||||
case "rollerblind":
|
||||
case "colorpicker":
|
||||
case "colortemppicker":
|
||||
case "buttons":
|
||||
[].slice.call(e.querySelectorAll("button")).forEach(function(button) {
|
||||
upgrade(button, "MaterialButton");
|
||||
|
@ -3154,6 +3348,9 @@
|
|||
case "colorpicker":
|
||||
appendControl(new ControlColorpicker(e));
|
||||
break;
|
||||
case "colortemppicker":
|
||||
appendControl(new ControlColortemppicker(e));
|
||||
break;
|
||||
case "mapview":
|
||||
appendControl(new ControlMap(e));
|
||||
break;
|
||||
|
@ -3748,6 +3945,14 @@
|
|||
colorpicker: ".colorpicker",
|
||||
button: ".colorpicker__buttons > button"
|
||||
},
|
||||
colortemppicker: {
|
||||
pick: ".mdl-form__colortemppicker--pick",
|
||||
circle: ".mdl-form__colortemppicker--preview > svg > circle",
|
||||
modalClass: "mdl-modal--colortemppicker",
|
||||
slider: ".colortemppicker__input",
|
||||
colortemppicker: ".colortemppicker",
|
||||
button: ".colortemppicker__buttons > button"
|
||||
},
|
||||
image: {
|
||||
legendButton: ".chart-legend-button",
|
||||
periodButton: ".chart-period-button",
|
||||
|
|
Loading…
Reference in New Issue