Node-red-contrib-ui-svg create table by input message

Good Morning.
I need to organize the goals in a table, and mark goals made and goals left to do.
Is there any way to create a table with the goals, without being everything manually?

image

I get the task by input. Is there any way to put them in an automatically generated table?

Ui-Table is certainly the first you should take a look at

but I need to integrate it inside the Node-red-contrib-ui-svg dashbord

SVG doesn't have a table type.

Read this thread to understand your options....

"Create a table in SVG - Stack Overflow" javascript - Create a table in SVG - Stack Overflow

Have you installed the core dashboard nodes (node-red-dashboard)?

Hi @samuelbras,
So I assume this table is surrounded by other shapes, and is part of a big drawing? Does it contain a lot rows? Because I am not sure how it will behave/look like when you have a larger table, that doesn't fit on the screen (and scrollbars are needed).

I don't think there is anything automatic available in SVG to accomplish this. Some ideas:

  1. The most automatic pure SVG way of working, seems to me that you apply a fill pattern on a shape. Like a grid, but with larger cells. Then you have your lines already out of the box, but of course you still need to position your texts at the correct coordinates. But absolutely not sure whether this is a good way to go...

  2. As @Steve-Mcl already explained, you can embed a standard html table inside an SVG drawing. The values of that foreign table element can be filled via an input msg (see here). And here you can find some of my experiments with foreign objects in the SVG node, although I have never used a table as foreign object myself ...

  3. And if you want to do it in pure SVG, you can also write some Javascript to calculate all the shapes to draw a table. But seems a lot of work to me. If you want to go that way, you might find some examples on the web to get you started (e.g. here).

So I think you first need to decide which way you want to go. Personally I think the html table inside the foreign object might be most automatic way of working. Because the html table component will do a lot of the work for you.

We don't know how the entire SVG drawing will look like, or how the table will be part of it (e.g. scrollbar when the table grows). So I'm afraid you are the only that can determine which will be the best way to go...

Bart

1 Like

Hi @BartButenaers

Yes, the table is integrated in a SVG Group inside a whole SVG.

For the scrollbars I have found a peace of code that add scrollbar in svg.
Now, for this propose I have made in pure SVG by input message. I have some work but I think that is solved for now.

thank you all for the support

Best regards

Samuel Brás

Hi @samuelbras,
You are welcome! Nice to hear that you are managing to get it solved.

If you should afterwards have a small (simplified) example flow to demonstrate it, it would be nice if you would like to share it with us. Only a simple small table that you can update via a simple input message.
To be honest, I am very curious now how something like that would look like.
Never seen something like that before ...

Thanks!
Bart

Hi @BartButenaers

I have prepared a simple sample, that solve my case.

the input message that I recive is somting like

   { "grid": [
        {
            "id": 100,
            "grid_item": "Line 1 text",
        },
        {
            "id": 110,
            "grid_item": "Line 2 text",
        },
        {
            "id": 120,
            "grid_item": "Line 3 text",
        },
        {
            "id": 130,
            "grid_item": "Line 4 text",
        },
        {
            "id": 140,
            "grid_item": "Line 5 text",
        },
        {
            "id": 150,
            "grid_item": "Line 6 text",
        }
    ]
	}

and the function that recive is like


var addX = 96;
var countElements=0;
msg.payload = [];


