Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

language/API for manual layout and design #2483

Open
maiermic opened this issue Nov 13, 2021 · 6 comments
Open

language/API for manual layout and design #2483

maiermic opened this issue Nov 13, 2021 · 6 comments
Labels
Contributor needed Status: Pending Is not to be executed as it currently is Type: Enhancement New feature or request

Comments

@maiermic
Copy link
Contributor

Prolog

There are a lot of issues about changing the layout and/or design, e.g.

I like the concise syntax of Mermaid's languages that are focused on a certain kind of diagram. However, the diagrams can only be extended/modified to a limited degree. The auto layout is handy in some case, but I often find the layout not appealing (e.g. the alignment of nodes).

I'd like to suggest a new way to create diagrams that does not use dagre. My suggestion is not primarily about syntax, but about the concept behind it. Hence, I use JavaScript code to describe my examples.

Concept (Main Idea)

My idea is inspired by the way how TikZ works in Latex (example). Even though I wouldn't use the same syntax 😉

The position of nodes are defined in relation to each other. A node has a bounding box with a coordinate (top left corner) and a dimension (width and height). Further, we define the following coordinates based on the bounding box definition:

  • center
  • cardinal points:
    • north
    • northEast
    • east
    • southEast
    • ...

coordinates.svg

An edge is basically just defined by it's start and end position.

Base Example

Let's write something similar to this flowchart

flowchart LR
    A-->B
Loading

flowchart-example.svg

function rightOf(node, gap=50) {
  return {
    x: node.east.x + gap,
    y: node.y,
  }
}

const n1 = rect()
const n2 = Object.assign(rect(), rightOf(n1))

const svgExample = renderDiagram({
  nodes: [n1, n2],
  edges: [edge(n1.east, n2.west)],
})

Runnable example

Different Directions

That syntax is kind of verbose and the example is boring 😒 Let's add some functions to spice it up 🌶️ 😁 Our diagram will look like this

flowchart-example-2.svg

const n1 = rect({fill: 'red', stroke: 'darkred'})
const n2 = rect({fill: 'yellow', stroke: 'orange'})
const n3 = rect({fill: 'lightblue', stroke: 'blue'})
const n4 = rect({fill: 'green', stroke: 'darkgreen'})

const diagram = createDiagram([
  [n1, right`-->`, n2],
  [n2, right`-->`, n3],
  [n2, below`-->`, n4],
])
const svgExample = renderDiagram(diagram)

Runnable example

Related Example

I'm still playing around with the technology. It works quite well so far. The objects used in the calculations require a bounding box. A mapping of those objects to (virtual) SVG elements is required to render them. While I was playing around, I re-implemented this diagram that I found in a related way

My implementation renders like this

git-workflow-example.svg

It's missing the tags at the top and some details look different (e.g. stroke width), but this could be adjusted 😉 I decided to calculate the layout in renderGitWorkflow. However, this function/logic could be split in its two concerns/responsibilities: creating and rendering diagram. For example, logic could be extracted as function createGitWorkflowDiagram in such a way that the returned result could be passed to renderDiagram, i.e.

const svgExample = renderDiagram(createGitWorkflowDiagram({
  branches: [
    masterBranch,
    hotfixBranch,
    releaseBranch,
    ...
  ],
  commitOrder: [
    [masterCommit1],
    [hotfixCommit1, developCommit1, feature2Commit1],
    [masterCommit2, developCommit2, feature2Commit2],
    ...
  ],
  edges: [
    edge(masterCommit1, hotfixCommit1),
    edge(masterCommit1, masterCommit2),
    ...
  ],
}))

Runnable example

This example shows that it is easy to define custom layouts or DSLs in JS 🤓 renderDiagram could be re-used between the different examples if it is designed well. Probably, it may be a class DiagramRenderer that could be configured and extended as needed. I'm still thinking about how the API should look like 😅

Epilog

I created this issue to get feedback on the approach and start a discussion. It is quite different to the current approaches (custom language + rendering and layout with dagre). Even though a new language could be added for my approach to hide the details in the library, I think that it is more powerful to re-use JavaScript and only provide an API (like shown in my examples). I'm still unsure how it should look like, but I learn from every example that I implement. Maybe you like to play with it, too, or share your thoughts ☺️

@maiermic maiermic added Status: Triage Needs to be verified, categorized, etc Type: Enhancement New feature or request labels Nov 13, 2021
@maiermic
Copy link
Contributor Author

I used https://www.diagrams.net/ to create the SVG that visualizes the cardinal points:

coordinates.svg

I now rewrote it using my approach (running example) and the result looks like this:
coordinates.svg

@abitrolly
Copy link
Contributor

It looks nice. However, my use case is fixing mermaid to respect order of nodes mentioned in flowchart definition, and with dagre being archived, the question is - how it all works? Comparing dagre with plan JS that does manual layout could greatly help to understand how mermaid works better.

Maybe even help to draw rhe diagram that shows how mermaid itself works. :D

@dnlmc
Copy link

dnlmc commented Mar 1, 2023

I have to imagine there is significant demand for more manual customization such as this, has the core team taken a perspective on this sort of direction?

@jgreywolf
Copy link
Contributor

jgreywolf commented Mar 8, 2023

We are very interested in adding such a solution. That might have to be a different type of diagram though with different syntax dedicated specifically for this purpose.

A host of new possibilities has opened up with the lazy loading of diagrams, as well as support from Mermaid Chart

@jgreywolf jgreywolf added Status: Pending Is not to be executed as it currently is Contributor needed and removed Status: Triage Needs to be verified, categorized, etc labels Mar 8, 2023
@inoas-nbw
Copy link

This would be a game changer for us.
What would also be great is if certain parts of a diagram are manually managed in layouting, aka sub-parts of the diagram.
As a note, plantuml also does some manual layouting, just maybe take a peek there or support their manual layouting also for mermaid to be able to load their format.

@rngtng
Copy link

rngtng commented Sep 3, 2024

Thanks for the effort to explore options here. For me, the missing option of manual layout is the biggest drawback of mermaid. Quite often the auto-layout is just too messing and has e.g. crossing lines without reasons...

I very much like the way structurizr solved it. They support an (optional) additional file to save the coordinates. See here https://docs.structurizr.com/ui/diagrams/manual-layout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Contributor needed Status: Pending Is not to be executed as it currently is Type: Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants