Merge branch '5237-unified-layout-common-renderer' into sidv/5237

* 5237-unified-layout-common-renderer:
  Tweaking spacings for elk and confurinable network placement strategy
  #5237 Elk spacing tweak and fix for fonthandling in directives
  #5237 Handling label size for elk layout
  #5237 Handling paddings in subgraphs for state diagrams
  #5237 Handling paddings in subgraphs for state diagrams
This commit is contained in:
Sidharth Vinod 2024-05-24 14:50:03 +05:30
commit e5069083c9
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
12 changed files with 9183 additions and 11463 deletions

View File

@ -75,7 +75,137 @@
</style>
</head>
<body>
<pre id="diagram" class="mermaid2">
%%{
init: {
"theme":"base",
"fontFamily": "Kalam",
"themeVariables": {
"background": "#FFFFFF",
"primaryColor": "#7bdfa7",
"primaryTextColor": "#3c3c3b",
"secondaryColor": "#642470",
"secondaryTextColor": "#3c3c3b",
"tertiaryColor": "#1c736D",
"tertiaryTextColor": "#3c3c3b",
"noteBkgColor": "#9fd8ef",
"loopTextColor": "#636362",
"labelBoxBkgColor": "#642470",
"labelBoxBorderColor": "#642470",
"labelTextColor": "#d4d4d4",
"signalTextColor": "#636362",
"signalColor": "#642470"
}
}
}%%
sequenceDiagram
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
John-->>-Alice: I feel great!
</pre
>
<pre id="diagram" class="mermaid2">
%%{
init: {
"theme":"base",
"fontFamily": "Forth Bold",
"themeVariables": {
"background": "#FFFFFF",
"primaryColor": "#7bdfa7",
"primaryTextColor": "#3c3c3b",
"secondaryColor": "#642470",
"secondaryTextColor": "#3c3c3b",
"tertiaryColor": "#1c736D",
"tertiaryTextColor": "#3c3c3b",
"noteBkgColor": "#9fd8ef",
"loopTextColor": "#636362",
"labelBoxBkgColor": "#642470",
"labelBoxBorderColor": "#642470",
"labelTextColor": "#d4d4d4",
"signalTextColor": "#636362",
"signalColor": "#642470"
}
}
}%%
sequenceDiagram
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
John-->>-Alice: I feel great!
</pre
>
<pre id="diagram" class="mermaid">
%%{init: {"layout": "elk", "mergeEdges": true} }%%
stateDiagram
direction TB
T00 --> T0
T00 --> T1
</pre
>
<pre id="diagram" class="mermaid">
%%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "NETWORK_SIMPLEX"} }%%
stateDiagram
State T0 {
direction LR
A --> B
}
State T1 {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "dagre", "mergeEdges": true} }%%
stateDiagram
direction TB
State T1 {
T11
}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "dagre", "mergeEdges": true} }%%
stateDiagram
State T1 {
T21
--
T22
}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "elk", "mergeEdges": true} }%%
stateDiagram
direction TB
State T1 {
T11
}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "elk", "mergeEdges": true} }%%
stateDiagram
State T1 {
T21
--
T22
}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "elk", "mergeEdges": true} }%%
stateDiagram
[*] --> T1
T1 --> T2
T1 --> T3
T1 --> T4
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"layout": "elk"} }%%
stateDiagram
[*] --> T1
@ -85,7 +215,7 @@ stateDiagram
T1 --> T3
</pre
>
<pre id="diagram" class="mermaid">
<pre id="diagram" class="mermaid2">
stateDiagram
State1: The state with a note
note right of State1
@ -94,8 +224,9 @@ stateDiagram
end note
</pre
>
<pre id="diagram" class="mermaid">
<pre id="diagram" class="mermaid2">
stateDiagram-v2
direction LR
[*] --> Active
state Active {
@ -106,445 +237,31 @@ stateDiagram-v2
%% Outer --> Inner
</pre
>
<pre id="diagram" class="mermaid2">
stateDiagram
direction TB
accTitle: This is the accessible title
accDescr: This is an accessible description
classDef notMoving fill:white,color:#000
classDef movement font-style:italic;
classDef badBadEvent fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow
[*] --> Still:::notMoving
Still --> [*]
Still --> Moving:::movement
Moving --> Still
Moving --> Crash:::movement
Crash:::badBadEvent --> [*]
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"look": "classic"} }%%
stateDiagram-v2
TN3: The state with a note
note right of TN3
Important information! You can write
notes.
end note
TN3 --> TN4
note left of TN4 : This is the note to the left.
</pre
>
<pre id="diagram" class="mermaid2">
block-beta
A["square"]
B("rounded")
C(("circle"))
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A>"rect_left_inv_arrow"]
B{"diamond"}
C{{"hexagon"}}
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A(["stadium"])
</pre>
<pre id="diagram" class="mermaid2">
block-beta
%% A[["subroutine"]]
%% B[("cylinder")]
C>"surprise"]
</pre>
<pre id="diagram" class="mermaid2">
block-beta
A[/"lean right"/]
B[\"lean left"\]
C[/"trapezoid"\]
D[\"trapezoid"/]
</pre>
<pre id="diagram" class="mermaid2">
flowchart
B
style B fill:#f9F,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram" class="mermaid2">
flowchart LR
a1 -- apa --> b1
</pre>
<pre id="diagram" class="mermaid2">
flowchart RL
subgraph "`one`"
a1 -- l1 --> a2
a1 -- l2 --> a2
end
</pre>
<pre id="diagram" class="mermaid2">
flowchart RL
subgraph "`one`"
a1 -- l1 --> a2
a1 -- l2 --> a2
end
</pre>
<pre id="diagram" class="mermaid2">
flowchart
id["`A root with a long text that wraps to keep the node size in check. A root with a long text that wraps to keep the node size in check`"]</pre
>
<pre id="diagram" class="mermaid2">
flowchart LR
A[A text that needs to be wrapped wraps to another line]
B[A text that needs to be<br/>wrapped wraps to another line]
C["`A text that needs to be wrapped to another line`"]</pre>
<pre id="diagram" class="mermaid2">
flowchart LR
C["`A text
that needs
to be wrapped
in another
way`"]
</pre
>
<pre id="diagram" class="mermaid2">
classDiagram-v2
note "I love this diagram!\nDo you love it?"
</pre>
<pre id="diagram" class="mermaid2">
stateDiagram-v2
State1: The state with a note with minus - and plus + in it
note left of State1
Important information! You can write
notes with . and in them.
end note </pre
>
<pre id="diagram" class="mermaid2">
mindmap
root
Child3(A node with an icon and with a long text that wraps to keep the node size in check)
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"theme": "forest"} }%%
mindmap
id1[**Start2**<br/>end]
id2[**Start2**<br />end]
%% Another comment
id3[**Start2**<br>end] %% Comment
id4[**Start2**<br >end<br >the very end]
</pre>
<pre id="diagram" class="mermaid2">
mindmap
id1["`**Start2**
second line 😎 with long text that is wrapping to the next line`"]
id2["`Child **with bold** text`"]
id3["`Children of which some
is using *italic type of* text`"]
id4[Child]
id5["`Child
Row
and another
`"]
</pre>
<pre id="diagram" class="mermaid2">
mindmap
id1("`**Root**`"]
id2["`A formatted text... with **bold** and *italics*`"]
id3[Regular labels works as usual]
id4["`Emojis and unicode works too: 🤓
शान्तिः سلام 和平 `"]
</pre>
<pre id="diagram" class="mermaid2">
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM]
core0 --- core2
rom --> core2
end
subgraph amd["`**AMD** Latte GPU`"]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<pre id="diagram" class="mermaid2">
%%{init: {"flowchart": {"defaultRenderer": "elk", "htmlLabels": false}} }%%
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM]
core0 --- core2
rom --> core2
end
subgraph amd["`**AMD** Latte GPU`"]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<br />
<pre id="diagram" class="mermaid2">
flowchart TB
%% I could not figure out how to use double quotes in labels in Mermaid
subgraph ibm[IBM Espresso CPU]
core0[IBM PowerPC Broadway Core 0]
core1[IBM PowerPC Broadway Core 1]
core2[IBM PowerPC Broadway Core 2]
rom[16 KB ROM]
core0 --- core2
rom --> core2
end
subgraph amd[AMD Latte GPU]
mem[Memory & I/O Bridge]
dram[DRAM Controller]
edram[32 MB EDRAM MEM1]
rom[512 B SEEPROM]
sata[SATA IF]
exi[EXI]
subgraph gx[GX]
sram[3 MB 1T-SRAM]
end
radeon[AMD Radeon R7xx GX2]
mem --- gx
mem --- radeon
rom --- mem
mem --- sata
mem --- exi
dram --- sata
dram --- exi
end
ddr3[2 GB DDR3 RAM MEM2]
mem --- ddr3
dram --- ddr3
edram --- ddr3
core1 --- mem
exi --- rtc
rtc{{rtc}}
</pre
>
<br />
&nbsp;
<pre id="diagram" class="mermaid2">
flowchart LR
B1 --be be--x B2
B1 --bo bo--o B3
subgraph Ugge
B2
B3
subgraph inner
B4
B5
end
subgraph inner2
subgraph deeper
C4
C5
end
C6
end
B4 --> C4
B3 -- X --> B4
B2 --> inner
C4 --> C5
end
subgraph outer
B6
end
B6 --> B5
</pre
>
<pre id="diagram" class="mermaid2">
sequenceDiagram
Customer->>+Stripe: Makes a payment request
Stripe->>+Bank: Forwards the payment request to the bank
Bank->>+Customer: Asks for authorization
Customer->>+Bank: Provides authorization
Bank->>+Stripe: Sends a response with payment details
Stripe->>+Merchant: Sends a notification of payment receipt
Merchant->>+Stripe: Confirms the payment
Stripe->>+Customer: Sends a confirmation of payment
Customer->>+Merchant: Receives goods or services
</pre
>
<pre id="diagram" class="mermaid2">
mindmap
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
British popular psychology author Tony Buzan
Research
On effectiveness<br/>and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
Pen and paper
Mermaid
</pre>
<br />
<pre id="diagram" class="mermaid2">
example-diagram
</pre>
<!-- <div id="cy"></div> -->
<!-- <script src="http://localhost:9000/packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script> -->
<!-- <script src="./mermaid-example-diagram-detector.js"></script> -->
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
<!-- <script src="./mermaid.js"></script> -->
<script type="module">
// import mindmap from '../../packages/mermaid-mindmap/src/detector';
// import example from '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs';
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
// await mermaid.registerExternalDiagrams([example]);
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
console.error('Mermaid error: ', err);
};
// mermaid.initialize({
// // theme: 'forest',
// startOnLoad: true,
// logLevel: 0,
// flowchart: {
// // defaultRenderer: 'elk',
// useMaxWidth: false,
// // htmlLabels: false,
// htmlLabels: true,
// },
// // htmlLabels: false,
// gantt: {
// useMaxWidth: false,
// },
// useMaxWidth: false,
// });
mermaid.initialize({
// theme: 'dark',
theme: 'base',
handdrawnSeed: 12,
// look: 'handdrawn',
look: 'handdrawn',
'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
// layout: 'dagre',
layout: 'elk',
flowchart: { titleTopMargin: 10 },
// fontFamily: 'Caveat',
fontFamily: 'Kalam',
// fontFamily: 'Kalam',
fontFamily: 'courier',
sequence: {
actorFontFamily: 'courier',
noteFontFamily: 'courier',
messageFontFamily: 'courier',
},
fontSize: 16,
fontSize: 12,
logLevel: 0,
});
function callback() {

View File

@ -1221,12 +1221,15 @@ direction LR
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {
};
mermaid.initialize({
handdrawn: false,
mergeEdges: true,
layout: 'dagre',
flowchart: { titleTopMargin: 10 },
// fontFamily: 'Caveat',
@ -1249,8 +1252,8 @@ direction LR
let coll = document.getElementsByClassName("collapsible");
for (let i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function () {
for (const element of coll) {
element.addEventListener("click", function () {
this.classList.toggle("active");
let content = this.nextElementSibling;
if (content.style.maxHeight) {

View File

@ -3,6 +3,7 @@ import { curveLinear } from 'd3';
import ELK from 'elkjs/lib/elk.bundled.js';
import mermaid from 'mermaid';
import { findCommonAncestor } from './find-common-ancestor.js';
import config from '../../mermaid/src/defaultConfig';
const {
common,
@ -70,13 +71,19 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
child.children = [];
await addVertices(nodeEl, nodeArr, child, node.id);
// We need the label hight to be able to size the subgraph;
const { shapeSvg, bbox } = await labelHelper(nodeEl, node, undefined, true);
labelData.width = bbox.width;
labelData.wrappingWidth = getConfig().flowchart.wrappingWidth;
labelData.height = bbox.height;
labelData.labelNode = shapeSvg.node();
shapeSvg.remove();
if (node.label) {
const { shapeSvg, bbox } = await labelHelper(nodeEl, node, undefined, true);
labelData.width = bbox.width;
labelData.wrappingWidth = getConfig().flowchart.wrappingWidth;
labelData.height = bbox.height - 8;
labelData.labelNode = shapeSvg.node();
// We need the label hight to be able to size the subgraph;
shapeSvg.remove();
} else {
// Subgraph without label
labelData.width = 0;
labelData.height = 0;
}
child.labelData = labelData;
child.domId = nodeEl;
}
@ -454,18 +461,11 @@ export const render = async (data4Layout, svg, element, algorithm) => {
id: 'root',
layoutOptions: {
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
'org.eclipse.elk.padding': '[top=100, left=100, bottom=110, right=110]',
'elk.layered.spacing.edgeNodeBetweenLayers': '30',
'elk.algorithm': algorithm,
'nodePlacement.strategy': 'NETWORK_SIMPLEX',
'spacing.nodeNode': 70,
'spacing.nodeNodeBetweenLayers': 25,
'spacing.edgeNode': 10,
'spacing.edgeNodeBetweenLayers': 20,
'spacing.edgeEdge': 20,
'spacing.edgeEdgeBetweenLayers': 20,
'spacing.nodeSelfLoop': 20,
'nodePlacement.strategy': data4Layout.config['elk.nodePlacement.strategy'],
'elk.layered.mergeEdges': data4Layout.config.mergeEdges,
'elk.direction': 'DOWN',
'spacing.baseValue': 30,
},
children: [],
edges: [],
@ -504,18 +504,23 @@ export const render = async (data4Layout, svg, element, algorithm) => {
// Subgraph
if (parentLookupDb.childrenById[node.id] !== undefined) {
log.trace('Subgraph XCX', node.id, node);
node.labels = [
{
text: node.labelText,
layoutOptions: {
'nodeLabels.placement': '[H_CENTER, V_TOP, INSIDE]',
},
width: node?.labelData?.width || 100,
height: node?.labelData?.height || 100,
width: node?.labelData?.width || 0,
height: node?.labelData?.height || 0,
},
];
node.layoutOptions = {
'spacing.baseValue': 30,
};
if (node.dir) {
node.layoutOptions = {
...node.layoutOptions,
'elk.direction': dir2ElkDirection(node.dir),
'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
};
@ -538,9 +543,9 @@ export const render = async (data4Layout, svg, element, algorithm) => {
}
});
log.info('before layout', JSON.stringify(elkGraph, null, 2));
log.trace('before layout', JSON.stringify(elkGraph, null, 2));
const g = await elk.layout(elkGraph);
log.info('after layout DAGA', JSON.stringify(g));
log.info('after layout', JSON.stringify(g));
// debugger;
drawNodes(0, 0, g.children, svg, subGraphsEl, 0);

View File

@ -190,7 +190,10 @@ export const addDirective = (directive: MermaidConfig) => {
// If the directive has a fontFamily, but no themeVariables, add the fontFamily to the themeVariables
if (directive.fontFamily && (!directive.themeVariables || !directive.themeVariables.fontFamily)) {
directive.themeVariables = { fontFamily: directive.fontFamily };
directive.themeVariables = {
...directive.themeVariables,
fontFamily: directive.fontFamily,
};
}
directives.push(directive);

View File

@ -88,6 +88,16 @@ export interface MermaidConfig {
*
*/
maxEdges?: number;
/**
* Elk specific option that allows edge egdes to share path where it convenient. It can make for pretty diagrams but can also make it harder to read the diagram.
*
*/
'elk.mergeEdges'?: boolean;
/**
* Elk specific option affedcting how nodes are placed.
*
*/
'elk.nodePlacement.strategy'?: 'SIMPLE' | 'NETWORK_SIMPLEX' | 'LINEAR_SEGMENTS' | 'BRANDES_KOEPF';
darkMode?: boolean;
htmlLabels?: boolean;
/**

View File

@ -237,7 +237,6 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
}
const newNode = nodeDb[itemId];
// console.log('New Node:', newNode);
// Save data for description and group so that for instance a statement without description overwrites
// one with description @todo TODO What does this mean? If important, add a test for it
@ -273,7 +272,7 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
// group
if (!newNode.type && parsedItem.doc) {
log.info('Setting cluster for ', itemId, getDir(parsedItem));
log.info('Setting cluster for XCX', itemId, getDir(parsedItem));
newNode.type = 'group';
newNode.isGroup = true;
newNode.dir = getDir(parsedItem);
@ -298,12 +297,17 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
domId: stateDomId(itemId, graphItemCount),
type: newNode.type,
isGroup: newNode.type === 'group',
padding: 15,
padding: 8,
rx: 10,
ry: 10,
useRough,
};
// Clear the label for dividers who have no description
if (nodeData.shape === SHAPE_DIVIDER) {
nodeData.label = '';
}
if (parent && parent.id !== 'root') {
log.trace('Setting node ', itemId, ' to be child of its parent ', parent.id);
nodeData.parentId = parent.id;
@ -324,7 +328,7 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
domId: stateDomId(itemId, graphItemCount, NOTE),
type: newNode.type,
isGroup: newNode.type === 'group',
padding: 15, //getConfig().flowchart.padding
padding: 0, //getConfig().flowchart.padding
useRough,
};
const groupData = {
@ -337,7 +341,7 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
domId: stateDomId(itemId, graphItemCount, PARENT),
type: 'group',
isGroup: true,
padding: 0, //getConfig().flowchart.padding
padding: 16, //getConfig().flowchart.padding
useRough,
};
graphItemCount++;
@ -382,8 +386,6 @@ export const dataFetcher = (parent, parsedItem, diagramStates, nodes, edges, alt
} else {
insertOrUpdateNode(nodes, nodeData);
}
// console.log('Nodes:', nodes);
}
if (parsedItem.doc) {
log.trace('Adding nodes children ');

View File

@ -581,11 +581,11 @@ export const getData = () => {
// }
extract(getRootDocV2());
const diagramStates = getStates();
const useRough = getConfig().look === 'handdrawn';
const config = getConfig();
const useRough = config.look === 'handdrawn';
dataFetcher(undefined, getRootDocV2(), diagramStates, nodes, edges, true, useRough);
return { nodes, edges, other: {} };
return { nodes, edges, other: {}, config };
};
export default {

View File

@ -54,7 +54,14 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
if (parentCluster !== undefined) {
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
// data.clusterPositioning = true;
log.info('Setting data for cluster XXX (', v, ') ', data, parentCluster);
log.trace(
'Setting data for parent cluster XXX\n Node.id = ',
v,
'\n data=',
data.height,
'\nParent cluster',
parentCluster.height
);
graph.setNode(parentCluster.id, data);
if (!graph.parent(v)) {
log.trace('Setting parent', v, parentCluster.id);
@ -64,7 +71,8 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
if (node && node.clusterNode) {
// const children = graph.children(v);
log.info('Cluster identified', v, node.width, graph.node(v));
log.info('Cluster identified XXX', v, node.width, graph.node(v));
// "o" will contain the full cluster not just the children
const o = await recursiveRender(
nodes,
node.graph,
@ -76,10 +84,18 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
const newEl = o.elem;
updateNodeBounds(node, newEl);
node.diff = o.diff || 0;
log.info('Node bounds (abc123)', v, node, node.width, node.x, node.y);
log.trace(
'New compound node after recursive render XAX',
v,
'width',
// node,
node.width,
'height',
node.height
// node.x,
// node.y
);
setNodeElem(newEl, node);
log.warn('Recursive render complete ', newEl, node);
} else {
if (graph.children(v).length > 0) {
// This is a cluster but not to be rendered recursively
@ -89,7 +105,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
clusterDb[node.id] = { id: findNonClusterChild(node.id, graph), node };
// insertCluster(clusters, graph.node(v));
} else {
log.info('Node - the non recursive path', v, node.id, node);
log.trace('Node - the non recursive path XAX', v, node.id, node);
await insertNode(nodes, graph.node(v), dir);
}
}
@ -113,20 +129,26 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
graph.edges().forEach(function (e) {
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
});
log.info('#############################################');
log.info('### Layout ###');
log.info('#############################################');
log.info(graph);
log.info('############################################# XXX');
log.info('### Layout ### XXX');
log.info('############################################# XXX');
dagreLayout(graph);
log.info('Graph after layout:', graphlibJson.write(graph));
// Move the nodes to the correct place
let diff = 0;
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
log.info('Need the size here XAX', graph.node('T1')?.height);
let { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
subGraphTitleTotalMargin = 0;
sortNodesByHierarchy(graph).forEach(function (v) {
const node = graph.node(v);
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
const p = graph.node(node?.parentId);
subGraphTitleTotalMargin = p?.offsetY || subGraphTitleTotalMargin;
log.info(
'Position ' + v + ': (' + node.x,
'Position XAX' + v + ': (' + node.x,
',' + node.y,
') width: ',
node.width,
@ -134,19 +156,66 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
node.height
);
if (node && node.clusterNode) {
// clusterDb[node.id].node = node;
node.y += subGraphTitleTotalMargin;
const parentId = graph.parent(v);
// Adjust for padding when on root level
node.y = parentId ? node.y + 2 : node.y - 8;
node.x -= 8;
log.info(
'A tainted cluster node XBX',
v,
node.id,
node.width,
node.height,
node.x,
node.y,
graph.parent(v)
);
clusterDb[node.id].node = node;
// node.y += subGraphTitleTotalMargin - 10;
node.y -= (node.offsetY || 0) / 2;
positionNode(node);
} else {
// Non cluster node
if (graph.children(v).length > 0) {
// A cluster in the non-recursive way
// positionCluster(node);
node.height += subGraphTitleTotalMargin;
node.height += 0;
const parent = graph.node(node.parentId);
node.y += (node.offsetY || 0) / 2;
insertCluster(clusters, node);
// A cluster in the non-recursive way
log.info(
'A pure cluster node with children XBX',
v,
node.id,
node.width,
node.height,
node.x,
node.y,
'offset',
parent?.offsetY
);
clusterDb[node.id].node = node;
} else {
node.y += subGraphTitleTotalMargin / 2;
const parent = graph.node(node.parentId);
node.y += (parent?.offsetY || 0) / 2;
log.info(
'A regular node XBX - using the padding',
v,
node.id,
'parent',
node.parentId,
node.width,
node.height,
node.x,
node.y,
'offsetY',
node.offsetY,
'parent',
parent,
node
);
positionNode(node);
}
}
@ -169,9 +238,14 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
diff = n.diff;
}
});
log.trace('Returning from recursive render XAX', elem, diff);
return { elem, diff };
};
/**
* ###############################################################
* Render the graph
* ###############################################################
*/
export const render = async (data4Layout, svg, element) => {
// Create the input mermaid.graph
const graph = new graphlib.Graph({
@ -223,13 +297,3 @@ export const render = async (data4Layout, svg, element) => {
siteConfig
);
};
// const shapeDefinitions = {};
// export const addShape = ({ shapeType: fun }) => {
// shapeDefinitions[shapeType] = fun;
// };
// const arrowDefinitions = {};
// export const addArrow = ({ arrowType: fun }) => {
// arrowDefinitions[arrowType] = fun;
// };

View File

@ -247,6 +247,8 @@ const roundedWithTitle = (parent, node) => {
const rectBox = rect.node().getBBox();
node.height = rectBox.height;
node.offsetX = 0;
node.offsetY = 20;
node.intersect = function (point) {
return intersectRect(node, point);
@ -292,8 +294,9 @@ const divider = (parent, node) => {
}
const rectBox = rect.node().getBBox();
node.width = rectBox.width;
node.height = rectBox.height;
node.diff = -node.padding / 2;
node.height = rectBox.height - node.padding;
node.diff = 0; //-node.padding / 2;
node.offsetY = 0;
node.intersect = function (point) {
return intersectRect(node, point);
};
@ -306,7 +309,6 @@ const shapes = { rect, roundedWithTitle, noteGroup, divider };
let clusterElems = {};
export const insertCluster = (elem, node) => {
log.trace('Inserting cluster');
const shape = node.shape || 'rect';
const cluster = shapes[shape](elem, node);
clusterElems[node.id] = cluster;

View File

@ -75,16 +75,12 @@ export const positionNode = (node) => {
node,
'translate(' + (node.x - node.width / 2 - 5) + ', ' + node.width / 2 + ')'
);
const padding = 8;
const diff = node.diff || 0;
const diff = 0;
if (node.clusterNode) {
el.attr(
'transform',
'translate(' +
(node.x + diff - node.width / 2) +
', ' +
(node.y - node.height / 2 - padding) +
')'
'translate(' + (node.x + diff - node.width / 2) + ', ' + (node.y - node.height / 2) + ')'
);
} else {
el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')');

View File

@ -100,6 +100,21 @@ properties:
type: integer
default: 500
minimum: 0
elk.mergeEdges:
description: |
Elk specific option that allows edge egdes to share path where it convenient. It can make for pretty diagrams but can also make it harder to read the diagram.
type: boolean
default: false
elk.nodePlacement.strategy:
description: |
Elk specific option affedcting how nodes are placed.
type: string
enum:
- SIMPLE
- NETWORK_SIMPLEX
- LINEAR_SEGMENTS
- BRANDES_KOEPF
default: SIMPLE
darkMode:
type: boolean
default: false
@ -201,7 +216,7 @@ properties:
default: false
forceLegacyMathML:
description: |
This option forces Mermaid to rely on KaTeX's own stylesheet for rendering MathML. Due to differences between OS
This option forces Mermaid to rely on KaTeX's own stylesheet for rendering MathML. Due to differences between OS
fonts and browser's MathML implementation, this option is recommended if consistent rendering is important.
If set to true, ignores legacyMathML.
type: boolean

19831
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff