Old topic, but I have got my sliders to work within the UI template node.
I have some Shelly RGBW2 led controllers which I control using NodeRED. I have created a UI which controls the different RGB and White channels. So I treat the RGB as mixed and the White channel is a separate light source. I stole the UI of the iOS color picker. It looks nice and works as expected in the Safari (MacOS) browser.
My NodeRED implementation:
The html angular code:
<style>
.slidecontainer {
/* font-size: 80%; */
width: 100%;
}
.slidecontainer input {
margin-bottom:12px;
}
/* slider bar */
.slider {
-webkit-appearance: none;
width: 98%;
height: 36px;
border-radius: 18px;
outline: none;
padding: 0px 2px;
}
/* per color slides */
.red {
background: linear-gradient(90deg, rgba(0,{{msg.payload.green}},{{msg.payload.blue}},1) 0%, rgba(255,{{msg.payload.green}},{{msg.payload.blue}},1) 100%);
}
.green {
background: linear-gradient(90deg, rgba({{msg.payload.red}},0,{{msg.payload.blue}},1) 0%, rgba({{msg.payload.red}},255,{{msg.payload.blue}},1) 100%);
}
.blue {
background: linear-gradient(90deg, rgba({{msg.payload.red}},{{msg.payload.green}},0,1) 0%, rgba({{msg.payload.red}},{{msg.payload.green}},255,1) 100%);
}
.gain {
background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},1) 100%);
}
.white {
background: linear-gradient(90deg, rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},{{msg.payload.gain/100}}) 0%, rgba(253,253,240,1) 100%);
}
/* slider knob */
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 32px;
height: 32px;
border-radius: 50%;
background: rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},1);
border: 2px solid white;
cursor: pointer;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.white.slider::-webkit-slider-thumb {
background: rgba(253,253,240,1);
}
/*
AAN / UIT knop
er is een transitie van de knop
- de knop is 26 pixel breed
- dus de knop moet van links naar rechts bewegen
- de hoeveelheid die de knop moet bewegen is de totale breedte min de breedte van de knop
*/
.switch {
position: relative;
display: inline-block;
width: 72px;
height: 36px;
appearance: none;
border: none;
cursor: pointer;
}
/* remove original */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* button background */
.button {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .1s;
transition: .1s;
}
/* button */
.button:before {
-webkit-appearance: none;
appearance: none;
position: absolute;
content: "";
margin:1px;
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid white;
cursor: pointer;
background: rgba(253,253,240,0.6);
-webkit-transition: .1s;
transition: .1s;
}
/* button on */
input + .button {
border:1px solid white;
}
input:checked + .button {
background-color: rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},{{msg.payload.gain/100}});
}
/* transition to right */
input:checked + .button:before {
-webkit-transform: translateX(36px);
-ms-transform: translateX(36px);
transform: translateX(36px);
}
/* Rounded input */
.button.round {
border-radius: 36px;
}
/* layout on off */
.onoff {
overflow: auto;
}
.onoff label{
float: right;
}
</style>
<div class="slidecontainer">
<div class="onoff">
{{msg.payload.title}}
<label class="switch"> <input type="checkbox"><span class="button round"></span></label>
</div>
Red ({{msg.payload.red}})
<input type="range" min="0" max="255" value="{{msg.payload.red}}" class="slider red" ng-model="msg.payload.red" ng-mouseup="send(msg)">
Green ({{msg.payload.green}})
<input type="range" min="0" max="255" value="{{msg.payload.green}}" class="slider green" ng-model="msg.payload.green" ng-mouseup="send(msg)">
Blue ({{msg.payload.blue}})
<input type="range" min="0" max="255" value="{{msg.payload.blue}}" class="slider blue" ng-model="msg.payload.blue" ng-mouseup="send(msg)">
Gain ({{msg.payload.gain}})
<input type="range" min="0" max="100" value="{{msg.payload.gain}}" class="slider gain" ng-model="msg.payload.gain" ng-mouseup="send(msg)">
White ({{msg.payload.white}})
<input type="range" min="0" max="255" value="{{msg.payload.white}}" class="slider white" ng-model="msg.payload.white" ng-mouseup="send(msg)">
</div>
The node-red code:
[
{
"id": "2ffcec6.78cdf94",
"type": "inject",
"z": "4d2d578e.6cea28",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "1",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 335,
"y": 2440,
"wires": [
[
"c9995b07.1f14f"
]
],
"l": false
},
{
"id": "c9995b07.1f14f",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "inject",
"func": "\n// create a random colour\nmsg.payload = { \"title\":\"Demo\",\n \"red\": Math.floor(Math.random() * (255) ),\n \"green\": Math.floor(Math.random() * (255) ),\n \"blue\": Math.floor(Math.random() * (255) ),\n \"gain\": Math.floor(Math.random() * 101),\n \"white\": Math.floor(Math.random() * 255)\n}\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 450,
"y": 2440,
"wires": [
[
"1467f9da.58d96e"
]
]
},
{
"id": "1467f9da.58d96e",
"type": "ui_template",
"z": "4d2d578e.6cea28",
"group": "fb4c245.8e22cd8",
"name": "RGB & White sliders",
"order": 2,
"width": "0",
"height": "0",
"format": "<style>\n.slidecontainer {\n\t/* font-size: 80%; */\n\twidth: 100%;\n}\n.slidecontainer input {\n\tmargin-bottom:12px;\n}\n/* slider bar */\n.slider {\n -webkit-appearance: none;\n width: 98%;\n height: 36px;\n border-radius: 18px;\n outline: none;\n padding: 0px 2px;\n}\n\n/* per color slides */\n.red {\n background: linear-gradient(90deg, rgba(0,{{msg.payload.green}},{{msg.payload.blue}},1) 0%, rgba(255,{{msg.payload.green}},{{msg.payload.blue}},1) 100%);\n}\n.green {\n background: linear-gradient(90deg, rgba({{msg.payload.red}},0,{{msg.payload.blue}},1) 0%, rgba({{msg.payload.red}},255,{{msg.payload.blue}},1) 100%);\n}\n.blue {\n background: linear-gradient(90deg, rgba({{msg.payload.red}},{{msg.payload.green}},0,1) 0%, rgba({{msg.payload.red}},{{msg.payload.green}},255,1) 100%);\n}\n.gain {\n background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},1) 100%);\n}\n.white {\n background: linear-gradient(90deg, rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},{{msg.payload.gain/100}}) 0%, rgba(253,253,240,1) 100%);\n}\n\n/* slider knob */\n.slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},1);\n border: 2px solid white;\n cursor: pointer;\n box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n}\n.white.slider::-webkit-slider-thumb {\n background: rgba(253,253,240,1);\n}\n\n/* \n\tAAN / UIT knop\n\ter is een transitie van de knop\n\t- de knop is 26 pixel breed\n\t- dus de knop moet van links naar rechts bewegen\n\t- de hoeveelheid die de knop moet bewegen is de totale breedte min de breedte van de knop\n*/\n\n.switch {\n position: relative;\n display: inline-block;\n width: 72px;\n height: 36px;\n appearance: none;\n border: none;\n cursor: pointer;\n}\n/* remove original */\n.switch input { \n opacity: 0;\n width: 0;\n height: 0;\n}\n\n/* button background */\n.button {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #ccc;\n -webkit-transition: .1s;\n transition: .1s;\n}\n\n/* button */\n.button:before {\n -webkit-appearance: none;\n appearance: none;\n position: absolute;\n content: \"\";\n margin:1px;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: 2px solid white;\n cursor: pointer;\n background: rgba(253,253,240,0.6);\n -webkit-transition: .1s;\n transition: .1s;\n}\n/* button on */\ninput + .button {\n border:1px solid white;\n}\ninput:checked + .button {\n background-color: rgba({{msg.payload.red}},{{msg.payload.green}},{{msg.payload.blue}},{{msg.payload.gain/100}});\n}\n\n/* transition to right */\ninput:checked + .button:before {\n -webkit-transform: translateX(36px);\n -ms-transform: translateX(36px);\n transform: translateX(36px);\n}\n\n/* Rounded input */\n.button.round {\n border-radius: 36px;\n}\n/* layout on off */\n.onoff {\n overflow: auto;\n}\n.onoff label{\n float: right;\n}\n</style>\n\n<div class=\"slidecontainer\">\n <div class=\"onoff\">\n {{msg.payload.title}}\n <label class=\"switch\"> <input type=\"checkbox\"><span class=\"button round\"></span></label>\n </div>\n\n\n\tRed ({{msg.payload.red}})\n\t<input type=\"range\" min=\"0\" max=\"255\" value=\"{{msg.payload.red}}\" class=\"slider red\" ng-model=\"msg.payload.red\" ng-mouseup=\"send(msg)\">\n\tGreen ({{msg.payload.green}})\n\t<input type=\"range\" min=\"0\" max=\"255\" value=\"{{msg.payload.green}}\" class=\"slider green\" ng-model=\"msg.payload.green\" ng-mouseup=\"send(msg)\">\n\tBlue ({{msg.payload.blue}})\n\t<input type=\"range\" min=\"0\" max=\"255\" value=\"{{msg.payload.blue}}\" class=\"slider blue\" ng-model=\"msg.payload.blue\" ng-mouseup=\"send(msg)\">\n\tGain ({{msg.payload.gain}})\n\t<input type=\"range\" min=\"0\" max=\"100\" value=\"{{msg.payload.gain}}\" class=\"slider gain\" ng-model=\"msg.payload.gain\" ng-mouseup=\"send(msg)\">\n\n \n White ({{msg.payload.white}})\n\t<input type=\"range\" min=\"0\" max=\"255\" value=\"{{msg.payload.white}}\" class=\"slider white\" ng-model=\"msg.payload.white\" ng-mouseup=\"send(msg)\">\n</div>",
"storeOutMessages": true,
"fwdInMessages": false,
"resendOnRefresh": true,
"templateScope": "local",
"x": 660,
"y": 2440,
"wires": [
[
"69180f62.347ca8"
]
]
},
{
"id": "fb4c245.8e22cd8",
"type": "ui_group",
"name": "Slider demo",
"tab": "9cb34fc7.ab81b8",
"order": 1,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "9cb34fc7.ab81b8",
"type": "ui_tab",
"name": "Test",
"icon": "dashboard",
"order": 17,
"disabled": false,
"hidden": false
}
]
The original iOS UI looks like this: