magjac / d3-graphviz

Graphviz DOT rendering and animated transitions using D3
BSD 3-Clause "New" or "Revised" License
1.67k stars 103 forks source link

Multiple graphs within same SVG #275

Closed papinto closed 1 year ago

papinto commented 1 year ago

This is more of a feature request. Can you add support for rendering multiple graphs within the same SVG?

I tried to do this with the following code:

const firstGraph = `
digraph {
  id=firstGraph;   
  a -> {b c};   
  a [id=node_a];
  b [id=node_b];
  c [id=node_c];
}`

const secondGraph = `
digraph {
  id=secondGraph ;   
  {d e} -> f;   
  d [id=node_d];
  e [id=node_e];
  f [id=node_f];
}
`
const renderSecondGraph = () => {
  graphviz("#graph")
    .keyMode("id")
    .renderDot(secondGraph)
}

const renderFirstGraph = () => {
  graphviz("#graph")
    .keyMode("id")
    .renderDot(firstGraph , renderSecondGraph)
}

renderFirstGraph()

When the renderSecondGraph function executes, it will replace the first graph with the second graph, even though they are different graphs using different ids.

After renderFirstGraph we get:

<div id="graph">
  <svg ...>
    <g id="firstGraph">...</g>
  </svg>
</div>

After renderSecondGraph we get:

<div id="graph">
  <svg ...>
    <g id="secondGraph">...</g>
  </svg>
</div>

What I would like to get instead:

<div id="graph">
  <svg ...>
    <g id="firstGraph">...</g>
    <g id="secondGraph">...</g>
  </svg>
</div>

Not sure if this is possible or how best to achieve it, but I imagine trying to follow the D3 pattern of datums, where the dot string is the data, we could have dot() and renderDot() functions that take in an array of strings. so the code would become:

const renderBothGraphs = () => {
  graphviz("#graph")
    .keyMode("id")
    .renderDot([firstGraph, secondGraph])
}

Hope the request is clear. Thank you for this library.

magjac commented 1 year ago

This library uses a port of Graphviz so the rendered SVG is what Graphviz renders. No more. No less. So you would need to find a way to have Graphviz render what you want.Then you will be able to render the same SVG with d3-graphviz. I think however that Graphviz would generate an SVG file containing two SVG elements in your case and I don't think this is even a valid SVG file.

papinto commented 1 year ago

Thanks for the reply. I found a solution which is to render the graph in another element and then move it:

  const secondGraphGroup = select<BaseType, unknown>("#secondGraph").remove()
  select("#graph")
    .select("svg")
    .append<BaseType>(() => secondGraphGroup.node())