UI Bubbles - multi state indicators
Simple UI element using Dashboard Template node. Provides multi state indication by setting colour of Circle boarder. Uses CSS and Angular ngClass array expressions.
Each bubble (Circle) has 4 states that are set to 0 - 3 via mas.payload.
Colours/Circle size can be customised using CSS (See State 1)
Supports ng-click to change UI state change and sends state back via msg.payload back to Node-RED. (See State 2)
Inside circle you can use Font Awesome icons which will change color to match state (See State 3)
Example shows a grid of 3 bubbles I've included three sliders to demo state change
[{"id":"2e68db49.c95d34","type":"ui_template","z":"14f37c28.1f3564","group":"cf2fe171.40162","name":"Bubble b3","order":3,"width":"2","height":"2","format":"<div class='bLable'>State 3</div>\n<div id='b1' ng-class=\"{0:'bubble off',1:'bubble on',2:'bubble tri',3:'bubble quad'}[(msg.payload || 0)]\">\n <i class='fa fa-lightbulb-o fa-2x off'></i>\n</div>\n<style>\n.bc {float: left; padding::0; margin:0 9px 0 0 !important;} \n.bLable {padding-left: 6px;}\n.bubble {float: left; width: 3.5em; height: 3.5em; border-radius: 50%; border: 7px solid #D21E1E; text-align:center; display:table-cell; outline: none !important; outline: 0 !important;}\n.off {border-color: #D21E1E;}\n.on {border-color: #5E9C31;}\n.tri {border-color: #D08C03;}\n.quad {border-color: #60A6E8;}\ndiv i {padding-top: 12px;}\ndiv .blank i {opacity: 0.0;}\ndiv .off i {color: #D21E1E;}\ndiv .on i {color: #5E9C31;}\ndiv .tri i {color: #D08C03;}\ndiv .quad i {color: #60A6E8;}\n</style>","storeOutMessages":true,"fwdInMessages":false,"x":379.4258117675781,"y":666.24755859375,"wires":[[]]},{"id":"cac093d5.3a665","type":"ui_slider","z":"14f37c28.1f3564","name":"","label":"State 3","group":"cf2fe171.40162","order":6,"width":"4","height":"1","passthru":false,"topic":"","min":0,"max":"3","step":1,"x":201.84078979492188,"y":665.3042602539062,"wires":[["2e68db49.c95d34"]]},{"id":"e322109b.1e4fe","type":"ui_template","z":"14f37c28.1f3564","group":"cf2fe171.40162","name":"Bubble b2","order":2,"width":"2","height":"2","format":"<div class='bLable'>State 2</div>\n<div id='b2' ng-class=\"{0:'bubble off',1:'bubble on',2:'bubble tri',3:'bubble Quad'}[(msg.payload || 0)]\" ng-click=\"sendClick($event)\"></div>\n\n<style>\n.bc {float: left; padding::0; margin:0 9px 0 0 !important;} \n.bLable {padding-left: 6px;}\n.bubble {float: left; width: 3.5em; height: 3.5em; border-radius: 50%; border: 7px solid #D21E1E; text-align:center; display:table-cell; outline: none !important; outline: 0 !important;}\n.off {border-color: #D21E1E;}\n.on {border-color: #5E9C31;}\n.tri {border-color: #D08C03;}\n.quad {border-color: #60A6E8;}\n</style>\n<script>\nvar sc = scope;\nvar sendClick = function(event){\n \n var thisRing = event.currentTarget.attributes.class.value;\n console.log('class: '+thisRing);\n if(thisRing === \"bubble off\"){\n event.currentTarget.attributes.class.value = \"bubble on\";\n state = 1;\n } else {\n event.currentTarget.attributes.class.value = \"bubble off\";\n state = 0\n }\n var uiid = JSON.stringify(event.currentTarget.attributes.id.value);\n sc.send({payload:state,topic:uiid});\n}\nscope.sendClick = sendClick;\n</script>","storeOutMessages":true,"fwdInMessages":false,"x":381.42572021484375,"y":619.9078979492188,"wires":[["6411180a.b681d8","d7519c84.77c8c"]]},{"id":"d7519c84.77c8c","type":"ui_slider","z":"14f37c28.1f3564","name":"","label":"State 2","group":"cf2fe171.40162","order":5,"width":"4","height":"1","passthru":true,"topic":"","min":0,"max":"1","step":1,"x":202.8406982421875,"y":620.9645385742188,"wires":[["e322109b.1e4fe"]]},{"id":"24929f61.4e267","type":"ui_template","z":"14f37c28.1f3564","group":"cf2fe171.40162","name":"Bubble b1","order":1,"width":"2","height":"2","format":"<div class='bLable'>State 1</div>\n<div ng-class=\"{0:'bubble off',1:'bubble on',2:'bubble tri',3:'bubble quad'}[(msg.payload || 0)]\"></div>\n\n<style>\n.bc {float: left; padding::0; margin:0 9px 0 0 !important;} \n.bLable {padding-left: 6px;}\n.bubble {float: left; width: 3.5em; height: 3.5em; border-radius: 50%; border: 7px solid #D21E1E; text-align:center; display:table-cell; outline: none !important; outline: 0 !important;}\n.off {border-color: #D21E1E;}\n.on {border-color: #5E9C31;}\n.tri {border-color: #D08C03;}\n.quad {border-color: #60A6E8;}\n</style>","storeOutMessages":true,"fwdInMessages":false,"x":379.4256896972656,"y":575.9079895019531,"wires":[[]]},{"id":"886220b5.bb34e","type":"ui_slider","z":"14f37c28.1f3564","name":"","label":"State 1","group":"cf2fe171.40162","order":4,"width":"4","height":"1","passthru":true,"topic":"","min":0,"max":"3","step":1,"x":198.84066772460938,"y":575.9645538330078,"wires":[["24929f61.4e267"]]},{"id":"6411180a.b681d8","type":"debug","z":"14f37c28.1f3564","name":"","active":true,"console":"false","complete":"false","x":554.8407897949219,"y":620.5118408203125,"wires":[]},{"id":"cf2fe171.40162","type":"ui_group","z":"","name":"Multi Bubble","tab":"8edb4c27.94fea","order":1,"disp":true,"width":"6"},{"id":"8edb4c27.94fea","type":"ui_tab","z":"","name":"Bubbles","icon":"dashboard"}]