As promised, a little example how to achieve it using default set nodes ("node_red_dashboard" is needed).
Feel free to use and modify it by your needs. The colors I used look fine on medium gray background.
I separated configuring part from data preparing part into different functions just for clarity of example.
Parameters can be configured using Change node also
You can get rid of shadows by just deleting the filter
properties in ui_template Shadows harm rendering for sure and not recommended for performance critical situations.
I added comments about basic stuff, I hope it makes this thing kind of clear.
[{"id":"66684c36.a1fb94","type":"inject","z":"828c92a8.6bb45","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"onceDelay":0.1,"x":370,"y":280,"wires":[["fdc73f50.1ac08"]]},{"id":"fdc73f50.1ac08","type":"function","z":"828c92a8.6bb45","name":"Generate some data","func":"var lastupdate = global.get(\"lastupdate\") || 0;\nif(lastupdate++ > 99){\n lastupdate = 0;\n}\nglobal.set(\"lastupdate\",lastupdate);\nmsg.payload = lastupdate\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":280,"wires":[["313749d2.75fae6","818a6bf4.ddc6e8","4be2825.29c377c","85ebd007.f2145","c096a17b.058b7","5769d1e9.05358","b7f58518.7e0968"]]},{"id":"ae422917.1413b8","type":"ui_template","z":"828c92a8.6bb45","group":"2accfba2.147474","name":"svg level vertical 2x3","order":2,"width":"2","height":"3","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n x=\"0\" \n ng:attr:y=\"{{$index * 4}}px\"\n width=\"12\" \n height=\"2\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-ver-value\"\n text-anchor=\"middle\" alignment-baseline=\"middle\"\n x=55%\n y=50%>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=15\n ng:attr:y={{msg.minpos}}>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"hanging\"\n x=15\n y=1 >\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1130,"y":320,"wires":[[]]},{"id":"81337426.09e378","type":"ui_template","z":"828c92a8.6bb45","group":"e19b4f66.fbbeb","name":"svg level horizontal 2x1","order":4,"width":"2","height":"1","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n y=80% \n ng:attr:x=\"{{$index * 4}}px\"\n width=\"2\"\n height=\"6\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-hor-value\"\n text-anchor=\"middle\" alignment-baseline=\"hanging\"\n x=50%\n y=0>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=0\n y=85%>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"end\" alignment-baseline=\"ideographic\"\n x=100%\n y=85%>\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1140,"y":480,"wires":[[]]},{"id":"3d2df1f1.8c42fe","type":"ui_template","z":"828c92a8.6bb45","group":"efcad470.381fb8","name":"Custom element style","order":0,"width":0,"height":0,"format":"<style>\n #level-hor-value {\n font-size: 1.4em;\n fill:#d0d0d0;\n }\n #level-minmax {\n font-size: 60%;\n fill:#d0d0d0;\n }\n #level-3x3-stripe {\n fill: #404040;\n }\n #level-ver-value {\n font-size: 1.8em;\n fill:#d0d0d0;\n }\n #chart-hour {\n font-size: 60%;\n fill:#d0d0d0;\n }\n #chart-stripe {\n fill: #404040;\n }\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":850,"y":180,"wires":[[]]},{"id":"76e613ef.e1bb0c","type":"inject","z":"828c92a8.6bb45","name":"init","topic":"init","payload":"create","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":430,"y":180,"wires":[["8961d767.2bad38"]]},{"id":"8961d767.2bad38","type":"function","z":"828c92a8.6bb45","name":"set site properties","func":"var unit = {\"h\":48,w:48}; // site sizes 1x1 wdget size\nvar colormap = {on:\"#47d147\",off:\"dimgrey\",warn:\"#ff9933\", high:\"#ff5c33\"} // green, gray, orange, red \nvar site = {\"unit\":unit,\"widgetcolors\":colormap}; //merge to store to global as one variable\nglobal.set(\"site\",site);\nreturn msg;","outputs":1,"noerr":0,"x":610,"y":180,"wires":[[]]},{"id":"c1f35432.aeb748","type":"ui_template","z":"828c92a8.6bb45","group":"2accfba2.147474","name":"svg level vertical 2x4","order":3,"width":"2","height":"4","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n x=\"0\" \n ng:attr:y=\"{{$index * 4}}px\"\n width=\"12\" \n height=\"2\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-ver-value\"\n text-anchor=\"middle\" alignment-baseline=\"middle\"\n x=55%\n y=50%>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=15\n ng:attr:y={{msg.minpos}}>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"hanging\"\n x=15\n y=1 >\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1130,"y":360,"wires":[[]]},{"id":"3978cc74.8f9694","type":"ui_template","z":"828c92a8.6bb45","group":"2accfba2.147474","name":"svg level vertical 2x5","order":4,"width":"2","height":"5","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n x=\"0\" \n ng:attr:y=\"{{$index * 4}}px\"\n width=\"12\" \n height=\"2\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-ver-value\"\n text-anchor=\"middle\" alignment-baseline=\"middle\"\n x=55%\n y=50%>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=15\n ng:attr:y={{msg.minpos}}>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"hanging\"\n x=15\n y=1 >\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1130,"y":400,"wires":[[]]},{"id":"9845d23a.797d6","type":"ui_template","z":"828c92a8.6bb45","group":"2accfba2.147474","name":"svg level vertical 2x2","order":1,"width":"2","height":"2","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n x=\"0\" \n ng:attr:y=\"{{$index * 4}}px\"\n width=\"12\" \n height=\"2\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-ver-value\"\n text-anchor=\"middle\" alignment-baseline=\"middle\"\n x=55%\n y=50%>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=15\n ng:attr:y={{msg.minpos}}>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"hanging\"\n x=15\n y=1 >\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1130,"y":280,"wires":[[]]},{"id":"313749d2.75fae6","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"vertical\"; //widget look\nmsg.units = 2; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":280,"wires":[["7925330e.07bb5c"]]},{"id":"818a6bf4.ddc6e8","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"vertical\"; //widget look\nmsg.units = 3; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":320,"wires":[["136cbf9c.efa6"]]},{"id":"4be2825.29c377c","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"vertical\"; //widget look\nmsg.units = 4; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":360,"wires":[["713cf384.d53dec"]]},{"id":"85ebd007.f2145","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"vertical\"; //widget look\nmsg.units = 5; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":400,"wires":[["1e353951.383ed7"]]},{"id":"c096a17b.058b7","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"horizontal\"; //widget look\nmsg.units = 2; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":480,"wires":[["d8cda4f7.3cf358"]]},{"id":"7925330e.07bb5c","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":280,"wires":[["9845d23a.797d6"]]},{"id":"136cbf9c.efa6","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":320,"wires":[["ae422917.1413b8"]]},{"id":"713cf384.d53dec","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":360,"wires":[["c1f35432.aeb748"]]},{"id":"1e353951.383ed7","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":400,"wires":[["3978cc74.8f9694"]]},{"id":"d8cda4f7.3cf358","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":480,"wires":[["81337426.09e378"]]},{"id":"fb78f9a5.209888","type":"ui_template","z":"828c92a8.6bb45","group":"e19b4f66.fbbeb","name":"svg level horizontal 3x1","order":4,"width":"3","height":"1","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n y=80% \n ng:attr:x=\"{{$index * 4}}px\"\n width=\"2\"\n height=\"6\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-hor-value\"\n text-anchor=\"middle\" alignment-baseline=\"hanging\"\n x=50%\n y=0>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=0\n y=85%>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"end\" alignment-baseline=\"ideographic\"\n x=100%\n y=85%>\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1140,"y":520,"wires":[[]]},{"id":"5769d1e9.05358","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"horizontal\"; //widget look\nmsg.units = 4; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":520,"wires":[["bdd01ad3.6a39c8"]]},{"id":"bdd01ad3.6a39c8","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":520,"wires":[["fb78f9a5.209888"]]},{"id":"f82fcdc6.76ca8","type":"ui_template","z":"828c92a8.6bb45","group":"e19b4f66.fbbeb","name":"svg level horizontal 4x1","order":4,"width":"4","height":"1","format":"<svg width=100% height=100%>\n <defs>\n <filter id=\"level-filter\" x=\"0\" y=\"0\" width=\"200%\" height=\"200%\">\n <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 1 0\" />\n <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"5\" />\n <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n </filter>\n </defs>\n <rect ng-repeat=\"obj in msg.colors track by $index\" \n y=80% \n ng:attr:x=\"{{$index * 4}}px\"\n width=\"2\"\n height=\"6\" \n style=\"fill:{{msg.colors[$index]}}\" filter=\"url(#level-filter)\"\n />\n <text id=\"level-hor-value\"\n text-anchor=\"middle\" alignment-baseline=\"hanging\"\n x=50%\n y=0>\n {{msg.value}}{{msg.valuesuffix}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"start\" alignment-baseline=\"ideographic\"\n x=0\n y=85%>\n {{msg.min}}\n </text>\n <text id=\"level-minmax\"\n text-anchor=\"end\" alignment-baseline=\"ideographic\"\n x=100%\n y=85%>\n {{msg.max}}\n </text>\n</svg> ","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1140,"y":560,"wires":[[]]},{"id":"b7f58518.7e0968","type":"function","z":"828c92a8.6bb45","name":"Configure","func":"msg.value = msg.payload; //expected to be a number\nmsg.min = 0; //expected minimum value of incoming data\nmsg.max = 100; //expected maximum value of incoming data\nmsg.valuesuffix = \"%\" //kind of data \nmsg.direction = \"horizontal\"; //widget look\nmsg.units = 4; //how many units widget takes in direction \n\nreturn msg;","outputs":1,"noerr":0,"x":820,"y":560,"wires":[["80d29778.56a648"]]},{"id":"80d29778.56a648","type":"function","z":"828c92a8.6bb45","name":"Generate","func":"//drawing of stripes will be done on exact pixels to avoid blur\n//calculated count of stripes will not fill 100% of area.\n\n\n// get global variables\nvar unit = global.get(\"site\").unit.h;\nvar colormap = global.get(\"site\").widgetcolors;\n// declare local variables\nvar c;\nvar colors = [];\n\n// how many stripes should be drawn according to calculated widget size\nvar count = Math.floor(unit * msg.units / 4) - 2; \n\n// parameters for range incoming values into size of widget\nvar params = {minin:msg.min, maxin:msg.max+1, minout:0, maxout:count};\n\n// range\nfunction range(n,params){\n var divisor = params.maxin - params.minin;\n n = ((n - params.minin) % divisor + divisor) % divisor + params.minin;\n n = ((n - params.minin) / (params.maxin - params.minin) * (params.maxout - params.minout)) + params.minout;\n return n;\n}\nvar rangedvalue = Math.round(range(msg.value,params));\n\n// determine color for each stripe\nfor(var i=0; i<count; i++){\n c = rangedvalue <= i ? colormap.off : ( i < (count-5) ? colormap.on : ( i < (count-2) ? colormap.warn : colormap.high));\n colors.push(c);\n}\n//vertical starts drawing from top. colors needed to be in reverse order \nif(msg.direction === \"vertical\"){\n colors.reverse();\n}\n\n// set msg parameters\nmsg.colors = colors;\n\n// for vertical, the last stripe will not be at the bottom exactly.\n// for adjusting min value position.\nmsg.minpos = count*4; \nreturn msg;","outputs":1,"noerr":0,"x":960,"y":560,"wires":[["f82fcdc6.76ca8"]]},{"id":"2accfba2.147474","type":"ui_group","z":"","name":"VERITCAL","tab":"ee954aaa.1cbb18","order":2,"disp":true,"width":"8","collapse":false},{"id":"e19b4f66.fbbeb","type":"ui_group","z":"","name":"HORIZONTAL","tab":"ee954aaa.1cbb18","disp":true,"width":"6","collapse":false},{"id":"efcad470.381fb8","type":"ui_group","z":"","name":"SITE","tab":"b5e9809.d91cc8","disp":true,"width":"6","collapse":false},{"id":"ee954aaa.1cbb18","type":"ui_tab","z":"","name":"WIDGETS","icon":"dashboard","order":1},{"id":"b5e9809.d91cc8","type":"ui_tab","z":"","name":"MAIN","icon":"dashboard","order":1}]