Announce node-red-contrib-ui-svg : feedback request

Hi folks,

An interactive floorplan is already a long time on top of my TODO list, so I developed an alfa version of node-red-contrib-ui-svg...

It would be nice if you could read the readme documentation, test it and give some 'constructive' feedback. Keep in mind that this is an early alfa version, that I published only to start the discussion!

I have already registered a list of known issues. For most of those issues I will need some input from the community. I'm not going to repeat all information here, but would be nice if somebody could have a look at them. You can put your feedback here (together with a link to the related issue on Github), so everybody can join the discussion.


  • Via this node you can render an SVG drawing on your Node-RED dashboard.
  • You can make SVG elements 'clickable', which means an output message will be created as soon as they are clicked.
  • You can add animations to SVG elements, which can a.o. be triggered via input messages.
  • You can change the SVG element attribute values via input messages.

Short demo of those major functionalities:

[{"id":"dacb48fa.613c18","type":"inject","z":"60ad596.8120ba8","name":"Start animation","topic":"trigger_animation","payload":"{\"elementId\":\"myanimation\",\"status\":\"start\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":660,"y":100,"wires":[["f55be9f2.fa96c8"]]},{"id":"d6e75e72.d2907","type":"inject","z":"60ad596.8120ba8","name":"Stop animation","topic":"trigger_animation","payload":"{\"elementId\":\"myanimation\",\"status\":\"stop\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":660,"y":140,"wires":[["f55be9f2.fa96c8"]]},{"id":"f55be9f2.fa96c8","type":"ui_svg_graphics","z":"60ad596.8120ba8","group":"ba24f321.07795","order":1,"width":"14","height":"10","svgString":"<svg preserveAspectRatio=\"none\" x=\"0\" y=\"0\" viewBox=\"0 0 900 710\" xmlns=\"\" xmlns:svg=\"\" xmlns:xlink=\"\">\n  <image width=\"889\" height=\"703\" id=\"background\" xlink:href=\"\"/>\n  <circle id=\"pir_living\" cx=\"310\" cy=\"45\" r=\"5\" stroke-width=\"0\" fill=\"#FF0000\"/>\n  <text id=\"camera_living\" x=\"310\" y=\"45\" font-family=\"FontAwesome\" fill=\"blue\" stroke=\"black\" font-size=\"35\" text-anchor=\"middle\" alignment-baseline=\"middle\" stroke-width=\"1\"></text>\n</svg>","clickableShapes":[{"targetId":"camera_living"}],"smilAnimations":[{"id":"myanimation","targetId":"pir_living","attributeName":"r","fromValue":"0","toValue":"40","trigger":"msg","duration":"2","repeatCount":"0","freeze":false}],"name":"","x":920,"y":180,"wires":[["143d3982.25d516"]]},{"id":"143d3982.25d516","type":"debug","z":"60ad596.8120ba8","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1090,"y":180,"wires":[]},{"id":"149b89f6.d3d7f6","type":"inject","z":"60ad596.8120ba8","name":"Fill camera icon green","topic":"update_attribute","payload":"{\"elementId\":\"camera_living\",\"attributeName\":\"fill\",\"attributeValue\":\"green\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":680,"y":260,"wires":[["f55be9f2.fa96c8"]]},{"id":"9e4420e1.7bfd7","type":"inject","z":"60ad596.8120ba8","name":"Fill camera icon orange","topic":"update_attribute","payload":"{\"elementId\":\"camera_living\",\"attributeName\":\"fill\",\"attributeValue\":\"orange\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":680,"y":300,"wires":[["f55be9f2.fa96c8"]]},{"id":"bc43666d.7cd0f8","type":"inject","z":"60ad596.8120ba8","name":"Fill camera icon blue","topic":"update_attribute","payload":"{\"elementId\":\"camera_living\",\"attributeName\":\"fill\",\"attributeValue\":\"blue\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":670,"y":220,"wires":[["f55be9f2.fa96c8"]]},{"id":"ba24f321.07795","type":"ui_group","z":"","name":"Floorplan test","tab":"fb3be807.e7ef18","disp":true,"width":"14","collapse":false},{"id":"fb3be807.e7ef18","type":"ui_tab","z":"","name":"SVG","icon":"dashboard","disabled":false,"hidden":false}]

Thanks and have fun (hopefully :thinking:),


Nice work and approach for animations.

Looking at this image:

Wouldn't it be more descriptive to rename topic:"clicked" to event:"clicked"

Same applies to control messages (topic vs action)

Didn’t read carefully enough and posted on the issue first..

Morning @bakman2,
Do you mean a message like this:

"payload": "myCircle",
"event": "clicked"

Or both fields inside the payload:

"payload": {
   "event": "clicked"

I don't mind which one, but users should have an easy way to route my messages through their flow (with minimal amount of extra nodes required)...

Because when an SVG is being clicked, the users could execute all kind of actions in their flow (to respond on the click event):


Hey Lena (@afelix)
No problem, as long as you keep helping me it doesn't matter :wink: As long as you include a link to the Github issue, it is easy for me to keep all issues separated (because the list is still rather long at the moment).

So about sharing widgets between users. Keep in mind that such a widget is not an image, but a group of N svg elements. For example I want to have a floorplan of my garden. As soon as my popup sprinklers are spraying water on my lawn, I want those sprinklers to become animated on my floorplan. If someone creates such a sprinkler widget to have that look and behaviour, it would be nice if I could add it.
Of course we could share them via the wiki of my node, and you just copy paste the widget's SVG string into your editor. But perhaps somebody has a better idea?

Okay brainstorming... depending on how big this node would get, you could build a small registry with an object storage db where the svg sets are saved. That registry should even be able to run on free tier heroku if you wanted to, with the node connecting to the registry, and listing API responses ready for downloading into the local user’s NR install. So that on actual usage it doesn’t have to fall back on the registry just during configuration.
And options to publish your widget creations to that registry as well.

Quick edit: big as in number of users, not big as in content/footprint. So in terms of bandwidth to that registry service.

That makes most sense :slight_smile:

There are number of options to reuse a single group of N svg elements all over the place:

  • The new SVG symbols with own coordinate system (i.e. own viewport)
  • The old SVG definitions
  • ...

But since I want to keep it simple, I think the SVG definitions are the way to go. Otherwise I'm afraid that user will become crazy of all the viewports ...

A simple example of something I was thinking about:

      <g id="sprinkler_widget">
         <!-- Here will be all the N svg elements (incl. 'animate' elements) that can represent and animate a sprinkler -->
    <!-- Let' put the first sprinkler on my floorplan -->
   <use x = "100" y = "100" xlink:href = "#sprinkler_widget"/>

    <!-- And let's put another sprinkler on my floorplan at another location -->
   <use x = "200" y = "150" xlink:href = "#sprinkler_widget"/>

So this way you have 1 sprinkler definition, whick I can (re)use N times at different locations in my SVG drawing. Although I'm not sure whether I can animate them separately: will need to test that if I have time ...

But where does a user needs to find the sprinkler_widget definition?

  • He can search on my Github page for examples and paste them manually in his SVG editor
  • I could add a number of widgets in my node (which people have shared with me), and I insert the definitions automatically when I see that the are 'use'd somewhere ... But what if a user uses an external tool to edit his SVG? Then he doesn't have the definitions, so he cannot create no 'use' elements for them ...

[EDIT 11:54] Perhaps can do it like this:

  1. Users contribute their widget to my node (via pull-request for example)
  2. When you edit the SVG string manually, you can just use it. I will add the definition automatically when I see it is being used. Then only the used definitions are being send to the dashboard afterwards, to reduce connection bandwith...
  3. When you want to edit the SVG string via an editor: I have another Github issue to integrate the SVG-edit editor with this node. In that case I could:
    • automatically include ALL definitions in the SVG string (when I send the string to the editor).
    • so you can use the definitions now in the SVG-edit editor.
    • when you return back to Node-RED, I remove those definitions again from the SVG string (since the definitions that are used will be included automatically afterwards : see point '2')

Amazing! A nice addition to create a management system for home automation & security, really nice

Fantastic work. Looking forward to trying this out.

Regarding click events, how about permitting us to specify a topic and payload where we register the clickable element.

The payload could be a typed input that permits sending of a fixed number/string/bool/JSON and flow/global etc.

So that the output msg would render like this....

 payload: __my_specified_value__

That should reduce the need for change nodes after the switch node and greatly simplify things when triggering mqtt out nodes.

Hope that makes sense.

Hi Walter (@krambriw),
Thanks! I wanted to have something where I can view very quickly what is going on in my house.
One Github issue is about sending the X/Y coordinates in the output message. Then I could create e.g. a node-red-contrib-ui-contextmenu node that shows a popup context menu at the click location. But still lots of work and only few free time left ...

Hi Steve,
I'm not surprised you join this discussion :wink:.
Your proposal surely makes sense to me!
Could add some columns to the clickables table:


When the topic field is left empty, I won't generate a msg.topic field or an emtpy msg.topic field?

Yeah, been waiting for this one since previous discussion :+1:

Hmm, either is good. I was gonna suggest use the id as default topic - thoughts on that?

Thanks for considering this option. I love nodes that minimise the need for extra change nodes after them.

Keep up the fantastic work.

For me that is ok ...

1 Like

So off the top of my head (sorry if this is already possible - still not had time to try it out )

Instead of a tab named "clickable shapes", what about "event registration" where users can chose from click, hover, right click, double click, focus, blur, etc?

Aha, busted!!

Had something like that in my initial version:


But double-click isn't supported in SVG out-of-the-box so I removed the event-column again. Moreover what do you expect at hover/focus/blur? I'm afraid that the flow would be overwhelmed with messages. And when hoovering a shape, I would expect something to happen immediately (e.g. show tooltip), but that is not possible this way (since the round-trip to the Node-RED flow just takes to long). Convince me that I'm wrong :cold_sweat:

I would never :slight_smile:

Ok, point taken. I had hoped double click and right click would be possible (as they could be used for differing actions) but then I got carried away with hover blur etc.

May be better to consider visibility of elements/SVG parts on hover / mouse over (from client side) but configured from node-red side. Not sure how that would be achieved but my thoughts were centered on this use case...
mouse over a camera, a set of clickable tools (hidden svg part) becomes visible below.

For a context menu, I had already considered creating a new context-menu node (see one of the above posts).

However you might have a point, but I think we have to consider extending the 'animations' tabsheet instead of the 'clickable shapes' tabsheet. Currently an animation can be triggered only after N seconds or by an input message:


But looking at the SVG specifications, there are more ways to trigger an animation (e.g. animation to toggle the visibility of a shape when hoovering above another shape). I will not add all options to my dropdown, because e.g. trigger "01:15" can easily be triggered via your crontab-node... And not all browser seem to support all events, although there seems to be a simple way to achieve the same result using pure javascript.

Does it make sense to implement extra animation triggers (for mouse pointer events)?

EDIT: Fixed, upgraded to latest NR and dashboard, now working great!!!

I must have made something wrong? I get the following message when deploying the sample project with the svg graphics node:

2019-08-18 19:21:12node: 387a2130.edc82emsg : error

"TypeError: Cannot read property 'push' of undefined"

Hi Walter, unfortunately I have no 'push' used so it must be under the cover somewhere...

  • Is it when you hit the deploy button?
  • And is there some extra information in the console?
  • Which Node-RED and dashboard version do you have?

[EDIT] I have quickly installed it from scratch on another Node-RED installation, and it seems to be working fine there ...

Push to undefined sounds like an array somewhere that is inaccessible/not existing. Could be in the node, could be in an underlying (sub)library that supplies an array to somewhere. Hard to debug without a line number or a filename of some kind. @krambriw do you have the node red log itself for when this error occurs, not just the output on the debug window? That one should tell the responsible file and line number.

I have implemented on Github issue 9, which allows users to activate a tooltip (to show mouse position):


When manually editing the SVG (without editor) you need a lot of calculations or guessing where to put your components. Hopefully this simplifies that process a bit:


1 Like