UIBUILDER: Using MermaidJS

Hi all, little mini FAQ about using MermaidJS to generate browser-based charts with data from Node-RED and with the support of UIBUILDER.

You will see some chat here: StateTrail-Node for Dashboard 2.0 - about using Mermaid for a timeline chart. It supports many other chart types too.

Mermaid takes TEXT chart descriptions and turns them into graphics. Usually it is used as an extension along side some tool to convert Markdown to HTML. If I get time, I'll add more info to this FAQ to show how to do that as well since UIBUILDER supports Markdown quite readily. But initially, I'll just show you 1 way to use the Mermaid library directly.

UIBUILDER progressively enhances native web tooling and so supports any web library. :wink:

[{"id":"65bbdbc1a8301e7b","type":"uibuilder","z":"1b2ed12a321034dc","name":"","topic":"","url":"mermaid-timeline","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"esm-blank-client","extTemplate":"","showfolder":false,"reload":true,"sourceFolder":"src","deployedVersion":"7.1.0","showMsgUib":true,"title":"","descr":"","editurl":"vscode://file/src/uibRoot/mermaid-timeline/?windowId=_blank","x":400,"y":340,"wires":[["a4004d1d51fe87d4"],[]]},{"id":"0980fae560b35fd6","type":"debug","z":"1b2ed12a321034dc","name":"uibuilder standard output","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":703.0000305175781,"y":386.9999895095825,"wires":[],"l":false},{"id":"f4a8f0029f21b813","type":"link in","z":"1b2ed12a321034dc","name":"in to uib","links":["1e40e8ac1c2ee858"],"x":245,"y":340,"wires":[["65bbdbc1a8301e7b"]]},{"id":"a4004d1d51fe87d4","type":"switch","z":"1b2ed12a321034dc","name":"","property":"_ui.id","propertyType":"msg","rules":[{"t":"eq","v":"btn1","vt":"str"},{"t":"eq","v":"btn2","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":590,"y":340,"wires":[["562c9d4ecec8efde"],["53ea9de0b8b3528a"],["0980fae560b35fd6"]]},{"id":"1e40e8ac1c2ee858","type":"link out","z":"1b2ed12a321034dc","name":"out to uib","mode":"link","links":["f4a8f0029f21b813"],"x":1045,"y":320,"wires":[]},{"id":"4571a4fe83cfd5b5","type":"template","z":"1b2ed12a321034dc","name":"index.html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!doctype html>\n<html lang=\"en\"><head>\n\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n    <title>Markdown-Mermaid Example - Node-RED uibuilder</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Markdown-Mermaid Example\">\n\n    <!-- Your own CSS -->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <script defer src=\"https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js\"></script>\n    <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n    <script defer src=\"./index.js\"></script>\n\n</head><body class=\"uib\">\n    \n    <h1 class=\"with-subtitle\">Markdown-Mermaid Example</h1>\n    <div role=\"doc-subtitle\">Using the uibuilder IIFE library.</div>\n\n    <div>\n        <button id=\"btn1\" onclick=\"uibuilder.eventSend(event)\">Machine-1</button>\n        <button id=\"btn2\" onclick=\"uibuilder.eventSend(event)\">Machine-2</button>\n    </div>\n\n    <!-- <pre id=\"chart\"></pre> -->\n    <pre id=\"chart\" class=\"mermaid\"></pre>\n\n    <div id=\"more\"></div>\n\n</body></html>\n","output":"str","x":910,"y":460,"wires":[["57d61672e9bf3aaf"]]},{"id":"d35ddf5578ec138c","type":"inject","z":"1b2ed12a321034dc","name":"Upd FE Code (Run this once to get the web page)","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":590,"y":460,"wires":[["4571a4fe83cfd5b5","dfb618a2f72fbebd"]]},{"id":"57d61672e9bf3aaf","type":"uib-save","z":"1b2ed12a321034dc","url":"mermaid-timeline","uibId":"65bbdbc1a8301e7b","folder":"src","fname":"index.html","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"index.html","topic":"","x":1070,"y":460,"wires":[]},{"id":"dfb618a2f72fbebd","type":"template","z":"1b2ed12a321034dc","name":"index.js","field":"payload","fieldType":"msg","format":"javascript","syntax":"mustache","template":"// @ts-nocheck\n\n// console.log(mermaid) // This is the mermaid library object\n\n// Don't let the library start automatically - we need control\nmermaid.initialize({ startOnLoad: false });\n\nconst printArguments = function (arg1, arg2, arg3) {\n    alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);\n};\n\n// Listen for incoming messages from Node-RED and action\nuibuilder.onChange('msg', (msg) => {\n    // console.log(msg.payload)\n\n    // Get a reference to the chart element\n    const chart = document.getElementById('chart')\n\n    // If the chart has already been processed, remove it\n    delete chart.dataset.processed\n    chart.innerHTML = ''\n\n    // Set the innerHTML of the chart element to the payload\n    $('#chart').textContent = msg.payload\n\n    // (Re-)run the mermaid code\n    mermaid.run({ querySelector: '#chart' });\n})\n","output":"str","x":900,"y":520,"wires":[["c6f4ee3f3127719b"]]},{"id":"c6f4ee3f3127719b","type":"uib-save","z":"1b2ed12a321034dc","url":"mermaid-timeline","uibId":"65bbdbc1a8301e7b","folder":"src","fname":"index.js","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"index.js","topic":"","x":1060,"y":520,"wires":[]},{"id":"e03baf0d7e66ba6a","type":"template","z":"1b2ed12a321034dc","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"  \n---\ndisplayMode: compact\n---\ngantt\n  dateFormat YYYY-MM-DD HH:mm\n  axisFormat %H:%M\n  tickInterval 1hour\n  title Machine Operation Status (HTML) \n  \n  section {{machine}}\n    {{data}}\n  \n  click des1 call printArguments(\"test1\", \"test2\", test3)\n","output":"str","x":940,"y":320,"wires":[["1e40e8ac1c2ee858"]]},{"id":"562c9d4ecec8efde","type":"function","z":"1b2ed12a321034dc","name":"Machine 1 data","func":"msg.data = `\n\nOFF :crit, des1, 2014-12-15 00:00, 2014-12-15 01:10\nON :active, des2, 2014-12-15 01:10, 2014-12-15 02:20\nOFF :crit, des1, 2014-12-15 02:20, 2014-12-15 09:30\nON :active, des2, 2014-12-15 09:30, 2014-12-15 14:00\n\n`\n\nmsg.machine = 'machine-1'\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":300,"wires":[["e03baf0d7e66ba6a"]]},{"id":"53ea9de0b8b3528a","type":"function","z":"1b2ed12a321034dc","name":"Machine 2 data","func":"msg.data = `\n    OFF :active, des1, 2014-12-15 00:00, 2014-12-15 01:10\n    ON :crit, des2, 2014-12-15 01:10, 2014-12-15 02:20\n    OFF :active, des1, 2014-12-15 02:20, 2014-12-15 09:30\n    ON :crit, des2, 2014-12-15 09:30, 2014-12-15 14:00\n`\n\nmsg.machine = 'machine-2'\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":340,"wires":[["e03baf0d7e66ba6a"]]}]

After setting up the uibuilder and uib-save nodes and deploying. Trigger the inject to get the desired web page and script. The page looks like this:

Press one of the buttons to get the chart:

Then press the other button to get the other chart. The data comes from link to the other thread.

The 2 function nodes set up the text data for each machine output and the template merges the data into the Mermaid chart description text. The full text looks like this:

  
---
displayMode: compact
---
gantt
  dateFormat YYYY-MM-DD HH:mm
  axisFormat %H:%M
  tickInterval 1hour
  title Machine Operation Status (HTML) 
  
  section machine-1
    

OFF :crit, des1, 2014-12-15 00:00, 2014-12-15 01:10
ON :active, des2, 2014-12-15 01:10, 2014-12-15 02:20
OFF :crit, des1, 2014-12-15 02:20, 2014-12-15 09:30
ON :active, des2, 2014-12-15 09:30, 2014-12-15 14:00

Note the initial blank line - you need that otherwise Mermaid objects to the YAML displayMode instruction.

Also note that Mermaid is essentially a STATIC chart. You cannot dynamically extend the chart data, you can only completely rebuild the chart. But with the magic of Node-RED and UIBUILDER, rebuilding the chart is simple.

This is a very simplistic example but it certainly works. Not sure whether I'd ever actually use this outside of a Markdown page but the approach could occasionally be helpful.

2 Likes

Works as expected indeed.
How do we get the on click event ?

I am able to get it to open a website (as in example), but unable to get the data within the chart (start time/end time) etc..

uib-st

A good question. The Mermaid documentation looks good but in fact has some significant issues. I've not managed to get the events to work but I've not had time to dig into the code to find out what is happening. I've tried some of their code examples and some of them don't work at all - I think because they come from an older version of the library. There are also oddities when using the displayMode option because if you aren't really careful, the library rejects it as being invalid.

Also, the Mermaid stuff is very static - you cannot extend the diagram, only fully rebuild.


One other thing this has done is to highlight an issue with the Markdown-IT library that is directly supported by uibuilder. It seems that all of the Mermaid extensions for Markdown-IT have issues.


Really, I still think that a web component is the right answer, I just need to find some time to get it written. Christmas time is not necessarily the best time to focus on this stuff! But I will try to find some more time. :slight_smile:

you need to add the javascript part:

 <script>
    const printArguments = function (arg1, arg2, arg3) {
      alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);
    };
    const printTask = function (taskId) {
      alert('taskId: ' + taskId);
    };
    const config = {
      startOnLoad: true,
      securityLevel: 'loose',
    };
    mermaid.initialize(config);
  </script>

the functions can be called as defined.

OK, I actually worked it out just after I wrote my last message. You need to add a security level setting:

// Don't let the library start automatically - we need control. Also enable events
mermaid.initialize({
    startOnLoad: false,
    securityLevel: 'loose',
})

Also, you need to assign the callback function to the global object. So instead of const printArguments = function ...., you need:

window.printArguments = function (arg1, arg2, arg3) {
    console.warn('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3)
}

Also note:

  • If you call the function with no arguments, it gets the id of the clicked area. If you pass arguments, you don't get that, just the things you passed.
  • The example data repeats an ID - if you do that, you only get an event on the first block with that id. So really, you need to give each entry a different, unique id.

The good news about doing this with uibuilder is that you can use uibuilder front-end functions:

click des2 call uibuilder.send({topic: "des2 clicked", payload: 42})

The bad news is that it really is not a scalable option.

can you give me an example flow ? i am not able to get it working. the open website link works though (as it is not js, just a href). Call function dont work in my flow, i am sure missing something

when using uibuilder you probably need to follow the instructions from @TotallyInformation above to expose the functions to the window object.

The flow is much the same:

This is the template:

  
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
gantt
  dateFormat YYYY-MM-DD HH:mm
  axisFormat %H:%M
  tickInterval 1hour
  title Machine Operation Status (HTML) 
  
  section {{machine}}
    {{data}}
  
  click des1 call printArguments("des1", 2, true)
  click des2 call uibuilder.send({payload: "Cannot have commas in the callback args!"})
  

Noting the use of debug output and dark theme. Also noting the use of a uibuilder function on the click event for the second entry (and that the MermaidJS argument parsing has a bug which prevents the inclusion of commas except as actual argument separators). I have also removed the directive for output of a compact display as this is now included in the JavaScript config instead.

[{"id":"65bbdbc1a8301e7b","type":"uibuilder","z":"1b2ed12a321034dc","name":"","topic":"","url":"mermaid-timeline","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"esm-blank-client","extTemplate":"","showfolder":false,"reload":true,"sourceFolder":"src","deployedVersion":"7.1.0","showMsgUib":true,"title":"","descr":"","editurl":"vscode://file/src/uibRoot/mermaid-timeline/?windowId=_blank","x":400,"y":340,"wires":[["a4004d1d51fe87d4","7dd7aebe047a1158"],[]]},{"id":"0980fae560b35fd6","type":"debug","z":"1b2ed12a321034dc","name":"uibuilder standard output","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":703.0000305175781,"y":386.9999895095825,"wires":[],"l":false},{"id":"f4a8f0029f21b813","type":"link in","z":"1b2ed12a321034dc","name":"in to uib","links":["1e40e8ac1c2ee858"],"x":245,"y":340,"wires":[["65bbdbc1a8301e7b"]]},{"id":"a4004d1d51fe87d4","type":"switch","z":"1b2ed12a321034dc","name":"","property":"_ui.id","propertyType":"msg","rules":[{"t":"eq","v":"btn1","vt":"str"},{"t":"eq","v":"btn2","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":590,"y":340,"wires":[["562c9d4ecec8efde"],["53ea9de0b8b3528a"],["0980fae560b35fd6"]]},{"id":"1e40e8ac1c2ee858","type":"link out","z":"1b2ed12a321034dc","name":"out to uib","mode":"link","links":["f4a8f0029f21b813"],"x":1045,"y":320,"wires":[]},{"id":"4571a4fe83cfd5b5","type":"template","z":"1b2ed12a321034dc","name":"index.html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!doctype html>\n<html lang=\"en\"><head>\n\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n    <title>Markdown-Mermaid Example - Node-RED uibuilder</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Markdown-Mermaid Example\">\n\n    <!-- Your own CSS -->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <script defer src=\"https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js\"></script>\n    <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n    <script defer src=\"./index.js\"></script>\n\n</head><body class=\"uib\">\n    \n    <h1 class=\"with-subtitle\">Markdown-Mermaid Example</h1>\n    <div role=\"doc-subtitle\">Using the uibuilder IIFE library.</div>\n\n    <div>\n        <button id=\"btn1\" onclick=\"uibuilder.eventSend(event)\">Machine-1</button>\n        <button id=\"btn2\" onclick=\"uibuilder.eventSend(event)\">Machine-2</button>\n    </div>\n\n    <!-- <pre id=\"chart\"></pre> -->\n    <pre id=\"chart\" class=\"mermaid\"></pre>\n\n    <div id=\"more\"></div>\n\n</body></html>\n","output":"str","x":910,"y":460,"wires":[["57d61672e9bf3aaf"]]},{"id":"d35ddf5578ec138c","type":"inject","z":"1b2ed12a321034dc","name":"Upd FE Code (Run this once to get the web page)","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":590,"y":460,"wires":[["4571a4fe83cfd5b5","dfb618a2f72fbebd"]]},{"id":"57d61672e9bf3aaf","type":"uib-save","z":"1b2ed12a321034dc","url":"mermaid-timeline","uibId":"65bbdbc1a8301e7b","folder":"src","fname":"index.html","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"index.html","topic":"","x":1070,"y":460,"wires":[]},{"id":"dfb618a2f72fbebd","type":"template","z":"1b2ed12a321034dc","name":"index.js","field":"payload","fieldType":"msg","format":"javascript","syntax":"mustache","template":"// @ts-nocheck\n\n// console.log(mermaid) // This is the mermaid library object\n\n// Don't let the library start automatically - we need control. Also enable events\nmermaid.initialize({\n    startOnLoad: false,\n    securityLevel: 'loose',\n    // https://mermaid.js.org/syntax/gantt.html#configuration\n    gantt: {\n        displayMode: 'compact',\n    },\n})\n\nconst printArguments = function (arg1, arg2, arg3) {\n    console.log('printArguments called with arguments: ', arg1, arg2, arg3)\n};\n\n// Listen for incoming messages from Node-RED and action\nuibuilder.onChange('msg', (msg) => {\n    // console.log(msg.payload)\n\n    // Get a reference to the chart element\n    const chart = document.getElementById('chart')\n\n    // If the chart has already been processed, remove it\n    delete chart.dataset.processed\n    chart.innerHTML = ''\n\n    // Set the innerHTML of the chart element to the payload\n    $('#chart').textContent = msg.payload\n\n    // (Re-)run the mermaid code\n    mermaid.run({ querySelector: '#chart' });\n})\n","output":"str","x":900,"y":520,"wires":[["c6f4ee3f3127719b"]]},{"id":"c6f4ee3f3127719b","type":"uib-save","z":"1b2ed12a321034dc","url":"mermaid-timeline","uibId":"65bbdbc1a8301e7b","folder":"src","fname":"index.js","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"index.js","topic":"","x":1060,"y":520,"wires":[]},{"id":"e03baf0d7e66ba6a","type":"template","z":"1b2ed12a321034dc","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"  \n%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%\ngantt\n  dateFormat YYYY-MM-DD HH:mm\n  axisFormat %H:%M\n  tickInterval 1hour\n  title Machine Operation Status (HTML) \n  \n  section {{machine}}\n    {{data}}\n  \n  click des1 call printArguments(\"des1\", 2, true)\n  click des2 call uibuilder.send({payload: \"Cannot have commas in the callback args!\"})\n  ","output":"str","x":940,"y":320,"wires":[["1e40e8ac1c2ee858"]]},{"id":"562c9d4ecec8efde","type":"function","z":"1b2ed12a321034dc","name":"Machine 1 data","func":"msg.data = `\n\nOFF :crit, des1, 2014-12-15 00:00, 2014-12-15 01:10\nON :active, des2, 2014-12-15 01:10, 2014-12-15 02:20\nOFF :crit, des1, 2014-12-15 02:20, 2014-12-15 09:30\nON :active, des2, 2014-12-15 09:30, 2014-12-15 14:00\n\n`\n\nmsg.machine = 'machine-1'\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":300,"wires":[["e03baf0d7e66ba6a"]]},{"id":"53ea9de0b8b3528a","type":"function","z":"1b2ed12a321034dc","name":"Machine 2 data","func":"msg.data = `\n    OFF :active, des1, 2014-12-15 00:00, 2014-12-15 01:10\n    ON :crit, des2, 2014-12-15 01:10, 2014-12-15 02:20\n    OFF :active, des1, 2014-12-15 02:20, 2014-12-15 09:30\n    ON :crit, des2, 2014-12-15 09:30, 2014-12-15 14:00\n`\n\nmsg.machine = 'machine-2'\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":340,"wires":[["e03baf0d7e66ba6a"]]},{"id":"7dd7aebe047a1158","type":"debug","z":"1b2ed12a321034dc","name":"uibuilder standard output","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":555,"y":280,"wires":[],"l":false}]

The flow does not include a mechanism for getting the current machine data - I suspect that you will want a separate flow that periodically gets that data and updates a context variable that you can then reference in the function node. In doing so, you will be able to simplify the flow reducing the 2 machine flows to a single generic one that grabs the context var for the requested machine and formats the appropriate output.

If you want click actions for all entries on the timeline, make sure that each data point has a unique id and that the function node adds something like a msg.actions so that it can be merged in via the template.

So far so good, I was able to get actions on click of every segment. BUT, how do i get the data embedded in the segments (start time, end time and duration basically, (duration i can caclulate externally) ? i am only getting the static text that is put in the code. 1-cannot have...2-cannot have...etc)

pardon me if I am being dumb, and pushing for a complete solution rather than just hints. you already did almost complete flow for me.

 
  click des1 call uibuilder.send({payload: "1-Cannot have commas in the callback args!"})
  click des2 call uibuilder.send({payload: "2-Cannot have commas in the callback args!"})
  click des3 call uibuilder.send({payload: "3-Cannot have commas in the callback args!"})
  click des4 call uibuilder.send({payload: "4-Cannot have commas in the callback args!"})

You are not. I was working on a more complete solution. Not complete because I've had to do some real work! :slight_smile:

Here is a somewhat untested function code:

const mcData = flow.get('mcData') ?? {}

const mcKey = msg._ui.slotText.toLowerCase()
const data = mcData[mcKey]

msg.payload = `
  
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
gantt
  dateFormat YYYY-MM-DD HH:mm
  axisFormat %H:%M
  tickInterval 1hour
  title Machine Operation Status (HTML) 
  
`

let clicks = `

`

if (data) {
    msg.payload += `section ${mcKey}\n`
    
    data.forEach( (event, i) => {
        const type = event.value === 'ON' ? 'active' : 'crit'

        msg.payload += `    ${event.value} :${type}, evt${i+1}, ${event.start}, ${event.end}`

        // The callback function has to exist in the browsers globalThis/window context
      clicks += `  click evt${i + 1} call printArguments("evt${i + 1}", ${i + 1}, ${event.value})\n`

        // Frustratingly, a bug in Mermaid means you cannot include commas
        // in the callback arguments so you are limited in what you can send
      clicks += `  click des2 call uibuilder.send({payload: "evt${i + 1} - ${i + 1} - ${event.value}"})\n`
        // Of course, you could create your own function to send data back if you want to process in the front-end
    })
    
    // Add the click event handlers
    msg.payload += clicks
    
    return msg
}

// Nothing is sent if the machine id not found

Corrected function code:

const mcData = flow.get('mcData') ?? {}

const mcKey = msg._ui.slotText.toLowerCase()
const data = mcData[mcKey]

msg.payload = `
  
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
gantt
  dateFormat YYYY-MM-DD HH:mm
  axisFormat %H:%M
  tickInterval 1hour
  title Machine Operation Status (HTML) 
  
`

let clicks = `

`

if (data) {
    msg.payload += `section ${mcKey}\n`
    
    data.forEach( (event, i) => {
        const type = event.value === 'ON' ? 'active' : 'crit'

        msg.payload += `    ${event.value} :${type}, evt${i+1}, ${event.start}, ${event.end}\n`

        // The callback function has to exist in the browsers globalThis/window context
      clicks += `  click evt${i + 1} call printArguments("evt${i + 1}", ${i + 1}, ${event.value})\n`

        // Frustratingly, a bug in Mermaid means you cannot include commas
        // in the callback arguments so you are limited in what you can send
      clicks += `  click evt${i + 1} call uibuilder.send({payload: "evt${i + 1} - ${i + 1} - ${event.value}"})\n`
        // Of course, you could create your own function to send data back if you want to process in the front-end
    })
    
    // Add the click event handlers
    msg.payload += clicks
    
    return msg
}

// Nothing is sent if the machine id not found

As far as I can tell, the only way you can do that with Mermaid is to build the data into the callbacks when you build the new version of the chart. The updated function node shows you the way.

This is very much a Mermaid issue - it is designed for static outputs and not for dynamic ones.

To do more would require you to unpack the inner workings of the API and though I had a quick go at that, their examples didn't actually work. I need to focus on better things now.

I get it, for my use case, this is not a solution. But, in order to get till here, I learnt few things and was able to make another completely new solution. But the user experience is not going to be the same as DB-1's statetrail.

To the statetrail I was just feeding data of 'status,timestamp' at one minute interval, and it was calculating all the segments (where status was changing) automatically and merging them and when i clicked any segment it used to give me start time, end time and duration.

to use this 'new' solution, i am calcluating the start time, end time BEFORE sending them to the chart (my job is already done by now :slight_smile:) and using chart as just a visual representation of data (which it is). but not as a interactive piece.

I am now using the data I prepopulated to find start/end time (by mysql query using LAG function on state, this was a big learning curve) to feed into a data table and using buttons in the table to user interaction, not very pretty, but does the job and the user is happy that it is a tad faster than before!

Thanks for all the inspiration and for other solutions in the meanwhile.

uib-table

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.