for (let i = 0; i < gridLines; i++) {

positionId = Order[i].id;
next = Order[i].next;
previous = Order[i].previous;

lineText = Order[i].grid_item;

var positionX = 64 + (addX*i);
var positionXLine = 100 + (addX*i);

var elementgroup = {
    "command" : "add_element",
    "elementType" : "group",
    "elementId" : "group"+positionId,
    "parentElementId" : "scrollgroup",
    "elementAttributes":{
        "next": next,
        "previous": previous
    }
};
msg.payload[countElements]= elementgroup;
countElements++;

var elementStep = {
    "command" : "add_element",
    "elementType" : "text",
    "elementId" : "topicPos"+positionId,
    "parentElementId" : "group"+positionId,
    "elementAttributes":{
        "class": "cls-7 " +positionId,
        "transform":"translate(72 " + positionX +")"
    },
    "textContent": i+1 + " / " + gridLines
};
msg.payload[countElements]= elementStep;
countElements++;

var elementDesc ="";

    elementDesc = {
        "command" : "add_element",
        "elementType" : "text",
        "elementId" : "topicDesc"+positionId,
        "parentElementId" : "group"+positionId,
        "elementAttributes":{
            "class": "cls-7 "+ positionId,
            "transform":"translate(171 " + positionX +")"
        },
        "textContent": lineText
    };

msg.payload[countElements]= elementDesc;
countElements++


var elementLine = {
    "command" : "add_element",
    "elementType" : "line",
    "elementId" : "line"+positionId,
    "parentElementId" : "group"+positionId,
    "elementAttributes":{
        "class": "cls-objectiveSeparator "+ positionId,
        "x2": "1600",
        "transform":"translate(20 " + positionXLine +")"
    }
};
countElements++;
}

It has some problems, like if the text in the grid has 2 rows or more.
But for now it solve the problem.

1 Like

Hey @samuelbras,
Thanks for sharing your solution, so others can benefit from it !!
Bart

@samuelbras,
I was wondering whether it would have been easier to add a HTML table as a foreign element inside the SVG drawing. So I am now talking about option 2 mentioned above.

Seemed tonight that this was not possible, because the add_element command only allowed to create SVG elements (which have their own namespace). I have added a fix on Github to allow non-SVG elements to be created, by adding a foreignElement=true to the input message. That allows to create standard HTML elements, like e.g. a <tr> element for a table row.

The example flow contains this SVG drawing of a board, and I have added a standard HTML table as a foreign object to that SVG drawing:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" height="263" viewBox="0 0 263 263" width="263">
  <g>
    <path d="M257.333,25.497h-32.867c0.124-0.48,0.196-0.98,0.196-1.499c0-3.313-2.687-6-6-6h-46.51
		c0.012-0.161,0.025-0.321,0.025-0.485c0-3.581-2.904-6.485-6.485-6.485h-68.05c-3.581,0-6.485,2.903-6.485,6.485
		c0,0.164,0.013,0.324,0.025,0.485h-46.51c-3.313,0-6,2.687-6,6c0,0.518,0.073,1.019,0.196,1.499H6c-3.314,0-6,2.686-6,6v148.492
		c0,3.313,2.686,6,6,6h115.926l-34.101,57.244c-1.696,2.847-0.763,6.53,2.084,8.226c2.848,1.696,6.53,0.763,8.226-2.084
		l27.532-46.217v33.019c0,3.313,2.687,6,6,6s6-2.687,6-6v-33.019l27.532,46.217c1.123,1.884,3.116,2.93,5.161,2.93
		c1.044,0,2.103-0.273,3.065-0.846c2.847-1.696,3.78-5.378,2.084-8.226l-34.101-57.244h115.926c3.314,0,6-2.687,6-6V31.497
		C263.333,28.183,260.647,25.497,257.333,25.497z M251.333,173.989H12V37.497h239.333V173.989z" />
  </g>
  <foreignObject x="30" y="50" width="200" height="110">
    <table style="width: 100%; border:2px solid;text-align:left">
      <colgroup>
        <col span="1" style="width: 70%;">
        <col span="1" style="width: 30%;">
      </colgroup>
      <tbody id="mytable">
        <tr>
          <th style="font-weight: bolder;text-decoration: underline">Room</th>
          <th style="font-weight: bolder;text-decoration: underline">°C</th>
        </tr>
        <tr>
          <td>Kitchen</td>
          <td>21</td>
        </tr>
      </tbody>
    </table>
  </foreignObject>
</svg>

Now we can add dynamically a table row, by injecting a message that creates a tr HTML element as a child of the table body (with id "mytable"). The table row (tr) contains two table cells (td):

{
    "command": "add_element",
    "elementType": "tr",
    "textContent": "<td>Bathroom</td><td>22</td>",
    "parentElementId": "mytable",
    "foreignElement": true
}

