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;
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;
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

19831
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff