[ANNOUNCE] node-red-contrib-ui-svg: 2.1.0 beta

Hi folks,

Feature requests keep arriving for the SVG node, so time for a new 2.1.0 beta.
For anybody who wants to test it, it can be installed directly from Github (from within your .node-red folder):

npm install bartbutenaers/node-red-contrib-ui-svg

This version contains following changes:

  • Fixed a bug with "freeze" of animation end for @JoseGodinho.

  • Fixed a series of touch event bugs for @janosch.

  • Ability to replace the entire SVG drawing by a new SVG from scratch via an input message.

    svg_replace

    [{"id":"16a953b2.21beec","type":"ui_svg_graphics","z":"a03bd3cf.177578","group":"925439b0.2863c8","order":0,"width":"4","height":"3","svgString":"<svg x=\"0\" y=\"0\" width=\"144\" height=\"144\" viewBox=\"0 0 144 144\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<circle id=\"myShape\" cx=\"73\" cy=\"72\" r=\"20\" color=\"red\" outline=\"black\"/>\n</svg>","clickableShapes":[{"targetId":"#myShape","action":"click","payload":"myShape clicked","payloadType":"str","topic":"#myShape"}],"javascriptHandlers":[],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":false,"showBrowserErrors":true,"outputField":"payload","editorUrl":"//drawsvg.org/drawsvg.html","directory":"","panning":"both","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"name":"svg-graphics","x":1230,"y":340,"wires":[["4672821a.2f296c"]]},{"id":"e105ccfb.c2849","type":"inject","z":"a03bd3cf.177578","name":"SVG with yellow circle","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"replace_svg\",\"svg\":\"<svg height=\\\"140\\\" width=\\\"140\\\"><circle id=\\\"myShape\\\" cx=\\\"50\\\" cy=\\\"50\\\" r=\\\"40\\\" fill=\\\"yellow\\\"/></svg>\"}","payloadType":"json","x":1020,"y":340,"wires":[["16a953b2.21beec"]]},{"id":"b232e2bf.52efb","type":"inject","z":"a03bd3cf.177578","name":"SVG with blue rectangle","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"replace_svg\",\"svg\":\"<svg height=\\\"140\\\" width=\\\"140\\\"><rect id=\\\"myShape\\\" x=\\\"20\\\" y=\\\"30\\\" width=\\\"110\\\" height=\\\"70\\\" fill=\\\"blue\\\"/></svg>\"}","payloadType":"json","x":1020,"y":400,"wires":[["16a953b2.21beec"]]},{"id":"5f208d4d.047af4","type":"inject","z":"a03bd3cf.177578","name":"SVG with pink ellipse","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"replace_svg\",\"svg\":\"<svg height=\\\"140\\\" width=\\\"140\\\"><ellipse id=\\\"myShape\\\" cx=\\\"60\\\" cy=\\\"50\\\" rx=\\\"60\\\" ry=\\\"30\\\" fill=\\\"pink\\\"/></svg>\"}","payloadType":"json","x":1020,"y":460,"wires":[["16a953b2.21beec"]]},{"id":"4672821a.2f296c","type":"debug","z":"a03bd3cf.177578","name":"log events","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1410,"y":340,"wires":[]},{"id":"925439b0.2863c8","type":"ui_group","z":"","name":"Replace SVG test","tab":"5c613937.fe7368","order":4,"disp":true,"width":"4","collapse":false},{"id":"5c613937.fe7368","type":"ui_tab","z":"","name":"Home","icon":"home","order":1,"disabled":false,"hidden":false}]
    

    Note that the event handlers, data bindings, ... will automatically be applied to the new SVG elements also!

  • Ability to specify Javascript event handlers, which are executed in the dashboard directly:

    svg_js_event_config

    Note the "expand" buttons in the above animation, which allows the code to be edited in a fullscreen Ace editor (with Javascript syntax highlighting) ...

    The original event handlers (which triggered an output message when an event occurred) allow to trigger some server-side events easily (e.g. turn on a light in your house). However suppose - when an event occurs - that you only want to make changes to the SVG (instead of changes on the server).
    In those use cases, these event handlers were very inefficient. For example: suppose you want to change the color of a circle when you click it. Until now you had to use a normal event handler, which sended an output message to the Node-RED flow. Then that output message had to be translated in the flow to an input message, which contained the instructions to update the circle color. And that message needed to be send in turn back to the dashboard, which means we had an entire roundtrip between frontend and backend:

    image

    In those cases it is much easier to apply a Javascript event handler to the event, which will be executed in the dashboard.

    The following flow shows how to apply a js event handler in the config screen, to apply a random color to the circle every time it is being clicked. Afterwards an input msg is injected to remove that event handler. And finally, another input message is injected containing a Javascript event handler that shows an alert popup when the circle is clicked:

    {"id":"89244415.be9278","type":"ui_svg_graphics","z":"a03bd3cf.177578","group":"5ae1b679.de89c8","order":4,"width":"0","height":"0","svgString":"<svg x=\"0\" y=\"0\" height=\"350\" viewBox=\"-0.04032258064515237 0 250.0806451612903 350\" width=\"250\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid meet\">\n<circle id=\"my_circle\" cx=\"30\" cy=\"30\" r=\"25\" style=\"stroke: none; fill: #0000ff;\">\n</circle>\n</svg>","clickableShapes":[],"javascriptHandlers":[{"selector":"#my_circle","action":"click","sourceCode":"var letters = '0123456789ABCDEF';\n  var color = '#';\n  for (var i = 0; i < 6; i++) {\n    color += letters[Math.floor(Math.random() * 16)];\n  }\n\n$(\"#my_circle\")[0].style.fill = color;\n \n$scope.send({payload: color, topic: 'circle_color'})"}],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":true,"showBrowserErrors":true,"outputField":"payload","editorUrl":"http://drawsvg.org/drawsvg.html","directory":"","panning":"disabled","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"name":"SVG with Javascript","x":540,"y":180,"wires":[["e06da0e0.2c837"]]},{"id":"d9df6292.785bc","type":"inject","z":"a03bd3cf.177578","name":"Show alert at double click","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_js_event\",\"event\":\"focus\",\"selector\":\"#my_circle\",\"script\":\"alert('Click event handled on the client ...')\"}","payloadType":"json","x":250,"y":140,"wires":[["89244415.be9278"]]},{"id":"5074f893.d378d8","type":"inject","z":"a03bd3cf.177578","name":"Remove clicked event","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"remove_js_event\",\"event\":\"click\",\"selector\":\"#my_circle\"}","payloadType":"json","x":240,"y":180,"wires":[["89244415.be9278"]]},{"id":"e06da0e0.2c837","type":"debug","z":"a03bd3cf.177578","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":750,"y":180,"wires":[]},{"id":"5ae1b679.de89c8","type":"ui_group","name":"Press Demo","tab":"3667e211.c08f0e","order":1,"disp":true,"width":"5","collapse":false},{"id":"3667e211.c08f0e","type":"ui_tab","name":"Home","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
    

As always all "constructive" feedback is very welcome!

Have fun with it!
Bart

6 Likes

Luckily some folks on Github have been doing some test work, which allowed me to fix some bugs meanwhile. And based on the feedback I have also added the following stuff:

  • The setting " Send output msg when the client is (re)loaded" triggers an output message when the browser (re)loads the widget, so the flow can determine to trigger some logic e.g. to preload the SVG with some startup data.

  • The setting " Show browser events on the server" displays events in the Debug sidebar, as soon as they occur in the Dashboard:

    image

    Which is easy to determine if an event has been occurred, e.g. on a smartphone (where the browser console log is not easily accessible).

  • The setting " Enable JS event debugging" will cause the browser debugger to pause just before the custom JS event handler is being executed.

  • A new wiki page has been added about troubleshooting issues with custom JS event handlers, like e.g. how to debug such event handlers.

This new 2.1.0 version is now available on npm :champagne: :clinking_glasses: :partying_face:

image|2.82x118

Had hoped to add some more extra functionalities, but the daily job is getting in the way of my Node-RED developments at the moment :roll_eyes:

2 Likes

Seemed that a nasty bug was introduced in this new version: the elementId and selector fields were not being included anymore in the output message. For anybody experiencing problems with it, the 2.1.1 version fixes this:

image