Which results in this:

svg_table

Here is the entire flow:

image

[{"id":"ac37cc973bbb46fe","type":"ui_svg_graphics","z":"3f01ab2a1bf97f25","group":"3ce32370.c60f1c","order":11,"width":"18","height":"10","svgString":"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0\" y=\"0\" height=\"263\" viewBox=\"0 0 263 263\" width=\"263\">\n  <g>\n    <path d=\"M257.333,25.497h-32.867c0.124-0.48,0.196-0.98,0.196-1.499c0-3.313-2.687-6-6-6h-46.51\n\t\tc0.012-0.161,0.025-0.321,0.025-0.485c0-3.581-2.904-6.485-6.485-6.485h-68.05c-3.581,0-6.485,2.903-6.485,6.485\n\t\tc0,0.164,0.013,0.324,0.025,0.485h-46.51c-3.313,0-6,2.687-6,6c0,0.518,0.073,1.019,0.196,1.499H6c-3.314,0-6,2.686-6,6v148.492\n\t\tc0,3.313,2.686,6,6,6h115.926l-34.101,57.244c-1.696,2.847-0.763,6.53,2.084,8.226c2.848,1.696,6.53,0.763,8.226-2.084\n\t\tl27.532-46.217v33.019c0,3.313,2.687,6,6,6s6-2.687,6-6v-33.019l27.532,46.217c1.123,1.884,3.116,2.93,5.161,2.93\n\t\tc1.044,0,2.103-0.273,3.065-0.846c2.847-1.696,3.78-5.378,2.084-8.226l-34.101-57.244h115.926c3.314,0,6-2.687,6-6V31.497\n\t\tC263.333,28.183,260.647,25.497,257.333,25.497z M251.333,173.989H12V37.497h239.333V173.989z\" />\n  </g>\n  <foreignObject x=\"30\" y=\"50\" width=\"200\" height=\"110\">\n    <table style=\"width: 100%; border:2px solid;text-align:left\">\n      <colgroup>\n        <col span=\"1\" style=\"width: 70%;\">\n        <col span=\"1\" style=\"width: 30%;\">\n      </colgroup>\n      <tbody id=\"mytable\">\n        <tr>\n          <th style=\"font-weight: bolder;text-decoration: underline\">Room</th>\n          <th style=\"font-weight: bolder;text-decoration: underline\">°C</th>\n        </tr>\n        <tr>\n          <td>Kitchen</td>\n          <td>21</td>\n        </tr>\n      </tbody>\n    </table>\n  </foreignObject>\n</svg>","clickableShapes":[],"javascriptHandlers":[],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":false,"showBrowserErrors":true,"showBrowserEvents":true,"enableJsDebugging":false,"sendMsgWhenLoaded":false,"noClickWhenDblClick":false,"outputField":"payload","editorUrl":"//drawsvg.org/drawsvg.html","directory":"","panning":"disabled","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"dblClickZoomPercentage":150,"name":"","x":660,"y":80,"wires":[[]]},{"id":"41fc31c058631fe9","type":"inject","z":"3f01ab2a1bf97f25","name":"Add table row","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"add_element\",\"elementType\":\"tr\",\"textContent\":\"<td>Bathroom</td><td>22</td>\",\"parentElementId\":\"mytable\",\"foreignElement\":true}","payloadType":"json","x":430,"y":80,"wires":[["ac37cc973bbb46fe"]]},{"id":"3ce32370.c60f1c","type":"ui_group","name":"Demo","tab":"d74bbed4.c2cfb","order":2,"disp":false,"width":"18","collapse":false},{"id":"d74bbed4.c2cfb","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Note that I quickly created this example flow, and I can improved a lot: scrollbars, fixed headers during scrolling, fixed number of visible rows ... So if anybody wants to improve the example flow and share it here, that would be nice!

P.S. The fix is not available on NPM yet. So if you want to test this, you need to install the fixed svg node directly from Github using this command (from within your .node-red folder):

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

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