mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-03 20:34:20 +01:00 
			
		
		
		
	Compare commits
	
		
			26 Commits
		
	
	
		
			@mermaid-j
			...
			halo-layou
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					39598baaa3 | ||
| 
						 | 
					08fbed7c47 | ||
| 
						 | 
					df636c6d0a | ||
| 
						 | 
					64554a6c60 | ||
| 
						 | 
					becadf0a7d | ||
| 
						 | 
					54d485f173 | ||
| 
						 | 
					b4f5b8ddaf | ||
| 
						 | 
					cb5c1ae367 | ||
| 
						 | 
					b29081d4e8 | ||
| 
						 | 
					654097c438 | ||
| 
						 | 
					1e672868c4 | ||
| 
						 | 
					bff32827b5 | ||
| 
						 | 
					65f9b29b86 | ||
| 
						 | 
					b4879d13b8 | ||
| 
						 | 
					95964b5487 | ||
| 
						 | 
					4e17da0a30 | ||
| 
						 | 
					2a91849a38 | ||
| 
						 | 
					082de76eef | ||
| 
						 | 
					570ae78b15 | ||
| 
						 | 
					885ac6f947 | ||
| 
						 | 
					193fdb225e | ||
| 
						 | 
					7cbd80af33 | ||
| 
						 | 
					16c448b89b | ||
| 
						 | 
					cb0a4703bd | ||
| 
						 | 
					8cb1c68166 | ||
| 
						 | 
					d752240efc | 
							
								
								
									
										5
									
								
								.changeset/angry-bags-brake.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/angry-bags-brake.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'mermaid': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
 | 
			
		||||
@@ -171,6 +171,58 @@ describe.skip('architecture diagram', () => {
 | 
			
		||||
            `
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should render an architecture diagram with a resonable height', () => {
 | 
			
		||||
    imgSnapshotTest(
 | 
			
		||||
      `architecture-beta
 | 
			
		||||
              group federated(cloud)[Federated Environment]
 | 
			
		||||
                  service server1(server)[System] in federated
 | 
			
		||||
                  service edge(server)[Edge Device] in federated
 | 
			
		||||
                  server1:R -- L:edge
 | 
			
		||||
 | 
			
		||||
              group on_prem(cloud)[Hub]
 | 
			
		||||
                  service firewall(server)[Firewall Device] in on_prem
 | 
			
		||||
                  service server(server)[Server] in on_prem
 | 
			
		||||
                  firewall:R -- L:server
 | 
			
		||||
 | 
			
		||||
                  service db1(database)[db1] in on_prem
 | 
			
		||||
                  service db2(database)[db2] in on_prem
 | 
			
		||||
                  service db3(database)[db3] in on_prem
 | 
			
		||||
                  service db4(database)[db4] in on_prem
 | 
			
		||||
                  service db5(database)[db5] in on_prem
 | 
			
		||||
                  service db6(database)[db6] in on_prem
 | 
			
		||||
 | 
			
		||||
                  junction mid in on_prem
 | 
			
		||||
                  server:B -- T:mid
 | 
			
		||||
 | 
			
		||||
                  junction 1Leftofmid in on_prem
 | 
			
		||||
                  1Leftofmid:R -- L:mid
 | 
			
		||||
                  1Leftofmid:B -- T:db1
 | 
			
		||||
 | 
			
		||||
                  junction 2Leftofmid in on_prem
 | 
			
		||||
                  2Leftofmid:R -- L:1Leftofmid
 | 
			
		||||
                  2Leftofmid:B -- T:db2
 | 
			
		||||
 | 
			
		||||
                  junction 3Leftofmid in on_prem
 | 
			
		||||
                  3Leftofmid:R -- L:2Leftofmid
 | 
			
		||||
                  3Leftofmid:B -- T:db3
 | 
			
		||||
 | 
			
		||||
                  junction 1RightOfMid in on_prem
 | 
			
		||||
                  mid:R -- L:1RightOfMid
 | 
			
		||||
                  1RightOfMid:B -- T:db4
 | 
			
		||||
                  
 | 
			
		||||
                  junction 2RightOfMid in on_prem
 | 
			
		||||
                  1RightOfMid:R -- L:2RightOfMid
 | 
			
		||||
                  2RightOfMid:B -- T:db5        
 | 
			
		||||
                  
 | 
			
		||||
                  junction 3RightOfMid in on_prem
 | 
			
		||||
                  2RightOfMid:R -- L:3RightOfMid
 | 
			
		||||
                  3RightOfMid:B -- T:db6         
 | 
			
		||||
 | 
			
		||||
                  edge:R -- L:firewall
 | 
			
		||||
      `
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Skipped as the layout is not deterministic, and causes issues in E2E tests.
 | 
			
		||||
 
 | 
			
		||||
@@ -900,6 +900,153 @@ flowchart LR
 | 
			
		||||
    n7@{ shape: rect}
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-1: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      subgraph S2
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
      D{"Use the editor"}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-2: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
      subgraph s0["APA"]
 | 
			
		||||
      subgraph s8["APA"]
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
        D{"X"}
 | 
			
		||||
        E[Q]
 | 
			
		||||
      end
 | 
			
		||||
      subgraph s3["BAPA"]
 | 
			
		||||
        F[Q]
 | 
			
		||||
        I
 | 
			
		||||
      end
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      I{"X"}
 | 
			
		||||
      end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-3: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
        D{"Use the editor"}
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
      D-->I
 | 
			
		||||
      D-->I
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-4: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
 subgraph s1["Untitled subgraph"]
 | 
			
		||||
        n1["Evaluate"]
 | 
			
		||||
        n2["Option 1"]
 | 
			
		||||
        n3["Option 2"]
 | 
			
		||||
        n4["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
 subgraph s2["Untitled subgraph"]
 | 
			
		||||
        n5["Evaluate"]
 | 
			
		||||
        n6["Option 1"]
 | 
			
		||||
        n7["Option 2"]
 | 
			
		||||
        n8["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
    A["Start"] -- Some text --> B("Continue")
 | 
			
		||||
    B --> C{"Evaluate"}
 | 
			
		||||
    C -- One --> D["Option 1"]
 | 
			
		||||
    C -- Two --> E["Option 2"]
 | 
			
		||||
    C -- Three --> F["fa:fa-car Option 3"]
 | 
			
		||||
    n1 -- One --> n2
 | 
			
		||||
    n1 -- Two --> n3
 | 
			
		||||
    n1 -- Three --> n4
 | 
			
		||||
    n5 -- One --> n6
 | 
			
		||||
    n5 -- Two --> n7
 | 
			
		||||
    n5 -- Three --> n8
 | 
			
		||||
    n1@{ shape: diam}
 | 
			
		||||
    n2@{ shape: rect}
 | 
			
		||||
    n3@{ shape: rect}
 | 
			
		||||
    n4@{ shape: rect}
 | 
			
		||||
    n5@{ shape: diam}
 | 
			
		||||
    n6@{ shape: rect}
 | 
			
		||||
    n7@{ shape: rect}
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-5: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
      it('6088-6: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
    subgraph "subbe"
 | 
			
		||||
      A
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -88,33 +88,61 @@
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
 subgraph s1["Untitled subgraph"]
 | 
			
		||||
        n1["Evaluate"]
 | 
			
		||||
        n2["Option 1"]
 | 
			
		||||
        n3["Option 2"]
 | 
			
		||||
        n4["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
    n1 -- One --> n2
 | 
			
		||||
    n1 -- Two --> n3
 | 
			
		||||
    n1 -- Three --> n4
 | 
			
		||||
    n5
 | 
			
		||||
    n1@{ shape: diam}
 | 
			
		||||
    n2@{ shape: rect}
 | 
			
		||||
    n3@{ shape: rect}
 | 
			
		||||
    n4@{ shape: rect}
 | 
			
		||||
    A["Start"] -- Some text --> B("Continue")
 | 
			
		||||
    B --> C{"Evaluate"}
 | 
			
		||||
    C -- One --> D["Option 1"]
 | 
			
		||||
    C -- Two --> E["Option 2"]
 | 
			
		||||
    C -- Three --> F["fa:fa-car Option 3"]
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      subgraph S2
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
      D{"Use the editor"}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
      subgraph s0["APA"]
 | 
			
		||||
      subgraph s8["APA"]
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
        D{"X"}
 | 
			
		||||
        E[Q]
 | 
			
		||||
      end
 | 
			
		||||
      subgraph s3["BAPA"]
 | 
			
		||||
        F[Q]
 | 
			
		||||
        I
 | 
			
		||||
      end
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      I{"X"}
 | 
			
		||||
      end
 | 
			
		||||
      end
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
        D{"Use the editor"}
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
      D-->I
 | 
			
		||||
      D-->I
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
@@ -155,7 +183,7 @@ flowchart LR
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
@@ -171,7 +199,7 @@ flowchart LR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
@@ -180,7 +208,19 @@ flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
</pre
 | 
			
		||||
    >
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
    subgraph "subbe"
 | 
			
		||||
      A
 | 
			
		||||
    end
 | 
			
		||||
</pre
 | 
			
		||||
    >
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
 
 | 
			
		||||
@@ -39,8 +39,8 @@ graph TB
 | 
			
		||||
 | 
			
		||||
    <script type="module">
 | 
			
		||||
      import mermaid from '/mermaid.esm.mjs';
 | 
			
		||||
      import flowchartELK from '/mermaid-flowchart-elk.esm.mjs';
 | 
			
		||||
      await mermaid.registerExternalDiagrams([flowchartELK]);
 | 
			
		||||
      import layouts from '/mermaid-layout-elk.esm.mjs';
 | 
			
		||||
      mermaid.registerLayoutLoaders(layouts);
 | 
			
		||||
      async function render(str) {
 | 
			
		||||
        const { svg } = await mermaid.render('dynamic', str);
 | 
			
		||||
        document.getElementById('dynamicDiagram').innerHTML = svg;
 | 
			
		||||
 
 | 
			
		||||
@@ -500,7 +500,7 @@ mermaid.ganttConfig = {
 | 
			
		||||
  sectionFontSize: 24, // Font size for sections
 | 
			
		||||
  numberSectionStyles: 1, // The number of alternating section styles
 | 
			
		||||
  axisFormat: '%d/%m', // Date/time format of the axis
 | 
			
		||||
  tickInterval: '1 week', // Axis ticks
 | 
			
		||||
  tickInterval: '1week', // Axis ticks
 | 
			
		||||
  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
			
		||||
  displayMode: 'compact', // Turns compact mode on
 | 
			
		||||
  weekday: 'sunday', // On which day a week-based interval should start
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ todo[Todo]
 | 
			
		||||
 | 
			
		||||
## Configuration Options
 | 
			
		||||
 | 
			
		||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams tacketBaseUrl. This can be set as in the the following example:
 | 
			
		||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams `ticketBaseUrl`. This can be set as in the the following example:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
---
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,11 @@
 | 
			
		||||
# @mermaid-js/layout-elk
 | 
			
		||||
 | 
			
		||||
## 0.1.7
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 | 
			
		||||
- [#6090](https://github.com/mermaid-js/mermaid/pull/6090) [`654097c`](https://github.com/mermaid-js/mermaid/commit/654097c43801b2d606bc3d2bef8c6fbc3301e9e4) Thanks [@knsv](https://github.com/knsv)! - fix: Updated offset calculations for diamond shape when handling intersections
 | 
			
		||||
 | 
			
		||||
## 0.1.6
 | 
			
		||||
 | 
			
		||||
### Patch Changes
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@mermaid-js/layout-elk",
 | 
			
		||||
  "version": "0.1.6",
 | 
			
		||||
  "version": "0.1.7",
 | 
			
		||||
  "description": "ELK layout engine for mermaid",
 | 
			
		||||
  "module": "dist/mermaid-layout-elk.core.mjs",
 | 
			
		||||
  "types": "dist/layouts.d.ts",
 | 
			
		||||
 
 | 
			
		||||
@@ -705,14 +705,11 @@ export const render = async (
 | 
			
		||||
    bounds: { x: any; y: any; width: any; height: any; padding: any },
 | 
			
		||||
    isDiamond: boolean
 | 
			
		||||
  ) => {
 | 
			
		||||
    log.debug('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
 | 
			
		||||
    log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
 | 
			
		||||
    const points: any[] = [];
 | 
			
		||||
    let lastPointOutside = _points[0];
 | 
			
		||||
    let isInside = false;
 | 
			
		||||
    _points.forEach((point: any) => {
 | 
			
		||||
      // const node = clusterDb[edge.toCluster].node;
 | 
			
		||||
      log.debug(' checking point', point, bounds);
 | 
			
		||||
 | 
			
		||||
      // check if point is inside the boundary rect
 | 
			
		||||
      if (!outsideNode(bounds, point) && !isInside) {
 | 
			
		||||
        // First point inside the rect found
 | 
			
		||||
@@ -906,7 +903,7 @@ export const render = async (
 | 
			
		||||
 | 
			
		||||
      const offset = calcOffset(sourceId, targetId, parentLookupDb);
 | 
			
		||||
      log.debug(
 | 
			
		||||
        'offset',
 | 
			
		||||
        'APA18 offset',
 | 
			
		||||
        offset,
 | 
			
		||||
        sourceId,
 | 
			
		||||
        ' ==> ',
 | 
			
		||||
@@ -971,29 +968,22 @@ export const render = async (
 | 
			
		||||
        }
 | 
			
		||||
        if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
 | 
			
		||||
          edge.points.unshift({
 | 
			
		||||
            x: startNode.x + startNode.width / 2 + offset.x,
 | 
			
		||||
            y: startNode.y + startNode.height / 2 + offset.y,
 | 
			
		||||
            x: startNode.offset.posX + startNode.width / 2,
 | 
			
		||||
            y: startNode.offset.posY + startNode.height / 2,
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
 | 
			
		||||
          const x = endNode.x + endNode.width / 2 + offset.x;
 | 
			
		||||
          // Add a point at the center of the diamond
 | 
			
		||||
          if (
 | 
			
		||||
            Math.abs(edge.points[edge.points.length - 1].y - endNode.y - offset.y) > 0.01 ||
 | 
			
		||||
            Math.abs(edge.points[edge.points.length - 1].x - x) > 0.001
 | 
			
		||||
          ) {
 | 
			
		||||
            edge.points.push({
 | 
			
		||||
              x: endNode.x + endNode.width / 2 + offset.x,
 | 
			
		||||
              y: endNode.y + endNode.height / 2 + offset.y,
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
          edge.points.push({
 | 
			
		||||
            x: endNode.offset.posX + endNode.width / 2,
 | 
			
		||||
            y: endNode.offset.posY + endNode.height / 2,
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        edge.points = cutPathAtIntersect(
 | 
			
		||||
          edge.points.reverse(),
 | 
			
		||||
          {
 | 
			
		||||
            x: startNode.x + startNode.width / 2 + offset.x,
 | 
			
		||||
            y: startNode.y + startNode.height / 2 + offset.y,
 | 
			
		||||
            x: startNode.offset.posX + startNode.width / 2,
 | 
			
		||||
            y: startNode.offset.posY + startNode.height / 2,
 | 
			
		||||
            width: sw,
 | 
			
		||||
            height: startNode.height,
 | 
			
		||||
            padding: startNode.padding,
 | 
			
		||||
@@ -1004,8 +994,8 @@ export const render = async (
 | 
			
		||||
        edge.points = cutPathAtIntersect(
 | 
			
		||||
          edge.points,
 | 
			
		||||
          {
 | 
			
		||||
            x: endNode.x + ew / 2 + endNode.offset.x,
 | 
			
		||||
            y: endNode.y + endNode.height / 2 + endNode.offset.y,
 | 
			
		||||
            x: endNode.offset.posX + endNode.width / 2,
 | 
			
		||||
            y: endNode.offset.posY + endNode.height / 2,
 | 
			
		||||
            width: ew,
 | 
			
		||||
            height: endNode.height,
 | 
			
		||||
            padding: endNode.padding,
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import {
 | 
			
		||||
  setDiagramTitle,
 | 
			
		||||
} from '../common/commonDb.js';
 | 
			
		||||
import type {
 | 
			
		||||
  ArchitectureAlignment,
 | 
			
		||||
  ArchitectureDB,
 | 
			
		||||
  ArchitectureDirectionPair,
 | 
			
		||||
  ArchitectureDirectionPairMap,
 | 
			
		||||
@@ -25,6 +26,7 @@ import type {
 | 
			
		||||
  ArchitectureState,
 | 
			
		||||
} from './architectureTypes.js';
 | 
			
		||||
import {
 | 
			
		||||
  getArchitectureDirectionAlignment,
 | 
			
		||||
  getArchitectureDirectionPair,
 | 
			
		||||
  isArchitectureDirection,
 | 
			
		||||
  isArchitectureJunction,
 | 
			
		||||
@@ -211,12 +213,18 @@ const addEdge = function ({
 | 
			
		||||
const getEdges = (): ArchitectureEdge[] => state.records.edges;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the current diagram's adjacency list & spatial map.
 | 
			
		||||
 * Returns the current diagram's adjacency list, spatial map, & group alignments.
 | 
			
		||||
 * If they have not been created, run the algorithms to generate them.
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
const getDataStructures = () => {
 | 
			
		||||
  if (state.records.dataStructures === undefined) {
 | 
			
		||||
    // Tracks how groups are aligned with one another. Generated while creating the adj list
 | 
			
		||||
    const groupAlignments: Record<
 | 
			
		||||
      string,
 | 
			
		||||
      Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
			
		||||
    > = {};
 | 
			
		||||
 | 
			
		||||
    // Create an adjacency list of the diagram to perform BFS on
 | 
			
		||||
    // Outer reduce applied on all services
 | 
			
		||||
    // Inner reduce applied on the edges for a service
 | 
			
		||||
@@ -224,6 +232,19 @@ const getDataStructures = () => {
 | 
			
		||||
      Record<string, ArchitectureDirectionPairMap>
 | 
			
		||||
    >((prevOuter, [id, service]) => {
 | 
			
		||||
      prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
 | 
			
		||||
        // track the direction groups connect to one another
 | 
			
		||||
        const lhsGroupId = getNode(edge.lhsId)?.in;
 | 
			
		||||
        const rhsGroupId = getNode(edge.rhsId)?.in;
 | 
			
		||||
        if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
 | 
			
		||||
          const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
          if (alignment !== 'bend') {
 | 
			
		||||
            groupAlignments[lhsGroupId] ??= {};
 | 
			
		||||
            groupAlignments[lhsGroupId][rhsGroupId] = alignment;
 | 
			
		||||
            groupAlignments[rhsGroupId] ??= {};
 | 
			
		||||
            groupAlignments[rhsGroupId][lhsGroupId] = alignment;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (edge.lhsId === id) {
 | 
			
		||||
          // source is LHS
 | 
			
		||||
          const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
 | 
			
		||||
@@ -245,6 +266,7 @@ const getDataStructures = () => {
 | 
			
		||||
    // Configuration for the initial pass of BFS
 | 
			
		||||
    const firstId = Object.keys(adjList)[0];
 | 
			
		||||
    const visited = { [firstId]: 1 };
 | 
			
		||||
    // If a key is present in this object, it has not been visited
 | 
			
		||||
    const notVisited = Object.keys(adjList).reduce(
 | 
			
		||||
      (prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
 | 
			
		||||
      {} as Record<string, number>
 | 
			
		||||
@@ -283,6 +305,7 @@ const getDataStructures = () => {
 | 
			
		||||
    state.records.dataStructures = {
 | 
			
		||||
      adjList,
 | 
			
		||||
      spatialMaps,
 | 
			
		||||
      groupAlignments,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
  return state.records.dataStructures;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,9 @@ import { setupGraphViewbox } from '../../setupGraphViewbox.js';
 | 
			
		||||
import { getConfigField } from './architectureDb.js';
 | 
			
		||||
import { architectureIcons } from './architectureIcons.js';
 | 
			
		||||
import type {
 | 
			
		||||
  ArchitectureAlignment,
 | 
			
		||||
  ArchitectureDataStructures,
 | 
			
		||||
  ArchitectureGroupAlignments,
 | 
			
		||||
  ArchitectureJunction,
 | 
			
		||||
  ArchitectureSpatialMap,
 | 
			
		||||
  EdgeSingular,
 | 
			
		||||
@@ -149,25 +151,91 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getAlignments(spatialMaps: ArchitectureSpatialMap[]): fcose.FcoseAlignmentConstraint {
 | 
			
		||||
function getAlignments(
 | 
			
		||||
  db: ArchitectureDB,
 | 
			
		||||
  spatialMaps: ArchitectureSpatialMap[],
 | 
			
		||||
  groupAlignments: ArchitectureGroupAlignments
 | 
			
		||||
): fcose.FcoseAlignmentConstraint {
 | 
			
		||||
  /**
 | 
			
		||||
   * Flattens the alignment object so nodes in different groups will be in the same alignment array IFF their groups don't connect in a conflicting alignment
 | 
			
		||||
   *
 | 
			
		||||
   * i.e., two groups which connect horizontally should not have nodes with vertical alignments to one another
 | 
			
		||||
   *
 | 
			
		||||
   * See: #5952
 | 
			
		||||
   *
 | 
			
		||||
   * @param alignmentObj - alignment object with the outer key being the row/col # and the inner key being the group name mapped to the nodes on that axis in the group
 | 
			
		||||
   * @param alignmentDir - alignment direction
 | 
			
		||||
   * @returns flattened alignment object with an arbitrary key mapping to nodes in the same row/col
 | 
			
		||||
   */
 | 
			
		||||
  const flattenAlignments = (
 | 
			
		||||
    alignmentObj: Record<number, Record<string, string[]>>,
 | 
			
		||||
    alignmentDir: ArchitectureAlignment
 | 
			
		||||
  ): Record<string, string[]> => {
 | 
			
		||||
    return Object.entries(alignmentObj).reduce(
 | 
			
		||||
      (prev, [dir, alignments]) => {
 | 
			
		||||
        // prev is the mapping of x/y coordinate to an array of the nodes in that row/column
 | 
			
		||||
        let cnt = 0;
 | 
			
		||||
        const arr = Object.entries(alignments); // [group name, array of nodes within the group on axis dir]
 | 
			
		||||
        if (arr.length === 1) {
 | 
			
		||||
          // If only one group exists in the row/column, we don't need to do anything else
 | 
			
		||||
          prev[dir] = arr[0][1];
 | 
			
		||||
          return prev;
 | 
			
		||||
        }
 | 
			
		||||
        for (let i = 0; i < arr.length - 1; i++) {
 | 
			
		||||
          for (let j = i + 1; j < arr.length; j++) {
 | 
			
		||||
            const [aGroupId, aNodeIds] = arr[i];
 | 
			
		||||
            const [bGroupId, bNodeIds] = arr[j];
 | 
			
		||||
            const alignment = groupAlignments[aGroupId]?.[bGroupId]; // Get how the two groups are intended to align (undefined if they aren't)
 | 
			
		||||
 | 
			
		||||
            if (alignment === alignmentDir) {
 | 
			
		||||
              // If the intended alignment between the two groups is the same as the alignment we are parsing
 | 
			
		||||
              prev[dir] ??= [];
 | 
			
		||||
              prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds]; // add the node ids of both groups to the axis array in prev
 | 
			
		||||
            } else if (aGroupId === 'default' || bGroupId === 'default') {
 | 
			
		||||
              // If either of the groups are in the default space (not in a group), use the same behavior as above
 | 
			
		||||
              prev[dir] ??= [];
 | 
			
		||||
              prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds];
 | 
			
		||||
            } else {
 | 
			
		||||
              // Otherwise, the nodes in the two groups are not intended to align
 | 
			
		||||
              const keyA = `${dir}-${cnt++}`;
 | 
			
		||||
              prev[keyA] = aNodeIds;
 | 
			
		||||
              const keyB = `${dir}-${cnt++}`;
 | 
			
		||||
              prev[keyB] = bNodeIds;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return prev;
 | 
			
		||||
      },
 | 
			
		||||
      {} as Record<string, string[]>
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const alignments = spatialMaps.map((spatialMap) => {
 | 
			
		||||
    const horizontalAlignments: Record<number, string[]> = {};
 | 
			
		||||
    const verticalAlignments: Record<number, string[]> = {};
 | 
			
		||||
    const horizontalAlignments: Record<number, Record<string, string[]>> = {};
 | 
			
		||||
    const verticalAlignments: Record<number, Record<string, string[]>> = {};
 | 
			
		||||
 | 
			
		||||
    // Group service ids in an object with their x and y coordinate as the key
 | 
			
		||||
    Object.entries(spatialMap).forEach(([id, [x, y]]) => {
 | 
			
		||||
      if (!horizontalAlignments[y]) {
 | 
			
		||||
        horizontalAlignments[y] = [];
 | 
			
		||||
      }
 | 
			
		||||
      if (!verticalAlignments[x]) {
 | 
			
		||||
        verticalAlignments[x] = [];
 | 
			
		||||
      }
 | 
			
		||||
      horizontalAlignments[y].push(id);
 | 
			
		||||
      verticalAlignments[x].push(id);
 | 
			
		||||
      const nodeGroup = db.getNode(id)?.in ?? 'default';
 | 
			
		||||
 | 
			
		||||
      horizontalAlignments[y] ??= {};
 | 
			
		||||
      horizontalAlignments[y][nodeGroup] ??= [];
 | 
			
		||||
      horizontalAlignments[y][nodeGroup].push(id);
 | 
			
		||||
 | 
			
		||||
      verticalAlignments[x] ??= {};
 | 
			
		||||
      verticalAlignments[x][nodeGroup] ??= [];
 | 
			
		||||
      verticalAlignments[x][nodeGroup].push(id);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Merge the values of each object into a list if the inner list has at least 2 elements
 | 
			
		||||
    return {
 | 
			
		||||
      horiz: Object.values(horizontalAlignments).filter((arr) => arr.length > 1),
 | 
			
		||||
      vert: Object.values(verticalAlignments).filter((arr) => arr.length > 1),
 | 
			
		||||
      horiz: Object.values(flattenAlignments(horizontalAlignments, 'horizontal')).filter(
 | 
			
		||||
        (arr) => arr.length > 1
 | 
			
		||||
      ),
 | 
			
		||||
      vert: Object.values(flattenAlignments(verticalAlignments, 'vertical')).filter(
 | 
			
		||||
        (arr) => arr.length > 1
 | 
			
		||||
      ),
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
@@ -244,7 +312,8 @@ function layoutArchitecture(
 | 
			
		||||
  junctions: ArchitectureJunction[],
 | 
			
		||||
  groups: ArchitectureGroup[],
 | 
			
		||||
  edges: ArchitectureEdge[],
 | 
			
		||||
  { spatialMaps }: ArchitectureDataStructures
 | 
			
		||||
  db: ArchitectureDB,
 | 
			
		||||
  { spatialMaps, groupAlignments }: ArchitectureDataStructures
 | 
			
		||||
): Promise<cytoscape.Core> {
 | 
			
		||||
  return new Promise((resolve) => {
 | 
			
		||||
    const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
 | 
			
		||||
@@ -318,9 +387,8 @@ function layoutArchitecture(
 | 
			
		||||
    addServices(services, cy);
 | 
			
		||||
    addJunctions(junctions, cy);
 | 
			
		||||
    addEdges(edges, cy);
 | 
			
		||||
 | 
			
		||||
    // Use the spatial map to create alignment arrays for fcose
 | 
			
		||||
    const alignmentConstraint = getAlignments(spatialMaps);
 | 
			
		||||
    const alignmentConstraint = getAlignments(db, spatialMaps, groupAlignments);
 | 
			
		||||
 | 
			
		||||
    // Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
 | 
			
		||||
    const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
 | 
			
		||||
@@ -454,7 +522,7 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
 | 
			
		||||
  await drawServices(db, servicesElem, services);
 | 
			
		||||
  drawJunctions(db, servicesElem, junctions);
 | 
			
		||||
 | 
			
		||||
  const cy = await layoutArchitecture(services, junctions, groups, edges, ds);
 | 
			
		||||
  const cy = await layoutArchitecture(services, junctions, groups, edges, db, ds);
 | 
			
		||||
 | 
			
		||||
  await drawEdges(edgesElem, cy);
 | 
			
		||||
  await drawGroups(groupElem, cy);
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ import type cytoscape from 'cytoscape';
 | 
			
		||||
|       Architecture Diagram Types        |
 | 
			
		||||
\*=======================================*/
 | 
			
		||||
 | 
			
		||||
export type ArchitectureAlignment = 'vertical' | 'horizontal' | 'bend';
 | 
			
		||||
 | 
			
		||||
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
 | 
			
		||||
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
 | 
			
		||||
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
 | 
			
		||||
@@ -170,6 +172,18 @@ export const getArchitectureDirectionXYFactors = function (
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getArchitectureDirectionAlignment = function (
 | 
			
		||||
  a: ArchitectureDirection,
 | 
			
		||||
  b: ArchitectureDirection
 | 
			
		||||
): ArchitectureAlignment {
 | 
			
		||||
  if (isArchitectureDirectionXY(a, b)) {
 | 
			
		||||
    return 'bend';
 | 
			
		||||
  } else if (isArchitectureDirectionX(a)) {
 | 
			
		||||
    return 'horizontal';
 | 
			
		||||
  }
 | 
			
		||||
  return 'vertical';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface ArchitectureStyleOptions {
 | 
			
		||||
  archEdgeColor: string;
 | 
			
		||||
  archEdgeArrowColor: string;
 | 
			
		||||
@@ -249,9 +263,27 @@ export interface ArchitectureDB extends DiagramDB {
 | 
			
		||||
 | 
			
		||||
export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;
 | 
			
		||||
export type ArchitectureSpatialMap = Record<string, number[]>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Maps the direction that groups connect from.
 | 
			
		||||
 *
 | 
			
		||||
 * **Outer key**: ID of group A
 | 
			
		||||
 *
 | 
			
		||||
 * **Inner key**: ID of group B
 | 
			
		||||
 *
 | 
			
		||||
 * **Value**: 'vertical' or 'horizontal'
 | 
			
		||||
 *
 | 
			
		||||
 * Note: tmp[groupA][groupB] == tmp[groupB][groupA]
 | 
			
		||||
 */
 | 
			
		||||
export type ArchitectureGroupAlignments = Record<
 | 
			
		||||
  string,
 | 
			
		||||
  Record<string, Exclude<ArchitectureAlignment, 'bend'>>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
export interface ArchitectureDataStructures {
 | 
			
		||||
  adjList: ArchitectureAdjacencyList;
 | 
			
		||||
  spatialMaps: ArchitectureSpatialMap[];
 | 
			
		||||
  groupAlignments: ArchitectureGroupAlignments;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ArchitectureState extends Record<string, unknown> {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
			
		||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/getDiagramElement.js';
 | 
			
		||||
import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js';
 | 
			
		||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
 | 
			
		||||
import type { LayoutData } from '../../rendering-util/types.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import { select } from 'd3';
 | 
			
		||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
			
		||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/getDiagramElement.js';
 | 
			
		||||
import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js';
 | 
			
		||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
 | 
			
		||||
import type { LayoutData } from '../../rendering-util/types.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
			
		||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
 | 
			
		||||
import { log } from '../../logger.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
 | 
			
		||||
import { getDiagramElement } from '../../rendering-util/getDiagramElement.js';
 | 
			
		||||
import { render } from '../../rendering-util/render.js';
 | 
			
		||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
 | 
			
		||||
import type { LayoutData } from '../../rendering-util/types.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -390,7 +390,7 @@ mermaid.ganttConfig = {
 | 
			
		||||
  sectionFontSize: 24, // Font size for sections
 | 
			
		||||
  numberSectionStyles: 1, // The number of alternating section styles
 | 
			
		||||
  axisFormat: '%d/%m', // Date/time format of the axis
 | 
			
		||||
  tickInterval: '1 week', // Axis ticks
 | 
			
		||||
  tickInterval: '1week', // Axis ticks
 | 
			
		||||
  topAxis: true, // When this flag is set, date labels will be added to the top of the chart
 | 
			
		||||
  displayMode: 'compact', // Turns compact mode on
 | 
			
		||||
  weekday: 'sunday', // On which day a week-based interval should start
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ todo[Todo]
 | 
			
		||||
 | 
			
		||||
## Configuration Options
 | 
			
		||||
 | 
			
		||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams tacketBaseUrl. This can be set as in the the following example:
 | 
			
		||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams `ticketBaseUrl`. This can be set as in the the following example:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
---
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/mermaid/src/rendering-util/insertElementsForSize.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/mermaid/src/rendering-util/insertElementsForSize.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import type { SVG } from '../diagram-api/types.js';
 | 
			
		||||
import { getConfig } from '../diagram-api/diagramAPI.js';
 | 
			
		||||
import type { LayoutData } from './types.js';
 | 
			
		||||
import { insertNode } from './rendering-elements/nodes.js';
 | 
			
		||||
 | 
			
		||||
export async function insertElementsForSize(el: SVG, data: LayoutData) {
 | 
			
		||||
  const nodesElem = el.insert('g').attr('class', 'nodes');
 | 
			
		||||
  el.insert('g').attr('class', 'edges');
 | 
			
		||||
  for (const item of data.nodes) {
 | 
			
		||||
    if (!item.isGroup) {
 | 
			
		||||
      const node = item;
 | 
			
		||||
      const config = getConfig();
 | 
			
		||||
      const newNode = await insertNode(nodesElem, node, { config, dir: node.dir });
 | 
			
		||||
      const boundingBox = newNode.node()!.getBBox();
 | 
			
		||||
      item.domId = newNode.attr('id');
 | 
			
		||||
      item.width = boundingBox.width;
 | 
			
		||||
      item.height = boundingBox.height;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,7 @@ import type { InternalHelpers } from '../internals.js';
 | 
			
		||||
import { internalHelpers } from '../internals.js';
 | 
			
		||||
import { log } from '../logger.js';
 | 
			
		||||
import type { LayoutData } from './types.js';
 | 
			
		||||
import { insertElementsForSize } from './insertElementsForSize.js';
 | 
			
		||||
 | 
			
		||||
export interface RenderOptions {
 | 
			
		||||
  algorithm?: string;
 | 
			
		||||
@@ -51,6 +52,8 @@ export const render = async (data4Layout: LayoutData, svg: SVG) => {
 | 
			
		||||
 | 
			
		||||
  const layoutDefinition = layoutAlgorithms[data4Layout.layoutAlgorithm];
 | 
			
		||||
  const layoutRenderer = await layoutDefinition.loader();
 | 
			
		||||
  // Add the bounding box to the layout so that the render can run
 | 
			
		||||
  await insertElementsForSize(svg, data4Layout);
 | 
			
		||||
  return layoutRenderer.render(data4Layout, svg, internalHelpers, {
 | 
			
		||||
    algorithm: layoutDefinition.algorithm,
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user