mermaid-js / mermaid

Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown
https://mermaid.js.org
MIT License
72.86k stars 6.66k forks source link

Layered Blocks Layout #3358

Closed rrichardson closed 10 months ago

rrichardson commented 2 years ago

Is your feature request related to a problem? Please describe.

I would prefer to describe APIs and such in terms of layered rectangles, rather than have a scattered array of boxes and curvy arrows.
It makes diagrams easier for me to read, plus this would be very useful for an API Layer diagram, to make it obvious that entity X is part of the foundational layer, where it consumes no other types. Then something at the top layer could all below it.

E.g. something like this, without the description bubbles on the left column. But with the connecting arrows, if desired.

image

Describe the solution you'd like

When working with (say) a class diagram. It would be nice if there was a way to apply an attribute to say that it was part of layer N. This might require an attribute of classDiagram that would be similar to direction such as layout LAYERS or something. The renderer would then create an encompassing rectangle around all classes of the same layer, and the encompassing rectangle would be stacked according to its relative number.

Describe alternatives you've considered

Presently, I think the class diagram is useful for describing dependencies, and the c4 diagram are the closest for providing encompassing rectangles, but neither seem to offer the ability to use a stacked rendering method instead of a graph solver with arrows.

Additional Context

Additional examples:

image

image

Kochise commented 1 year ago

https://text-to-diagram.com/?example=containers&b=mermaid https://github.com/terrastruct/TALA https://github.com/terrastruct/d2

knsv commented 1 year ago

This is a good idea! I have been thinking a bit on rendering and syntax. Here are some sample diagrams: (From above) image

image

and

image

knsv commented 1 year ago

Syntax suggestion for layout (paperware)

Simple block

image
block
  columns 1
  block1[Block 1]

Blocks next to each other

image
block
  columns 2
  block1[Block 1]
  block2[Block 2]

Blocks in a column

image
block
  columns 1
  block1[Block 1]
  block2[Block 2]

Different widths

image
block
  columns 1
  block1[Block 1]

  block
     columns 2
     block2[Block 2]
     block3[Block 3]
  end %% End the compound block

Arrows

image
block
  columns 3
  block1[Block 1]
  <==>
  block2[Block 2]

or (equivalent)

block
  columns 3
  block1[Block 1] <==>  block2[Block 2]

Vertical arrow

image
block
  columns 1
  block1[Block 1]
  ^==v
  block2[Block 2]
knsv commented 1 year ago

Lets try the syntax on one of the example diagrams: image

block
  columns 2

  block["Data Services"]
    columns 2
    block["Relational"]
      columns 1
      mssql["Microsoft SQL<br/>Server"]
    end
    block["Tabular"]
      columns 2
      gds["Google Data Store"]
      mc["Memcache"]
    end
  end

  ^==v

  block["Presentation Services"]
    columns 1
    block
      columns 2
      webui["Web UI"]
      windowsui["Windows UI"]
    end
    uifw["UI F/W"]
  end
jordanroga commented 1 year ago

Here's a modified series of suggestions inspired by the above and some of my thoughts. Some of these are looking to tackle more layout control (a bit more generalized than the initial issue - which I think is a subset of broader control and also tackling https://github.com/mermaid-js/mermaid/issues/2509).

These are just suggestions. I'm not sure how perfectly this is driving on what people want, but it's maybe a few things to think about.

Ultimately targeting something like this:

Screen Shot 2023-07-01 at 11 47 24 AM

The following syntax could be used.

blockDiagram

  classDef blackwpadding color:#ffffff, fill:#000000,padding-bottom:0.1,padding-left:0.1;
  classDef background stroke-width:0;    
  classDef backgroundhalf stroke-width:0,height:0.5;    
  classDef half height:0.5;
  classDef direct sep:false;    

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::blackwpadding
    end
    mysql --- gds
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
      webui --> windowsui
    end
    block:::background
      node:::background
      uifw["UI F/W"]:::direct
      node:::backgroundhalf
      Extra:::half
    end
  webui --v uifw
  windowsui -v- uifw
  end

DataServices  ^--v PresentationServices

Walking through it step by step.

blockDiagram 

  DataServices["Data Services"]
    block PresentationServices["Presentation Services"]
  end

or

blockDiagram

  block DataServices["Data Services"]
  end

  block PresentationServices["Presentation Services"]
  end

yeilds

Screen Shot 2023-07-01 at 10 19 17 AM

Each new block is essentially a positioning element, and with 1 column by default which is vertically orienting the components within it. The number of columns can be overridden by blocks within blocks (nested) or nodes which individually override the layout, more on this below.

Also, I think padding by default should be zero with a need to be explicit through styling by each node (driving impact in closest nested block) or setting up a new default.

blockDiagram

  DataServices["Data Services"]

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 20 37 AM

Arrow/connection directionality is explicit: between middle of the bottom of the node preceding and the middle of the top of the node following it (or middle of the left and middle of the right for sideways arrows).

Thinking it should be similar to flowchart default syntax and styling mostly, no need for thick arrows unless specified. Also thinking location of syntax for arrows doesn’t matter, just the connections since layout is explicit. Connections between variable names of nodes or blocks - similar to graph/node in flowchart (A["Title One"] , B["Title Two"], A-->B).

The single direction downwards (or upwards) oriented arrows could be --v (or --^). The directionally upward/downward arrow-less connection could be -v- (with --- being left/right oriented). Arrows with a default at 0.5 (or similar) of default block height in size with changing length similar to flowchart (maybe 0.125 block height per additional -, like ---->).

Connections act as their own nodes essentially (may want to overlay connections on nodes which might be used only for positioning, touch on this later).

blockDiagram

  block DataServices["Data Services"]
      Relational
   end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 21 10 AM

Blocks by default should act as nodes unless there is at least one node inside it, then blocks provide structuring of layout. Can be titled or not - when there is a title (text associated beyond variable name), add something like 0.5 node height to the block for the title (nodes at same level shouldn’t increase height though). If unnamed no title should be added. The overarching blockDiagram itself acts somewhat like a block with a 1 column vertical orientation.

Styling blocks without associated variable can only be done with with :::className inline and blocks without titles can not have direct connections with the overarching group (only variable associated blocks or nodes within them).

blockDiagram

  block DataServices["Data Services"]
    Relational
    Tabular
  end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 24 33 AM

New nodes fall in line with layout of block (here, default of 1 column).

blockDiagram

  block DataServices["Data Services"]
    columns H
    Relational
    Tabular
  end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 29 59 AM

Here columns H recognizes a number of columns defined by the nodes within the block, default sizing (of each 1 column) should be determined by the greater of a standard size or max width of default of text or wrapped text (or max width with new lines given markdown-like). This can be explicitly defined as well, see below.

blockDiagram

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    Tabular
  end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 33 21 AM
blockDiagram

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2
    end
  end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 35 04 AM

The explicit definition of the number of columns in a block defines its layout and the explicit definition of nodes taking up those columns can help define layout more precisely. columns H should have the same result, but if was instead mc:1, columns 3 would have an empty space equivalent to an additional column (with nodes/ blocks left aligned within block), whereas H is more dynamic.

blockDiagram

  classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
    end
  end

  block PresentationServices["Presentation Services"]
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 10 49 13 AM

Nodes and blocks should be able to be styled in a similar manner to nodes and subgraphs in a flowchart.

blockDiagram

  classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
    end
  end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui[“Windows UI”]
    end
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 11 13 08 AM

Because the columns are dynamically determined horizontally (by columns H), there are two columns in the unnamed block.

blockDiagram

  classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
    end
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui[“Windows UI”]
    end
    block
      uifw["UI F/W"]
    end 
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 11 18 16 AM

A new unnamed block with one column adding a new node, has it centered, because this is a new block it is below the block nested above it. Both are within a block with a default of one column with a preference for vertical orientation.

blockDiagram

   classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
  columns H
      block Relational
      mssql["Microsoft SQL<br/>Server"]
      end
      block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
      end
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui[“Windows UI”]
    end
    block
      columns H
      uifw["UI F/W"]:2
    end

  end
DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 11 20 33 AM

Explicitly defining the node to have two columns will override the default of one column (while maintaining a vertical orientation of the block), but the block will overall take up two columns.

blockDiagram

  classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
  columns H
      block Relational
        mssql["Microsoft SQL<br/>Server"]
      end
      block Tabular
        columns 3
        gds["Google Data Store"]:1
        mc["Memcache"]:2:::black
      end
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui[“Windows UI”]
    end
    block
      node
      uifw["UI F/W"]
      node
    end   
  end

DataServices  ^--v PresentationServices

yields

Screen Shot 2023-07-01 at 11 20 57 AM

Adding blank nodes can be useful for positioning elements in a block diagram and can be ignored for content. The orientation of these blocks is maintained as the default vertical orientation and the default columns of 1 is not overridden by any nodes.


