SVG node - store the current state

Hi folks,

Received last week a couple of questions about the node-red-contrib-ui-svg node. The users update the original SVG drawing by injecting input messages (e.g. to update the color of a specified shape), but after a deploy/refresh/reboot they again get the original drawing.

People send data about e.g. their sensors to the SVG node, to visualize the current state. But after a refresh/deploy they still want the last drawing status to become available again.

But I'm not sure anymore how the svg node should behave in those situations. So would be nice to get some ideas about this...

Let's discuss a simple drawing that consists out of a single circle.

Current setup

The SVG drawing is stored (at server side) in Node-RED (flow.json file) as a string, since the SVG node has a property "svgString".

  1. The SVG string is send to the client (= dashboard), where it will be loaded in the browser's DOM tree.

  2. The browser will render the DOM tree, and the circle will be displayed.

  3. An input message can be injected, e.g. to change the circle color.

  4. That input message will be send to the browser, where it is loaded in the DOM tree again (so the circle will be rendered in the new color).

But at a refresh/deploy the original SVG string will be send to the client again (see 1), which means the circle will be drawn again with its initial color. So all the changes made via input messages will be lost in the final drawing.

Possible future setup

A possible solution 'could' perhaps be to add a DOM tree (based on svg.js) in the server side of the SVG node:

  1. The SVG string will be loaded in the server's DOM tree.

  2. That server DOM tree will be serialized to a string and send to the client (= dashboard), where it will be loaded in the browser's DOM tree.

  3. The browser will render the DOM tree, and the circle will be displayed.

  4. An input message can be injected, e.g. to change the circle color.

  5. That message will be used to update the server side DOM tree. P.S. for performance we will not serialize the entire tree to send it to be client (so not via 2).

  6. That message will also be used to update the client side DOM tree.

So at a refresh we could send again the updated server side DOM tree to the client, so the circle would still have its updated color after a refresh. Although I have not investigated yet whether this is possible ... And after a reboot we would start again from the original SVG string.

Would be nice to get some ideas:

  • Is this a good proposal, or perhaps not?
  • Is it ok to do it like this, or is this perhaps easily possible outside our node? We got a proposal here to workaround it by recording and replaying the messages. Would be better to have a general solution ... There was a related discussion ...
  • How do other nodes deal with refreshes, ... I now that the last message can be replayed automatically inside a ui node, but not sure whether more stuff is available out of the box?

Thanks a lot !!!
Bart

1 Like

Not sure if this is helpful to you or not, but I use HTML to store my SVG then use JavaScript to manipulate it. I have another post on her with a control panel that is all SVG, active buttons, LEDs that change color, etc. I use Inkscape to draw whatever I want, then for example a gauge... I name the pointer as "POINTER" and use a JavaScript command to assign a rotation.

Here are a couple of very simple samples. http://askjerry.info/SVG

If you want more info... I should be doing a YouTube video on it before too long.
Jerry

Did you consider localStorage ?

You would then have to reconcile that with any updates that had occurred on the server while disconnected. That's going to be even harder than just fetching it all again

@bakman2, @Askjerry,
Thanks, indeed local storage in the client would be a third option. But like @dceejay says then perhaps I remember too much on the client side. E.g. when something changes in my SVG node, I need to know that on the client side to refresh the local storage there.

And we had a couple of other feature requests to be able to get the current status of a specified SVG shape, e.g. from @d0d04m3. To solve that, the only solution would be server side DOM tree. So therefore I would prefer to keep the cache on the server, otherwise I need to implement both (client and server) cache.

So I "assume" @Steve-Mcl and myself should do something similar like @hotNipi has already done, by adding a data-storage option. Although I assume that even goes a step further by storing the data in the contextstore, so then I assume we should store the server-side DOM tree also (to be able to restore it after a restart)?

Please let the ideas coming!! Because I would like to implement this in the 2.0.0 release of the SVG node, and some folks are already waiting a long time for other stuff that I added into that release branch...

Release V2 Bart. Get that out of the way :slight_smile:

I'm not convinced we need to handle this. Sure it's definitely a "nice to have" but users can achieve this by using the ui_control and context storage today.

If it's something you feel strongly about, then I think the only viable solution would be a shadow SVG (server side) that is updated with every msg then when a new dashboard is opened, send the shadow SVG to the client.

Note however, that will not take care of everything e.g. any client side DOM changes.

I would second that - add all this caching to a separate branch. As the inheritor of the dashboard I still suspect the handling of all the data on both server and then client side is what is helping to drag down performance of things like charts, as it has to save (and drop when necessary) data on server side so when the client comes back the chart can then be replayed to catch up - (until somebody (cough) doesn't want the old state replayed every time :wink: - and also update client side as and when new points come in - and drop old data etc etc... there be dragons.

2 Likes

Ok deal...

Ok deal...

I still haven't had time to play yet with the ui_control.
Could we share here then some ideas about how users can solve this. Then I will afterwards create a tutorial on our wiki. Would appreciate to have some some simple examples (with ui_control and context storage), so we can discuss those here and collect some best practise guidelines...
Thanks!!!!!!

Perhaps I have another Idea:

I use ui-table a lot feeding in single rows / cells instead of complete tables ... The actual/current table exists only on the dashboard. So I face the same problem:

Instead of building in storage and replay functionality into ui-table I use a second "helper" node:

image

All data to and from the table is passed through this node so it can

  • keep a single cached copy of the table data
  • replay complete tables on tab change
  • make dynamic layouts persistent (hide/show rows and columns, column width and order, responsive layout ...)
  • handle cell edits
  • replace complete table data
  • get current table data (for permanent storage for example)
  • handling callbacks (context clicks for exampe)

So instead of branching of an enhanced version why not splitting the tasks into more than one node?

Just an idea.


BTW it is a subflow easy to configure (and perhaps modify)
image
I used it in remote device table (dynamic updates of cells) syslog server (handling a lot of log data: many static lines streaming in) and currently a new version of my garden irrigation system (handling cell edits, manual row sorting and swapping tables for different configurations)

1 Like

Hi Chris,

Sounds logic. I had the same idea yesterday, but I thought: if I use svg.js in a separate node, then probably only our svg node would use that other svg cache node...

I see that Dave likes your proposal, so I 'assume' it must be a good proposal :joy: But not sure I understand correctly how it works...

  • Which type of node is your helper node?
  • So you would cache somehow the entire svg in that node
  • Does it update your table after a browser refresh?
  • ...

I don't see the entire picture yet using this approach :woozy_face:

Hi @BartButenaers,

  • It is a subflow (Some people thing subflows are the "poor men custom node" but I love them because they are flexible and can evolve over time not only through the maintainer- I call them "poor developer node" because of the lack of powerful IDE / debugger). I normaly start with a function node. If I need that function somewhere else i create a subflow and if this is well backed and mature perhaps I do a custom node (I only miss an IDE and a debugger).
  • Yes ... And where it is stored is up to the user: image
    • tableData stores all data came in. It could be on file but "syslog" or the "remote device table" shows only live data so in this case I use memory only
    • tableConfig stores the layout and all changes
    • tableEdit stores the edits as an "overlay" (good if you have live data where you want to keep an edit even if it is updated by a device)
  • Yes that why it is connected to a ui-control node and you specify your tab name (see above) that a refresh is triggered as soon the table comes up to live
  • due to the way subflows can access $parent.flow context it is all stored there

    all done dynamically (so if a parameter is not used it is not created)

Some thoughts I had.

  • when I added the command functions into ui-table I thought about the "replay" problem and started implementing it into ui-table - soon I found out that there are so many different scenarios that ui-table is getting to heavy. (poor maintaines going through a ton of bed room coders pasta :crazy_face:)
  • The config ui would get overloaded with too many options the "normal" user don`t need. So I left it untouched
  • Where to store the data should be configurable and accessible by the user (see all discussion about "should nodes store persistent data")
  • Even when to trigger a refresh / replay should be able to be configured. We are using node red, so wire in a appropriate note (in most cases ui-control but perhaps someone needs something else)
  • a subflow is handy because it can quickly be expanded with every new task by everyone.

just to give you an idea, here is the sprinkler flow I`m working on right now with the latest version of ui-table handler. (Don't know if it working without all the rest but perhaps it does (use the inject to start, then edit some cells and refresh/reconnect the table should restore)

The remote device table is an example where I broke a task into flexible parts in the hope that it is reusable, flexible, expandable and what not. That is my personal idea of Node-RED

flows.json (43.7 KB)

And before you ask ... if ui-table would be my own node I would add "ui-table handler" as a second custom node. But as ui-table is a core node I think "keep it simple stupid" is the best approach.

When "ui-table handler" is well tested I will publish it on flows.nodered.org or perhaps do a custom contrib node.

and at some point we'll get this completed - https://github.com/node-red/designs/tree/master/designs/exportable-subflow
(though there are a lot of wrinkles to sort out first)

2 Likes

Interesting ... So basically if someone is happy with his subflow than "one click" he has a somehow "custom node"? ... Nice

For me the beauty of subflows is that "everybody" can easily expand or modify them as they need. As my subflows are basically one function node I would (never done before) create a custom node and copy paste the code from the function node into id and add the ui ... Then I could use an IDE & debugger. Or does this process help in building the config UI?. That is the second thing I like with subflows: Quickly build simple config UI, write some md info text ... I'm done for 95% of my tasks. If more complicated configs I use json properties ...

But with a subflow including a "real" Node-RED flow (not only js code) that would be very beneficial.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.