|
[ |
|
{ |
|
"id": "1678f3c7ab967e39", |
|
"type": "group", |
|
"z": "278e7d113ed09433", |
|
"style": { |
|
"stroke": "#999999", |
|
"stroke-opacity": "1", |
|
"fill": "none", |
|
"fill-opacity": "1", |
|
"label": true, |
|
"label-position": "nw", |
|
"color": "#a4a4a4" |
|
}, |
|
"nodes": [ |
|
"18b02b8e78a54427", |
|
"68208d9442bc03c1", |
|
"5f6a472f6435e598", |
|
"389e05735379ed2e", |
|
"db89d982a40f6c4d", |
|
"3feb6c0d7c1c07b2", |
|
"8ce7dd9a5d97b83b", |
|
"06fa35d1c6063d4c", |
|
"891a5f86c7c89917", |
|
"3939b0bbde991557", |
|
"2e40ef6c2172741a" |
|
], |
|
"x": 128, |
|
"y": 95, |
|
"w": 1018, |
|
"h": 532 |
|
}, |
|
{ |
|
"id": "18b02b8e78a54427", |
|
"type": "uibuilder", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "", |
|
"topic": "", |
|
"url": "uib-dynamic-svg-eg", |
|
"fwdInMessages": false, |
|
"allowScripts": false, |
|
"allowStyles": false, |
|
"copyIndex": true, |
|
"templateFolder": "blank", |
|
"extTemplate": "", |
|
"showfolder": false, |
|
"reload": true, |
|
"sourceFolder": "src", |
|
"deployedVersion": "6.4.1", |
|
"showMsgUib": true, |
|
"x": 620, |
|
"y": 240, |
|
"wires": [ |
|
[ |
|
"95af327f377fa565" |
|
], |
|
[ |
|
"5f6a472f6435e598" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "68208d9442bc03c1", |
|
"type": "debug", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Std output", |
|
"active": true, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": true, |
|
"complete": "true", |
|
"targetType": "full", |
|
"statusVal": "", |
|
"statusType": "counter", |
|
"x": 1005, |
|
"y": 300, |
|
"wires": [], |
|
"l": false |
|
}, |
|
{ |
|
"id": "5f6a472f6435e598", |
|
"type": "debug", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Ctrl output", |
|
"active": false, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": true, |
|
"complete": "true", |
|
"targetType": "full", |
|
"statusVal": "", |
|
"statusType": "counter", |
|
"x": 785, |
|
"y": 300, |
|
"wires": [], |
|
"l": false |
|
}, |
|
{ |
|
"id": "389e05735379ed2e", |
|
"type": "comment", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "uibuilder Dynamic SVG - Vanilla HTML, no framework needed. \\n Updated version of old example that used VueJS \\n Read this comment for details. Requires uibuilder v6.1 or above", |
|
"info": "This example demonstrates how to use uibuilder\nwith SVG images to create a dynamic home\nlighting dashboard.\n\nUse a background-image (see index.css) and\nthen clone the included \"bulb\" SVG \n(see index.html `<template>`) and change the\nproperties of each bulb using uibuilder's \nreduced-code functions. Colours, size, position,\netc are all controlled by CSS classes.\n\n## To use the example\n\nAs always deploy your flow after adding a\nuibuilder node, making sure the url setting \nis unique.\n\nThen update the `index.html`, `index.js` and \n`index.css` files with the code provided.\n\nOpen the resulting page and play with\ncontrolling from Node-RED and try clicking\non the bulb symbols on the page to see \nhow all the interactions work.\n\nThis example demonstrates a hybrid way of \nworking with uibuilder to create web pages.\n\nThere is some code and some Node-RED flow.\n\nHopefully, this illustrates how a little code \ncan go a long way and that you are not \nconstrained to use just one approach but can \nmix and match as desired.", |
|
"x": 430, |
|
"y": 160, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "db89d982a40f6c4d", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Toggle Visible Msgs", |
|
"props": [ |
|
{ |
|
"p": "_uib", |
|
"v": "{\"command\":\"showMsg\"}", |
|
"vt": "json" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "", |
|
"x": 290, |
|
"y": 300, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "3feb6c0d7c1c07b2", |
|
"type": "debug", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Std output", |
|
"active": true, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": true, |
|
"complete": "true", |
|
"targetType": "full", |
|
"statusVal": "", |
|
"statusType": "counter", |
|
"x": 1085, |
|
"y": 180, |
|
"wires": [], |
|
"l": false |
|
}, |
|
{ |
|
"id": "8ce7dd9a5d97b83b", |
|
"type": "link in", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "link in 10", |
|
"links": [ |
|
"a4fb2160fb46d36c", |
|
"06fa35d1c6063d4c" |
|
], |
|
"x": 485, |
|
"y": 240, |
|
"wires": [ |
|
[ |
|
"18b02b8e78a54427" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "06fa35d1c6063d4c", |
|
"type": "link out", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "link out 35", |
|
"mode": "link", |
|
"links": [ |
|
"8ce7dd9a5d97b83b" |
|
], |
|
"x": 565, |
|
"y": 360, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "891a5f86c7c89917", |
|
"type": "group", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Control lights from Node-RED", |
|
"style": { |
|
"fill": "#ffbfbf", |
|
"fill-opacity": "0.23", |
|
"label": true, |
|
"color": "#000000" |
|
}, |
|
"nodes": [ |
|
"ad6de73ba713120d", |
|
"b2b85b92b1cf7da5", |
|
"77193b09f79ec310", |
|
"4c9d8f9adc268c35", |
|
"f86567acf2326bad", |
|
"36595c40107736a2" |
|
], |
|
"x": 154, |
|
"y": 339, |
|
"w": 302, |
|
"h": 242 |
|
}, |
|
{ |
|
"id": "ad6de73ba713120d", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "LIGHTS (random)", |
|
"props": [ |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "LIGHTS", |
|
"x": 290, |
|
"y": 380, |
|
"wires": [ |
|
[ |
|
"b2b85b92b1cf7da5" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "b2b85b92b1cf7da5", |
|
"type": "change", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "Randomly turn on/off all bulbs", |
|
"rules": [ |
|
{ |
|
"t": "set", |
|
"p": "_ui", |
|
"pt": "msg", |
|
"to": "(\t /* Generate a true/false for each bulb */\t $b1 := $random() >= 0.5;\t $b2 := $random() >= 0.5;\t $b3 := $random() >= 0.5;\t $b4 := $random() >= 0.5;\t /* Apply to msg._ui to randomly update all bulbs */\t [\t {\t \"method\":\"update\",\t \"components\": [\t {\t \"id\":\"bulb1\",\t \"attributes\": {\t /* NB: Give this one a different colour to the others */\t \"class\":\"bulb posn1 \" & ($b1 ? \"bulb-fail\" : \"\"),\t /* We use a data attribute to make it easier to track on/off state */\t \"data-state\": ($b1 ? \"on\" : \"off\")\t }\t }\t ]\t },\t {\t \"method\":\"update\",\t \"components\": [\t {\t \"id\":\"bulb2\",\t \"attributes\": {\t \"class\":\"bulb posn2 \" & ($b2 ? \"bulb-warn\" : \"\"),\t \"data-state\": ($b2 ? \"on\" : \"off\")\t }\t }\t ]\t },\t {\t \"method\":\"update\",\t \"components\": [\t {\t \"id\":\"bulb3\",\t \"attributes\": {\t \"class\":\"bulb posn3 \" & ($b3 ? \"bulb-warn\" : \"\"),\t \"data-state\": ($b3 ? \"on\" : \"off\")\t }\t }\t ]\t },\t {\t \"method\":\"update\",\t \"components\": [\t {\t \"id\":\"bulb4\",\t \"attributes\": {\t \"class\":\"bulb posn4 \" & ($b4 ? \"bulb-warn\" : \"\"),\t \"data-state\": ($b4 ? \"on\" : \"off\")\t }\t }\t ]\t }\t ]\t)", |
|
"tot": "jsonata" |
|
} |
|
], |
|
"action": "", |
|
"property": "", |
|
"from": "", |
|
"to": "", |
|
"reg": false, |
|
"x": 415, |
|
"y": 380, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
], |
|
"l": false |
|
}, |
|
{ |
|
"id": "77193b09f79ec310", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "LIGHT 1 on", |
|
"props": [ |
|
{ |
|
"p": "_ui", |
|
"v": "[{\"method\":\"update\",\"components\":[{\"id\":\"bulb1\",\"attributes\":{\"class\":\"bulb posn1 bulb-fail\",\"data-state\":\"on\"}}]}]", |
|
"vt": "json" |
|
}, |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "LIGHT-1", |
|
"x": 310, |
|
"y": 420, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "4c9d8f9adc268c35", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "LIGHT 1 off", |
|
"props": [ |
|
{ |
|
"p": "_ui", |
|
"v": "[{\"method\":\"update\",\"components\":[{\"id\":\"bulb1\",\"attributes\":{\"class\":\"bulb posn1\",\"data-state\":\"off\"}}]}]", |
|
"vt": "json" |
|
}, |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "LIGHT-1", |
|
"x": 310, |
|
"y": 460, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f86567acf2326bad", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "LIGHT 2 on", |
|
"props": [ |
|
{ |
|
"p": "_ui", |
|
"v": "[{\"method\":\"update\",\"components\":[{\"id\":\"bulb2\",\"attributes\":{\"class\":\"bulb posn2 bulb-warn\",\"data-state\":\"on\"}}]}]", |
|
"vt": "json" |
|
}, |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "LIGHT-2", |
|
"x": 310, |
|
"y": 500, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "36595c40107736a2", |
|
"type": "inject", |
|
"z": "278e7d113ed09433", |
|
"g": "891a5f86c7c89917", |
|
"name": "LIGHT 2 off", |
|
"props": [ |
|
{ |
|
"p": "_ui", |
|
"v": "[{\"method\":\"update\",\"components\":[{\"id\":\"bulb2\",\"attributes\":{\"class\":\"bulb posn2\",\"data-state\":\"off\"}}]}]", |
|
"vt": "json" |
|
}, |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": false, |
|
"onceDelay": 0.1, |
|
"topic": "LIGHT-2", |
|
"x": 310, |
|
"y": 540, |
|
"wires": [ |
|
[ |
|
"06fa35d1c6063d4c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "3939b0bbde991557", |
|
"type": "group", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "User clicks turn on/off", |
|
"style": { |
|
"fill": "#e3f3d3", |
|
"fill-opacity": "0.26", |
|
"label": true, |
|
"color": "#000000" |
|
}, |
|
"nodes": [ |
|
"95af327f377fa565", |
|
"c3bec95c24885417", |
|
"a4fb2160fb46d36c" |
|
], |
|
"x": 794, |
|
"y": 159, |
|
"w": 252, |
|
"h": 109.5 |
|
}, |
|
{ |
|
"id": "95af327f377fa565", |
|
"type": "switch", |
|
"z": "278e7d113ed09433", |
|
"g": "3939b0bbde991557", |
|
"name": "Switch out bulb clicks", |
|
"property": "payload.state", |
|
"propertyType": "msg", |
|
"rules": [ |
|
{ |
|
"t": "eq", |
|
"v": "on", |
|
"vt": "str" |
|
}, |
|
{ |
|
"t": "eq", |
|
"v": "off", |
|
"vt": "str" |
|
}, |
|
{ |
|
"t": "else" |
|
} |
|
], |
|
"checkall": "false", |
|
"repair": false, |
|
"outputs": 3, |
|
"x": 835, |
|
"y": 220, |
|
"wires": [ |
|
[ |
|
"c3bec95c24885417" |
|
], |
|
[ |
|
"c3bec95c24885417" |
|
], |
|
[ |
|
"68208d9442bc03c1" |
|
] |
|
], |
|
"outputLabels": [ |
|
"A bulb is currently ON", |
|
"A bulb is currently OFF", |
|
"Anything else" |
|
], |
|
"l": false |
|
}, |
|
{ |
|
"id": "c3bec95c24885417", |
|
"type": "change", |
|
"z": "278e7d113ed09433", |
|
"g": "3939b0bbde991557", |
|
"name": "Toggle clicked bulb state", |
|
"rules": [ |
|
{ |
|
"t": "set", |
|
"p": "_ui", |
|
"pt": "msg", |
|
"to": "(\t [\t {\t \"method\":\"update\",\t \"components\":[\t {\t \"id\": _ui.id,\t \"attributes\":{\t /* Toggle fill colour */\t \"class\":\"bulb \" & payload.posn & \" \" & (payload.state = \"off\" ? \"bulb-warn\" : \"\"),\t /* Toggle state */\t \"data-state\": (payload.state = \"on\" ? \"off\" : \"on\")\t }\t }\t ]\t }\t]\t)", |
|
"tot": "jsonata" |
|
} |
|
], |
|
"action": "", |
|
"property": "", |
|
"from": "", |
|
"to": "", |
|
"reg": false, |
|
"x": 905, |
|
"y": 200, |
|
"wires": [ |
|
[ |
|
"3feb6c0d7c1c07b2", |
|
"a4fb2160fb46d36c" |
|
] |
|
], |
|
"l": false |
|
}, |
|
{ |
|
"id": "a4fb2160fb46d36c", |
|
"type": "link out", |
|
"z": "278e7d113ed09433", |
|
"g": "3939b0bbde991557", |
|
"name": "link out 34", |
|
"mode": "link", |
|
"links": [ |
|
"8ce7dd9a5d97b83b" |
|
], |
|
"x": 1005, |
|
"y": 220, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "2e40ef6c2172741a", |
|
"type": "group", |
|
"z": "278e7d113ed09433", |
|
"g": "1678f3c7ab967e39", |
|
"name": "Copy these to the \\n appropriate files \\n ", |
|
"style": { |
|
"fill": "#ffffbf", |
|
"fill-opacity": "0.15", |
|
"label": true, |
|
"color": "#000000", |
|
"label-position": "n" |
|
}, |
|
"nodes": [ |
|
"fbe4c7573f698409", |
|
"4ca9ba62878dbad8", |
|
"83f5b29fe8ebb1d7", |
|
"5dce296a96d3f95e" |
|
], |
|
"x": 654, |
|
"y": 367, |
|
"w": 212, |
|
"h": 234 |
|
}, |
|
{ |
|
"id": "fbe4c7573f698409", |
|
"type": "comment", |
|
"z": "278e7d113ed09433", |
|
"g": "2e40ef6c2172741a", |
|
"name": "index.html", |
|
"info": "<!doctype html>\n<html lang=\"en\"><head>\n\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n <title>Dynamic SVG Example - Node-RED uibuilder</title>\n <meta name=\"description\" content=\"Node-RED uibuilder - Dynamic SVG Example\">\n\n <!-- Your own CSS (defaults to loading uibuilders css)-->\n <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->\n <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n <script defer src=\"./index.js\">/* custom code */</script>\n <!-- #endregion -->\n\n</head><body class=\"uib\">\n <template id=\"bulb-template\">\n <svg id=\"mybulb\" class=\"bulb\" height=\"3rem\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <filter id=\"shadow\">\n <feDropShadow dx=\"1\" dy=\"1\" stdDeviation=\"5\" flood-opacity=\"50%\" />\n </filter>\n <filter id=\"glow\" filterUnits=\"userSpaceOnUse\"\n x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <!-- blur the text at different levels-->\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"5\" result=\"blur5\"/>\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"10\" result=\"blur10\"/>\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"20\" result=\"blur20\"/>\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"30\" result=\"blur30\"/>\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"50\" result=\"blur50\"/>\n <!-- merge all the blurs except for the first one -->\n <feMerge result=\"blur-merged\">\n <feMergeNode in=\"blur10\"/>\n <feMergeNode in=\"blur20\"/>\n <feMergeNode in=\"blur30\"/>\n <feMergeNode in=\"blur50\"/>\n </feMerge>\n <!-- recolour the merged blurs red-->\n <feColorMatrix result=\"red-blur\" in=\"blur-merged\" type=\"matrix\"\n values=\"1 0 0 0 0\n 0 0.06 0 0 0\n 0 0 0.44 0 0\n 0 0 0 1 0\" />\n <feMerge>\n <!--<feMergeNode in=\"red-blur\"/> largest blurs coloured red -->\n <feMergeNode in=\"blur-merged\"/>\n <feMergeNode in=\"blur5\"/> <!-- smallest blur left white -->\n <feMergeNode in=\"SourceGraphic\"/> <!-- original -->\n </feMerge>\n </filter>\n </defs>\n <title>TITLE</title>\n <path name=\"icon\" d=\"M511.549861 803.293331H408.419043a73.232959 73.232959 0 0 1-67.1862-41.991375 59.795719 59.795719 0 0 1-6.71862-30.569722 207.60536 207.60536 0 0 0-33.593101-113.88061 196.519637 196.519637 0 0 0-27.882273-33.5931A463.248853 463.248853 0 0 1 217.274302 504.314738a399.086031 399.086031 0 0 1-36.95241-75.248544 242.542184 242.542184 0 0 1-15.116895-77.264131 349.032312 349.032312 0 0 1 8.062344-84.990544 314.76735 314.76735 0 0 1 51.733375-114.888403A367.172586 367.172586 0 0 1 361.724634 34.011334 327.532728 327.532728 0 0 1 433.949799 8.144647 369.524103 369.524103 0 0 1 528.682342 0.418234a333.579486 333.579486 0 0 1 126.310057 29.225997 326.860866 326.860866 0 0 1 70.881442 44.678824A382.625412 382.625412 0 0 1 808.848799 168.383736a314.095488 314.095488 0 0 1 41.991375 105.146403 312.751764 312.751764 0 0 1 6.382689 92.045095 275.799353 275.799353 0 0 1-20.15586 76.256338 449.139751 449.139751 0 0 1-61.139443 107.16199 497.513815 497.513815 0 0 1-33.5931 39.639858 160.575019 160.575019 0 0 0-31.241583 48.038134 215.331773 215.331773 0 0 0-18.812136 55.428615c-1.679655 11.757585 0 23.179239-2.687448 33.5931a171.660742 171.660742 0 0 1-3.695241 25.194826 69.873649 69.873649 0 0 1-33.593101 40.647651 74.576683 74.576683 0 0 1-39.639858 10.07793zM490.050277 88.768088c-11.085723 0-22.171446 2.351517-33.5931 4.031172a210.96467 210.96467 0 0 0-74.240752 26.538549 244.221839 244.221839 0 0 0-55.428616 44.342893 222.386324 222.386324 0 0 0-43.335099 63.82689 230.784599 230.784599 0 0 0-19.483998 94.732543 28.218204 28.218204 0 0 0 33.5931 28.890066 28.890066 28.890066 0 0 0 22.171446-26.202618v-13.773171a167.965501 167.965501 0 0 1 9.406068-49.045927 184.762052 184.762052 0 0 1 64.834684-83.98275 167.965501 167.965501 0 0 1 93.72475-33.593101 142.770676 142.770676 0 0 0 18.140274 0 23.851101 23.851101 0 0 0 19.148067-15.452826 33.5931 33.5931 0 0 0 0-19.483998 23.51517 23.51517 0 0 0-20.491791-18.140274 122.950747 122.950747 0 0 0-15.116895 0zM647.601917 943.040628a15.788757 15.788757 0 0 1-13.773171 15.116895H400.356699a17.468412 17.468412 0 0 1-16.460619-8.734206 18.812136 18.812136 0 0 1 0-20.15586 16.124688 16.124688 0 0 1 16.460619-4.703034h227.089358a19.148067 19.148067 0 0 1 19.148067 20.827722zM405.731595 899.369598a18.140274 18.140274 0 0 1-16.460619-12.765378 17.804343 17.804343 0 0 1 15.452826-23.851101H635.508401a18.812136 18.812136 0 0 1 17.804343 13.773171 19.819929 19.819929 0 0 1-10.749792 21.499584 24.187032 24.187032 0 0 1-8.734206 0H423.535938zM437.64504 1022.992207a17.132481 17.132481 0 0 1-15.452826-9.406068 18.140274 18.140274 0 0 1 15.116895-26.202618h139.411367a19.819929 19.819929 0 0 1 19.483998 17.804343 16.124688 16.124688 0 0 1-8.734206 15.788757 19.148067 19.148067 0 0 1-9.741999 3.023379H442.348074z\" />\n <!-- <circle name=\"default\" cx=\"50\" cy=\"50\" r=\"50\"></circle> -->\n </svg>\n </template>\n \n <h1 class=\"with-subtitle\">Dynamic SVG Example</h1>\n <div role=\"doc-subtitle\">Using the uibuilder IIFE library.</div>\n <p>\n This is a uibuilder example looking at how easy it is to create a dynamic view of IoT devices in a building\n using SVG images both for the background (floor-plan) and device indicators.\n </p>\n\n <div id=\"more\"><!-- '#more' is used as a parent for dynamic HTML content in examples --></div>\n\n <h2>My House, Ground Floor</h2>\n <div id=\"floorplan\" class=\"plan\"><!-- Bulb icons dynamically inserted here --></div>\n\n</body></html>\n", |
|
"x": 740, |
|
"y": 440, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "4ca9ba62878dbad8", |
|
"type": "comment", |
|
"z": "278e7d113ed09433", |
|
"g": "2e40ef6c2172741a", |
|
"name": "index.css", |
|
"info": "/* Load defaults from `<userDir>/node_modules/node-red-contrib-uibuilder/front-end/uib-brand.css`\n * This version auto-adjusts for light/dark browser settings but might not be as complete.\n */\n@import url(\"../uibuilder/uib-brand.css\");\n\n/* These variables build on existing variables in uib-brand.css\n * They will be incorporated into that file in uibuilder v6.2\n */\n:root {\n --warning-intense: hsl(\n var(--warning-hue) 100% 50%\n );\n --failure-intense: hsl(\n var(--failure-hue) 100% 50%\n );\n --surface5: hsl( /* additional background shade */\n var(--brand-hue)\n calc(100% * var(--surfaces-saturation))\n calc(\n 100% * (var(--surfaces-lightness)\n - (var(--surfaces-factor) * .20)\n + (var(--surfaces-factor) * var(--surfaces-bias)))\n )\n );\n}\n\n\n/* Bulb classes control look, colour and position */\n\n.bulb { /* Default \"off\" class plus standard style */\n z-index: 9999 !important; /* Bulbs HAVE to be in the top z-layer */\n cursor: pointer; \n position: absolute; /* allows exact positioning within the parent div */\n transition: filter 2s ease-in-out 0s;\n background-color: rgba(0, 0, 0, 0.001); /* transparent background */\n filter: url(\"#shadow\"); /* selects the shadow filter */\n}\n.bulb path {\n fill: grey;\n}\n\n.bulb-warn { /* Standard \"on\" class */\n filter: url('#glow'); /* selects the glow filter instead of shadow */\n}\n.bulb-warn path {\n fill: var(--warning-intense);\n}\n\n.bulb-fail { /* Alternative \"on\" class with different colour */\n filter: url('#glow');\n}\n.bulb-fail path {\n fill: var(--failure-intense);\n}\n\n/* Bulb position classes, change as needed\n * Positions are relative to the parent floorplan div\n */\n.posn1 {\n top: 100px; left: 100px; \n}\n.posn2 {\n top: 120px; left: 270px; \n}\n.posn3 {\n top: 120px; left: 650px; \n}\n.posn4 {\n top: 270px; left: 250px; \n}\n\n/* floorplan div class change anything\n * except the position:relative.\n * The background image location is relative\n * to your uibuilder front-end files.\n */\n.plan {\n position:relative; \n width:99%; height:30rem; \n background:url(\"./background.svg\");\n background-color: var(--surface5);\n}\n", |
|
"x": 740, |
|
"y": 480, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "83f5b29fe8ebb1d7", |
|
"type": "comment", |
|
"z": "278e7d113ed09433", |
|
"g": "2e40ef6c2172741a", |
|
"name": "index.js", |
|
"info": "// @ts-nocheck\n/** Dynamic SVG example */\n\n// uibuilder.logLevel = 1\n\n/** A clone of the uibuilder $ function so you don't have to install v6.2-dev\n * Simplistic jQuery-like document CSS query selector, returns an HTML Element\n * If the selected element is a <template>, returns the first child element.\n * type {HTMLElement}\n * @param {string} cssSelector A CSS Selector that identifies the element to return\n * @returns {HTMLElement|HTMLTemplateElement|null}\n */\nfunction mySelector(cssSelector) {\n let el = document.querySelector(cssSelector)\n\n if (!el) {\n log(1, 'mySelector', `No element found for CSS selector ${cssSelector}`)()\n return null\n }\n\n if (el.nodeName === 'TEMPLATE') {\n el = el.content.firstElementChild\n if (!el) {\n log(0, 'mySelector', `Template selected for CSS selector ${cssSelector} but it is empty`)()\n return null\n }\n }\n\n return el\n}\n\nfunction doMe(event) {\n uibuilder.eventSend(event)\n}\n\n/** Insert a clone of a template tag\n * NB: Template should have only a single direct child tag, nothing other than that tag and its contents will be cloned.\n * @param {HTMLTemplateElement} template The template to clone and insert\n * @param {HTMLElement} parent The parent within which to insert the clone\n * @param {object} [ui] Optional uib UI object that will apply changes to the cloned element (e.g. attribs, slot)\n */\nfunction htmlClone(template, parent, ui) {\n console.log(ui)\n if (!template || !(template instanceof Element)) {\n console.error('Template HTMLElement not provided or is not an HTML Element')\n return\n }\n if (!parent || !(parent instanceof Element)) {\n console.error('Parent HTMLElement not provided or is not an HTML Element')\n return\n }\n if (!ui) ui = {}\n if (!ui.position) ui.position = 'last'\n\n const clone = template.cloneNode(true)\n\n // Oops! Fns starting with `_` should not have been used - sorry. This fn no longer available directly.\n // Will add an equivalent in a future release (post v6.4.1) probably called `uiEnhanceElement`\n // uibuilder._uiComposeComponent(clone, ui)\n clone.id = ui.id\n clone.classList.add(ui.attributes['data-posn'])\n clone.dataset.state = ui.attributes['data-state']\n clone.dataset.posn = ui.attributes['data-posn']\n clone.onclick = doMe //uibuilder.eventSend\n\n if (ui.position === 'first') {\n // Insert new el before the first child of the parent. Ref: https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore#example_3\n parent.insertBefore(clone, parent.firstChild)\n } else if (Number.isInteger(Number(ui.position))) {\n elParent.insertBefore(clone, parent.children[ui.position])\n } else {\n // Append to the required parent\n parent.appendChild(clone)\n }\n\n}\nconst x = {\n \"id\": \"bulb1\",\n \"attributes\": {\n \"class\": \"bulb posn1\",\n \"data-state\": \"off\",\n \"data-posn\": \"posn1\"\n },\n \"events\": {\n \"click\": \"uibuilder.eventSend\"\n },\n \"position\": \"last\"\n}\n\n// The Template tag in index.html contains a template \"bulb\" SVG image\n// Here, we clone that multiple times and set some properties.\n// Note that `htmlClone` is a function that will land in the uibuilder client in v6.2\n// Also, the $ function is improved in v6.2 so a copy of that is included here for convenience.\n//\n// We track state and position class on data-* attributes so that it is much easier to process\n// click events in Node-RED without having to create a custom click handler, we can just use the standard eventSend.\n// CSS classes do all the clever stuff 😁\n\nhtmlClone($('#bulb-template'), $('#floorplan'), {\n // As always, we set a unique ID for every created element so it can be updated easily later\n id: 'bulb1',\n // You only need this if you want to choose 'first' or a position number,\n // the clone will be added at the specified child position of the parent.\n // position: 'last', \n attributes: {\n // Apply base bulb class and a positioning class\n class: 'bulb posn1',\n // Track the on/off state separately - makes processing in Node-RED easier\n 'data-state': 'off',\n // Track the position class separately - makes processing in Node-RED easier\n 'data-posn': 'posn1'\n },\n // We have to add event handlers after a clone, they cannot be included in the template\n events: {\n click: 'uibuilder.eventSend'\n }\n})\n\nhtmlClone(mySelector('#bulb-template'), mySelector('#floorplan'), {\n id: 'bulb2',\n attributes: {\n class: 'bulb posn2',\n 'data-state': 'off',\n 'data-posn': 'posn2'\n },\n events: {\n click: 'uibuilder.eventSend'\n }\n})\n\nhtmlClone(mySelector('#bulb-template'), mySelector('#floorplan'), {\n id: 'bulb3',\n attributes: {\n class: 'bulb posn3',\n 'data-state': 'off',\n 'data-posn': 'posn3'\n },\n events: {\n click: 'uibuilder.eventSend'\n }\n})\n\nhtmlClone(mySelector('#bulb-template'), mySelector('#floorplan'), {\n id: 'bulb4',\n attributes: {\n class: 'bulb posn4',\n 'data-state': 'off',\n 'data-posn': 'posn4'\n },\n events: {\n click: 'uibuilder.eventSend'\n },\n})\n", |
|
"x": 730, |
|
"y": 520, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "5dce296a96d3f95e", |
|
"type": "comment", |
|
"z": "278e7d113ed09433", |
|
"g": "2e40ef6c2172741a", |
|
"name": "background.svg", |
|
"info": "Can't include this directly here otherwise\nthe flow cannot be posted to the forum.\n\nThe example background file can be obtained\nhere:\n\nhttps://gist.github.com/TotallyInformation/02eb3716157db586f3f5b8a85c241009#file-background-svg\n\nCopy the text out of it and paste into a new \nfile, `background1.svg` in the same location \nas your `index.html` file.\n", |
|
"x": 760, |
|
"y": 560, |
|
"wires": [] |
|
} |
|
] |
Hi Julian,
Nice work! I'm trying to duplicate, but I'm having trouble with showing the background. Could you elaborate about what to do with background.svg? All I'm seeing is the lamps, which i can turn on and off (see picture below).