blockDiagram

  classDef black color:#ffffff, fill:#000000;
  block DataServices["Data Services"]
   columns H
   block Relational
      mssql["Microsoft SQL<br/>Server"]
   end
   block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
    end
  end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
    end
    block
      node
      uifw["UI F/W"]
      node
    end
  end

DataServices  ^--v PresentationServices
webui --v uifw
windowsui --v uifw

yields

Screen Shot 2023-07-01 at 11 24 27 AM

Blank nodes can be overlaid by connections (any node can connect to any other, but overlay on top of blank nodes is useful for ensuring clean diagrams). When arrows are overlaying blank nodes, they are not taking up any of their own space (with default of 0.5 node height), otherwise (when overlaying other nodes or blocks which are not blank, they should still connect to the appropriate position on those blocks or nodes, but should only take up their own specified size with a default of 0.5). themselves By default, multiple connections should have some positioning away from the center of the connected node (second one; B, in A --v B). A class style element of sep could be used to adjust this in class definitions and also as part of global styling to directly connect to the center of connected nodes even when there are multiple connections.

blockDiagram

classDef black color:#ffffff, fill:#000000;

  block DataServices["Data Services"]
  columns H
      block Relational
        mssql["Microsoft SQL<br/>Server"]
      end
      block Tabular
        columns 3
        gds["Google Data Store"]:1
        mc["Memcache"]:2:::black
      end
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
    end
    block
      node:::background
      uifw["UI F/W"]
      node:::background
    end
  end
DataServices  ^--v PresentationServices
webui --v uifw
windowsui -v- uifw

yields

Screen Shot 2023-07-01 at 11 29 53 AM

Styling can still be applied to blank nodes, but it must be inline (often will want them to disappear, maybe a built in class to align with background of block nested would be nice).

blockDiagram

  classDef black color:#ffffff, fill:#000000;
  classDef background stroke-width:0;    

  block DataServices["Data Services"]
   columns H
   block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::black
    end
  end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
      webui --> windowsui
    end
    block
      node:::background
      uifw["UI F/W"]
      node:::background
    end
  end

DataServices  ^--v PresentationServices
webui --v uifw
windowsui -v- uifw

yields

Screen Shot 2023-07-01 at 11 42 27 AM
blockDiagram
   classDef black color:#ffffff, fill:#000000;
   classDef background stroke-width:0;    
   classDef backgroundhalf stroke-width:0,height:0.5;    
   classDef half height:0.5;

  block DataServices["Data Services"]
  columns H
      block Relational
        mssql["Microsoft SQL<br/>Server"]
      end
      block Tabular
        columns 3
        gds["Google Data Store"]:1
        mc["Memcache"]:2:::black
      end
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
    webui --> windowsui
    end
    block:::background
      node:::background
      uifw["UI F/W"]
      node:::backgroundhalf
    Extra:::half
    end
  end
DataServices  ^--v PresentationServices
webui --v uifw
windowsui -v- uifw

yields

Screen Shot 2023-07-01 at 11 44 28 AM
blockDiagram

  classDef blackwpadding color:#ffffff, fill:#000000,padding-bottom:0.1,padding-left:0.1;
  classDef background stroke-width:0;    
  classDef backgroundhalf stroke-width:0,height:0.5;    
  classDef half height:0.5;
  classDef direct sep:false;    

  block DataServices["Data Services"]
    columns H
    block Relational
      mssql["Microsoft SQL<br/>Server"]
    end
    block Tabular
      columns 3
      gds["Google Data Store"]:1
      mc["Memcache"]:2:::blackwpadding
    end
    mysql --- gds
   end

  block PresentationServices["Presentation Services"]
    block
      columns H
      webui["Web UI"]
      windowsui["Windows UI"]
      webui --> windowsui
    end
    block:::background
      node:::background
      uifw["UI F/W"]:::direct
      node:::backgroundhalf
      Extra:::half
    end
  webui --v uifw
  windowsui -v- uifw
  end

DataServices  ^--v PresentationServices
Screen Shot 2023-07-01 at 11 47 24 AM

Here, the turning off of the sep styling element for the class applied to uifw node directs the connections coming to the middle of the top of the element even though there are more than one. Adding padding as a styling element can shift the blocks within which a node (or block) is nested in size to add room for the padding associated.

Using this framework, there are a few things which could be more addressable.

This diagram does not render as expected because the renderer makes decisions which are not perfectly aligned with what the editor may want. This is an instance of the same problem as https://github.com/mermaid-js/mermaid/issues/2509.

Utilizing this proposed syntax, the intent of an editor could be expressed through the following:

blockDiagram

  block One
    columns H
    A
    B
    C
    A --> B
    B --> C
  end

  block Two
    columns H
    D
    E
    F
    D --> E
    E -->  F
  end

  block Three
    columns H
    G
    H
    I
    G --> H
    H --> I
  end

  C --v D
  F --v G

This would yield the following.

Screen Shot 2023-07-02 at 6 48 26 PM

Utilizing this proposed syntax, the intent of an editor looking to produce something similar to the first example in this could be something reflected through something like the following.

blockDiagram

  classDef background stroke-width:0;    

  block(""):::background
    columns H
    ApplicationLayer("Application Layer")
    block
      columns H
      UserInterface("User Interface (WPF, HTML5/CSS3, Swing)"):3
    end
  end

  block:::background
    columns H
    PresentationLayer["Presentation Layer"]
    block("")
      columns H
      Smack["J2SE Mobil App (Smack)"]
      JsJAC["Java Script Browser App (JsJAC)"]
      babelim[".NET Windows App (Babel-im)"]
    end
  end

  block:::background
    columns H
    SessionLayer("Session Layer")
    block("")
      columns H
      XMPP["XMPP Component"]
      block
        Authentication
        Authorization
      end
      LDAP["LDAP, DB, POP"]
    end
  end

  block:::background
    columns H
    NetworkLayer("Network Layer")
    block("")
      columns H
      HTTP[HTTP]:1.5
      SOCK[SOCK]:1.5
    end
  end

  block:::background
    columns H
    DataLayer("Data Layer")
    block("")
      columns H
      XMPP[XMPP]
      BDB["Business DB"]
      AD["Active Directory"]
    end
  end

I've not added the padding here, but this should yield the following.

Screen Shot 2023-07-02 at 1 59 54 PM

Utilizing this proposed syntax, the intent of an editor looking to produce something similar to the third example in this could be something reflected through something like the following.

%%{ init : { "theme" : "default", "blockDiagram" : { "sep" : "false" }}}%%

blockDiagram
  classDef rot8 height:8,rot:270;  

  columns H
  BareMetal:::rot8

  block
  ApplicationLayer["Application Layer"]:4

  block
    BSD
    WLAN
    Network
    BTBLE
  end

  WiseConnect:4

  block Interface
    UART
    SPI
    USB
    SDIO
  end

  block Hardware
    UARTH
    SPIH
    USBH
    SDIOH
  end

  ApplicationLayer ^--v BSD
  ApplicationLayer ^--v WLAN
  ApplicationLayer ^--v Network
  ApplicationLayer ^--v BTBLE

  BSD ^--v WiseConnect
  WLAN ^--v WiseConnect
  Network ^--v WiseConnect
  BTBLE ^--v WiseConnect

  WiseConnect ^--v Interface

  UART ^--v UARTH
  SPI ^--v SPIH
  USB ^--v USBH
  SDIO ^--v SDIOH

  end

This could yield something like the following.

Screen Shot 2023-07-02 at 2 40 41 PM

Here the rot class variable could recognize text rotation to align with the block height, this is maybe a bit clunky, but also keeps the organization of the blocks aligned with the rest of the diagram. The connections in between interface and hardware nested nodes overlay the hardware element but only take up 0.5 height of space (this is node a blank block or node). This is similar to the example with directionality above as well.

These are all just a bunch of suggestions. I'm not sure how other people might feel or how the challenges associated with how these might be implemented.

knsv commented 1 year ago

Great work @jordanroga!

I like the addition of the auto column count where you don't have the need to set it automatically columns 'H' could actually be the default value. I also like the addition of setting the width of the block.

Good that you included the vertical layout. Instead of a class this should probably be a part of the syntax directly as a specific feature as it will affect the rendering more that a rotations. If you have internal blocks in the vertical block for instance.

I also approve of keeping the syntax close to Mermaid flowcharts as you have it in your examples.

Another area that should be defined is block arrows vs edges. Edges chould be defined as in flowcharts: -->, <-- and <-->

block arrows are probable something else:

blockDiagram
columns 1
A
blockArrow
B
image
blockDiagram
A
blockArrow
B
image
blockDiagram
columns 1
A
blockArrow(1,3)
block tripple
   columns 3
     B
     C
     D
end
image

Likewise, the padding between blocks and alignment of sibling blocks as for instance on the same row needs a simple mechanism. You could opt for:

Padding: blocks can either have a space around them or not...

knsv commented 1 year ago

My take on the initial example, in principal the same with some simplifications:

blockDiagram

  classDef background stroke-width:0;    

  block
    ApplicationLayer("Application Layer")
    block
      UserInterface("User Interface (WPF, HTML5/CSS3, Swing)"):3
    end
  end

  block
    PresentationLayer["Presentation Layer"]
    block
      Smack["J2SE Mobil App (Smack)"]
      JsJAC["Java Script Browser App (JsJAC)"]
      babelim[".NET Windows App (Babel-im)"]
    end
  end

  block
    SessionLayer("Session Layer")
    block
      XMPP["XMPP Component"]
      block[]
        Authentication
        Authorization
      end
      LDAP["LDAP, DB, POP"]
    end
  end

  block
    NetworkLayer("Network Layer")
    block
      columns 2
      HTTP[HTTP]
      SOCK[SOCK]
    end
  end

  block
    DataLayer("Data Layer")
    block
      XMPP[XMPP]
      BDB["Business DB"]
      AD["Active Directory"]
    end
  end

Again, imagine the padding:

Screen Shot 2023-07-02 at 1 59 54 PM
nirname commented 1 year ago

Perhaps some of the ideas are already there, I'll leave a comment there to make it as clear as possible.

Auto columns

Amount of columns are automatically calculated. So specifying it is redundant.

The only scenario where we would need to specify this columns 'H' is where we have some other default for the whole graph, e.g.

mermaid.initialize({
  theme: 'default',
  block: {
    columns: 3,
  },
});

and only then we would redefine this behavior for specific bock

block-beta

block
  block app
    columns auto %% or
    columns H %% or
    columns 5 
  end
end

I found auto keyword to be more descriptive than H letter. May be columns 0 is ok as a default value too

Diagram name coincides with keyword inside

We are trying to shorten the names of the diagrams, so we would like to support block diagram name instead of or along with blockDiagram keyword. We are also -beta suffix to mark the diagrams which syntax can change. Thus given block-beta form after removing the -beta suffix the name of the graph will coincide with block keyword:

block-beta => block

Which is actually not bad at all, because we can consider the whole graph as if it is one block. So the graph itself is a tree represented by one root node. That probably means that we could support the same attributes for the whole graph as for the block. Like layout direction.

Layout direction

Speaking about ^--v arrows, I think they are redundant, because we also have other things like diagonal arrows. Instead I would suggest using columns attribute or direction attribute and wrap elements to be rearranged in empty block. Otherwise it will end up in updating all the arrows

Given

block-beta

block app["Application"]
direction LR
app --> client
app --> admin
client <--> admin
client["Client Application"]
admin["Admin Application"]
end

direction=TB

direction=LR

Direction is inspired by dot language as well as flex-direction attribute.

Layout direction auto-change

Layout direction for nested blocks must be switched automatically

block-beta
direction TB

block row1
  col1
  col2
  col3
end
block row2
  col1
  col2
  col3
end
block row3
  col1
  col2
  col3
end

The same graph with direction LR

Referencing items

Since this very graph is a tree sometimes it could be more convenient to reference specific items of that tree. So we could avoid conflicts if a block is having the descendants with the same components as another block

block-beta
direction TB
block row1
  col1
  col2
  col3
end
block row2
  col1
  col2
  col3
  col1 --> row1:col2
  col2 --> row1:col3
end
block row3
  col1
  col2
  col3
  col1 --> row2:col2
  col2 --> row2:col3
end

Width

Not sure about width property. Perhaps this digit 3 shows that the width of that block equals to 3 columns:

UserInterface("User Interface (WPF, HTML5/CSS3, Swing)"):3

But in that very example it must be omitted, I think the default behavior should be 'max' (or may be 'min'), depending on graph properties. And that is not obvious what to do in case if one line contains 2 elements and the other contains 3. Perhaps we need a percentage. If a child block is only one, that its width is 100%. If there are 2 blocks, and they have like width modifiers set to 1 and 3 respectively, than their width is 25% and 75%. By default that modifier should be equal to 1. Or may be we need to support any other css / svg attributes

nirname commented 1 year ago

Should we rename our diagram to layered-blocks or layered? To my mind it better reflects its designation

vassudanagunta commented 1 year ago

While I understand the usefulness of these types of diagrams, I don't think they should be added to Mermaid unless a syntax is devised that is consistent with Mermaid's fundamental ethos:

