Having fun with SVG - playing with light sources

Hi folks,

A HAPPY NEW YEAR to the entire community!! :champagne: :champagne: :champagne:

While the wife and kids were still sleeping, I sneaked downstairs to experiment with light sources in SVG. Not sure whether this is called dedication, or just me being pathetic :rofl:

With this simple flow:

image

[{"id":"4a7aaca8.bd6084","type":"ui_svg_graphics","z":"7f1827bd.8acfe8","group":"7185c2fb.c66bbc","order":0,"width":"12","height":"12","svgString":"<div class=\"contain-demo\">  \n  <svg width=\"100%\" height=\"100%\" viewBox=\"0 0 250 250\" enable-background=\"new 0 0 250 250\">\n    <defs>\n      <!--The default filter region is x=-10% y=-10% width=120% height=120%-->\n      <!--Which need to be shrinked to clip the filter at the room boundaries-->\n      <filter id=\"green_light\" x=\"0%\" y=\"0%\" width=\"100%\" height=\"100%\">\n        <feGaussianBlur in = \"SourceAlpha\" stdDeviation=\"1\" result=\"blur1\" />\n        <feSpecularLighting result=\"specOut\" in=\"blur1\" specularExponent=\"30\"  lighting-color=\"#00cc00\" >\n            <fePointLight x=\"141\" y=\"73\" z=\"80\" />\n        </feSpecularLighting>\n      </filter>\n    </defs>\n    \n    <image width=\"100%\" height=\"100%\" id=\"background\" xlink:href=\"https://www.roomsketcher.com/wp-content/uploads/2016/10/1-Bedroom-Floor-Plans.jpg\" />\n\n    <rect id=\"rect_living\" x=\"80\" y=\"30\" width=\"123\" height=\"86\" fill=\"black\" fill-opacity=\"0.1\" filter=\"\"/>\n    <text id=\"light_living\" x=\"141\" y=\"73\" font-family=\"FontAwesome\" fill=\"green\" stroke=\"darkgreen\" font-size=\"25\" text-anchor=\"middle\" alignment-baseline=\"middle\" stroke-width=\"1\">fa-lightbulb-o</text>\n  </svg>\n</div>","clickableShapes":[{"targetId":"#light_living","action":"click","payload":"light_living","payloadType":"str","topic":"light_living"}],"javascriptHandlers":[],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":false,"showBrowserErrors":true,"showBrowserEvents":false,"enableJsDebugging":false,"sendMsgWhenLoaded":false,"outputField":"payload","editorUrl":"//drawsvg.org/drawsvg.html","directory":"","panning":"disabled","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"dblClickZoomPercentage":150,"name":"","x":680,"y":2400,"wires":[["e4f8bd1d.95b4a"]]},{"id":"e4f8bd1d.95b4a","type":"link out","z":"7f1827bd.8acfe8","name":"SVG output msg","links":["b5e846dd.ae7e88"],"x":815,"y":2400,"wires":[]},{"id":"b5e846dd.ae7e88","type":"link in","z":"7f1827bd.8acfe8","name":"","links":["e4f8bd1d.95b4a"],"x":95,"y":2400,"wires":[["9327a30d.6d2f2"]]},{"id":"6000cdf2.42d564","type":"change","z":"7f1827bd.8acfe8","name":"Update filter attribute","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t\"command\": \"set_attribute\",\t\"selector\": \"#rect_living\",\t\"attributeName\": \"filter\",\t\"attributeValue\": payload\t}   ","tot":"jsonata"},{"t":"delete","p":"topic","pt":"msg"},{"t":"delete","p":"event","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":2400,"wires":[["4a7aaca8.bd6084"]]},{"id":"9327a30d.6d2f2","type":"function","z":"7f1827bd.8acfe8","name":"Toggle light state","func":"if (msg.topic === \"light_living\") {\n    var state = flow.get(\"state_light\");\n    \n    node.error(\"old state = \" + state );\n    \n    if (state === \"ON\") {\n        state = \"OFF\";\n        msg.payload = \"\";\n    }\n    else {\n        state = \"ON\";\n        msg.payload = \"url(#green_light)\";\n    }\n    \n    node.error(\"new state = \" + state );\n    \n    flow.set(\"state_light\", state);\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":230,"y":2400,"wires":[["6000cdf2.42d564"]]},{"id":"7185c2fb.c66bbc","type":"ui_group","z":"","name":"SVG light demo","tab":"35f53152.449cde","order":2,"disp":true,"width":"12","collapse":false},{"id":"35f53152.449cde","type":"ui_tab","z":"","name":"Lights","icon":"dashboard","disabled":false,"hidden":false}]

I can show visually which light is ON on my floorplan. I this demo I have used a green LED light:

svg_light_demo

I'm not an SVG expert at all, but would like to spread some basic ideas of the SVG possibilities...
If anybody has a better implementation, please share it with us!!!

In SVG you can define a light source element of different types:

  • feDistantLight defines a distant light source, similar to how the sun lights everything during the day.
  • fePointLight defines a light source that radiates from a single point, similar to how a light bulb lights a room.
  • feSpotLight defines a light source similar to a spot light that shines intensely over a small area.

So I think that for my home automation the fePointLight seems to be the best match to simulate a light bulb.

Then we need to create a filter chain, where the result of a filter will be the input of the next filter.
This is my chain after a bit of trial and error:

<filter id="green_light" x="0%" y="0%" width="100%" height="100%">
   <feGaussianBlur in = "SourceAlpha" stdDeviation="1" result="blur1" />
      <feSpecularLighting result="specOut" in="blur1" specularExponent="30"  lighting-color="#00cc00" >
         <fePointLight x="141" y="73" z="80" />
      </feSpecularLighting>
   </filter>
</defs>

Some details about this:

  • I positioned the light in the middle of my room. Don't know if I can make this relative to the room, because now it is relative to the origin of the SVG, which causes the definition not being reusable for my other rooms...

  • I used feSpecularLighting to apply a colour to my light. In this case I have specified GREEN ("#00cc00").

  • The feGaussianBlur applies some blur.

  • It is important to specify a filter region (x="0%" y="0%" width="100%" height="100%") because the default region (x="-10%" y="-10%" width="120%" height="120%") would cause the filter to be applied also around our room (rectangle):

    image

Since the demo floorplan is a simple image of a floorplan, the light would shine across multiple rooms (not taking into account the walls). To solve that we draw a rectangle above the room contour, and apply the light filter only to that rectangle:

<image width="100%" height="100%" id="background" xlink:href="https://www.roomsketcher.com/wp-content/uploads/2016/10/1-Bedroom-Floor-Plans.jpg" />
<rect id="rect_living" x="80" y="30" width="123" height="86" fill="black" fill-opacity="0.1" filter=""/>

Some details about this:

  • By default I apply an empty filter (i.e. no filter) to this rectangle, because the light is OFF when we start.
  • I set the color to black and opacity to 0.1 to make the room a bit darker (since the light is off by default):

And then in the flow I apply the filter to the rectangle when the light bulb is being clicked.

I hope you like it,
Bart

9 Likes

Happy new year Bart. You literally bring the light to us in these dark times. :grinning: Thanks

3 Likes

Yes, I also make the world again a bit greener :wink:

BTW you can play with the specularExponent to adjust the range of the bulb:

2 Likes

Happy New Year to all the people that hang-out on the Forum.

Bart, there seems to be no limit to your creativity???

Thanks for all your contributions - I'm looking forward to seeing what else you "invent" in 2021.

1 Like

Oh yes, there is: a time limit ...

2 Likes

Bart

Thanks for all your dedication and hard work, it is difficult to keep up with your innovation :grinning:

2 Likes

In my own experiments for Vue/uibuilder, I think that I just stuck with a simple blur around the icon image. This does appear to be going above and beyond the call of duty!

Good stuff though. Just don't let your wife catch you playing with this SVG "p*rn" :rofl:

1 Like

Happy New Year everyone!

Bart, you never cease to amaze me with your ideas and the encouragement of others, including myself. Thank you!!

1 Like

Got a private message of somebody wondering whether it is possible to adjust the "brightness" of the light. From the SVG docs I assume this should be done by adding the following filter to the chain (like e.g. in this tutorial), which plays with the R,G,B channels:

<feComponentTransfer id="brightness" in="specOut">
   <feFuncR type="linear" slope="2"/>
   <feFuncG type="linear" slope="2"/>
   <feFuncB type="linear" slope="2"/>
</feComponentTransfer>

However I don't see any difference :roll_eyes:
Like I said above, I'm not an SVG expert, so most probably I did something wrong ...

Anyway I found somewhere else that it is also possbile to play with the specularConstant, so I added that to my existing filter:

<feSpecularLighting result="specOut" in="blur1" specularConstant="2" specularExponent="50"  lighting-color="#00cc00" >

By default the value is 1, but below you can see the result for some different values:

If anybody can improve this, please be my guest!!!

2 Likes