rich-iannone / DiagrammeR

Graph and network visualization using tabular data in R
https://rich-iannone.github.io/DiagrammeR/
Other
1.68k stars 247 forks source link

Update mermaid.js version #475

Open DDorch opened 1 year ago

DDorch commented 1 year ago

This issue is in echo with issues #231, #227, #241, #294, #329, #363, #421, #470, #473 and maybe some others...

The need to update the version of mermaid.js embedded in the DiagrammeR package is pressing.

As suggested in #421, we can manually update the file /DiagrammeR/htmlwidgets/lib/mermaid/dist/mermaid.slim.min.js in the installation folder of the package with the last version downloaded from https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js.

One way to always have the latest version of DiagrammeR in the package could be to add an updateMermaid function in the package:

#'  Update the mermaid library in the package
#' @param version A [character] of the desired version (the latest by default)
#' @return See value returned by [download.file]
updateMermaid <- function(version = "") {
  url <- "https://cdn.jsdelivr.net/npm/mermaid@version/dist/mermaid.min.js"
  if (version != "") {
    stopifnot(grepl("^[[:digit:]]+\\.[[:digit:]]+\\.[[:digit:]]+$", version))
    version <- paste0("@", version)
  }
  url <- gsub("@version", version, url)
  try(
    download.file(url, 
                  system.file("htmlwidgets/lib/mermaid/dist/mermaid.slim.min.js", 
                              package = "DiagrammeR"))
  )
}

There are several issues with this solution:

@rich-iannone what do you think of that?

DanGustafssonTelgeEnergi commented 1 year ago

I have tried this solution on my local installtion in Windows, and it seems to work (for now). My original issue was to do "erDiagrams" using mermaid from within R - now that works if I update the js-library according to the instructions above. Mermaid seems to be actively developed, by many, so some kind of updating scheme would be in order?

DDorch commented 1 year ago

Duplicate with #480

Seferin commented 1 year ago

Before this running this function with updateMermaid(version="9.3.0") I was stuck with mermaid 0.3.0 and unable to use the mermaid Entity Relationship class of diagram (erDiagram). This solved my problem.

travis-leith commented 1 year ago

@DDorch this appears to break the click functionality introduced in https://github.com/rich-iannone/DiagrammeR/pull/362. Any idea why?

DDorch commented 1 year ago

@DDorch this appears to break the click functionality introduced in #362. Any idea why?

I'm sorry, this needs further investigations to see what has changed in the library that breaks this functionality. At least, that explains why the mermaid library has not been updated yet. Unfortunately, I don't have time these next weeks/months to solve this issue.

trafficonese commented 1 year ago

@DDorch this appears to break the click functionality introduced in #362. Any idea why?

I just tried with the newest mermaid verion. The click functionality seems to be fine for the first example in #362 and the second one does not render so clicking is not even possible.

This code does not work with the new version:

DiagrammeR("graph LR;A(Rounded)-->B[Squared];B-->C{A Decision};
 C-->D[Square One];C-->E[Square Two];
 style A fill:#E5E25F;  style B fill:#87AB51; style C fill:#3C8937;
 style D fill:#23772C;  style E fill:#B6E6E6;"
    )

You will just see:

Syntax error in graph
mermaid version 9.4.0
travis-leith commented 1 year ago

@trafficonese the first example isn't mermaid, unless I have misunderstood.

trafficonese commented 1 year ago

you're right, thats a grViz. But since the mermaid example isnt even rendering, I cannot test the click functionality.

travis-leith commented 1 year ago

On mermaid.live it renders if you take out all the style stuff.

DavZim commented 4 months ago

Is there anything that can be done to accelerate this? It would be great to have the latest version of mermaid in DiagrammeR.

DavZim commented 4 months ago

As I see it, the problem with the newer Mermaid versions is that detecting clicks would be broken. This might be due to changes in security (eg securityLevel: 'loose', see also docs).

I have played around with the newest version to create a MWE in shiny to see if interaction works, this is what I came up with:

library(shiny)

txt <- r"{graph TD
  A[[Start]] --> B(Preview)
  B --o C{decide}
  B -.-> D
  C ==> D[(End)]

  click A node_click "This is a Tooltip"
  click B node_click "This is a Tooltip"
  click C node_click "This is a Tooltip"
  click D node_click "This is a Tooltip"
}"

css <- "
g.nodes > g.node > rect { fill: red !important; }
g.nodes > g.node > polygon { fill: red !important; }
g.nodes > g.node { cursor: pointer; }
"

start_mermaid_js <- "
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true, securityLevel: 'loose' });
"

js <- r"{
node_click = function (id) {
  Shiny.setInputValue("mygraph_click", id, {priority: "event"});
};
}"

ui <- fluidPage(
  tags$head(
    tags$style(HTML(css)),
    tags$script(HTML(start_mermaid_js), type = "module"),
    tags$script(HTML(js)),
  ),
  "Here is a Mermaid JS Diagram",
  div(
    class = "html-widget html-widget-output shiny-report-size html-fill-item",
    id = "mygraph",
    pre(
      class = "mermaid",
      txt
    )
  )
)

server <- function(input, output, session) {
  observe({
    cat(sprintf("R detected that in mygraph Node '%s' was clicked\n",
                input$mygraph_click))
  })
}

shinyApp(ui, server)
# When run and clicked on a node, the following would be seen in the R console
#> R detected that in mygraph Node 'A' was clicked
#> R detected that in mygraph Node 'B' was clicked
#> R detected that in mygraph Node 'C' was clicked
#> R detected that in mygraph Node 'D' was clicked

There are two caveats:

  1. renderUI does not work with this setup as mermaid is not rendering the chart again.
  2. the callback function (node_click) needs to be set for every node and the id (mygraph) for the chart is hardcoded. I had hoped that something like the following would work, but it doesnt as the JS code needs to be rerun after mermaid renders a graph
// NOT WORKING
var nodes = document.querySelectorAll('g.nodes > g.node');
console.log(nodes);
alert('nodes: ' + nodes.length);

nodes.forEach(function(node) {
  node.style.cursor = 'pointer';
  node.addEventListener('click', function(){
    var node_id = node.id;
    console.log("Click on node " + node_id);
  // TODO figure out the id of the chart "mygraph" automatically
   Shiny.setInputValue("mygraph_click", id, {priority: "event"});
  });
});

and of course this is not in the DiagrammeR framework. But I hope this might help @rich-iannone or someone else who has enough insider knowledge to implement this in DiagrammeR.