Perhaps the problem is simply that my brain has grown stiff with age. Perhaps ya'll can read[^1] the various syntax examples above and the meaning is evident. If that's the case, please disregard this comment. 😊🙃🤪

But otherwise, if one has to render the Mermaid source to see the meaning, what is the advantage over just using SVG? If one is looking at the a diff before a git commit or when examining git history to understand changes to a diagram, and one ends up needing to render both versions to comprehend the change, there is no advantage over SVG, only disadvantages (SVG is far more flexible. You can draw exactly the diagram you want). You can see minor changes like spelling or label changes in the git diff for SVG just as well as you can for the above syntaxes.

I don't know if an "easy to comprehend textual description translatable to a graphic" is possible for these types of diagrams, but for starters, nix the keywords 'block' and 'column'. Those are layout instructions, not semantics.

If no such syntax is possible, just say no. 😉

[^2]: For example, the syntax for flow chart and sequence diagrams represent the same abstract semantics of the graphical rendering, but in text. A follows B. C follows B. Client invokes Service. etc. The proposals for Venn diagram syntax (I'm working on a proposal for it as well) would also represent the same content, just in text.

[^1]: Note I wrote "read", not "parse". If you are implementing a parser and renderer in your mind to get the meaning, I contend the syntax goes against what makes Mermaid good.

nirname commented 1 year ago

@vassudanagunta Please, propose the syntax you think is correct

knsv commented 1 year ago

@vassudanagunta I agree with your sentiment. The point is that the diagram should be readable as text as well. Saying that we could just as easy use svgs seems a little exaggerated though. I believe we will find a better syntax then that.

Syntax summary

The format of this thread is not working anymore with different versions of the proposed syntax. I will collect the latest. syntax here: https://github.com/mermaid-js/mermaid/wiki/Block-Diagram-(WIP)

The we can discuss in around that.

knsv commented 1 year ago

@nirname Thanks for your input. I have updated the wiki page with most of your suggestions.

nirname commented 1 year ago

I have been thinking about this "columns" attribute for graph and block and I have doubts about it.

To my mind, we have to reconsider this "columns" property, because having amount of columns alongside "amount of columns occupied" attribute for the node influence the whole layout and forces user to change each and every node attribute.

Assume we are dealing with this

block-beta
block System
  columns 3
  front:1
  back:1
end

And now I would like to change the size of one of the blocks (by some obscure reason) to 1/4 (25%), thus

block-beta
block System
  columns 12 %% 3 does not work anymore, I need 1/2 for one block and 1/3 for another, thus 4*3 and we are much alike bootstrap or material design in a 12-columns grid layout
  front:4 %% this used to be 1/3, now it becomes 4/12
  back:3 %% this is what we were up to, change it
end

Perhaps it have some consistency, but changing columns property perhaps will ruin the whole graph. Moreover: column-oriented grid systems are responsive, so they behave differently on different sizes of screens. That is probably what a user expected from it.

It may be of some use, though, because it serves as "word wrap", but this is not the task.

Why do users use this simple text notation?

Because they want the layout to be done for them

Why do we need to manually move the nodes or blocks?

Because we are not happy with the layout, but why? Because some lines are entangled, graph is not flattened, we want different length for links and want some nodes to be on the same level, coupled together. So it is not about fixing the layout at all, it is about giving instructions for our layout algorithm to make it happen.

Like Graphviz does

{
node[rank="same"]
A -> B
}

If this is the case, e.g. if we would like our nodes to be on the same level image

this means that this layout must be consistent regardless of other possible nodes

block

block SystemA
  proxy 1 : proxy-level
  app 1 : app-level
end

block SystemB
  proxy 2 : proxy-level
  middleware
  app 2 : app-level
  database
end

image

We probably have to get rid of "column" property at all.

The open question is should an arrow between 2 nodes act like a leveler or not

knsv commented 1 year ago

@nirname Perhaps a call to work this out.

nirname commented 1 year ago

What should we do if we add an edge between block and its content?

block

block A
  B --> C
end
A --> C
Yokozuna59 commented 1 year ago

@knsv @nirname since the langium parser has been merged #4727, should we implement the parser in langium?

nirname commented 1 year ago

@Yokozuna59 I think we can give it a shot

wuleninja commented 1 year ago

This proposition looks like the closest to what would allow me to do UI mockups with Mermaid!

BryanCrotazGivEnergy commented 1 month ago

Trying this out, can't see how to name a composite block - no matter what I try it renders the parent block name as a child block