mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-04 12:54:08 +01:00 
			
		
		
		
	Compare commits
	
		
			73 Commits
		
	
	
		
			mermaid@11
			...
			fix-update
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					6f919ebafa | ||
| 
						 | 
					a302ead548 | ||
| 
						 | 
					918bcef6e6 | ||
| 
						 | 
					fe6ddc89c3 | ||
| 
						 | 
					2708b1c2f8 | ||
| 
						 | 
					16569b295b | ||
| 
						 | 
					11a35c11ee | ||
| 
						 | 
					216be22801 | ||
| 
						 | 
					994f7df29a | ||
| 
						 | 
					dc11b8645c | ||
| 
						 | 
					181af8167b | ||
| 
						 | 
					799d2ed547 | ||
| 
						 | 
					08160a74b4 | ||
| 
						 | 
					6d221fb3ca | ||
| 
						 | 
					8b20907141 | ||
| 
						 | 
					d318f1a13c | ||
| 
						 | 
					525a7de8ae | ||
| 
						 | 
					a459c436c9 | ||
| 
						 | 
					1c2a0020bd | ||
| 
						 | 
					141c6b3808 | ||
| 
						 | 
					8d4ffdf808 | ||
| 
						 | 
					32106e259c | ||
| 
						 | 
					b36edd557e | ||
| 
						 | 
					5e3b5e8f36 | ||
| 
						 | 
					764b315dc1 | ||
| 
						 | 
					47c0d2d040 | ||
| 
						 | 
					ac3b777bf6 | ||
| 
						 | 
					166782cd38 | ||
| 
						 | 
					b37eb6d0d1 | ||
| 
						 | 
					f759f5dcf7 | ||
| 
						 | 
					80bcefe321 | ||
| 
						 | 
					70cbbe69d8 | ||
| 
						 | 
					baf4093e8d | ||
| 
						 | 
					fd185f7694 | ||
| 
						 | 
					027d7b6368 | ||
| 
						 | 
					7986b66a88 | ||
| 
						 | 
					edb0edc451 | ||
| 
						 | 
					b511a2e9be | ||
| 
						 | 
					b80ea26a2b | ||
| 
						 | 
					f88986a87d | ||
| 
						 | 
					e16f0848ab | ||
| 
						 | 
					2812a0d12a | ||
| 
						 | 
					25fa26d915 | ||
| 
						 | 
					62915183b1 | ||
| 
						 | 
					6874ab3fb6 | ||
| 
						 | 
					040af4f545 | ||
| 
						 | 
					65ca3eabfd | ||
| 
						 | 
					8b9bbad842 | ||
| 
						 | 
					d2773db7dc | ||
| 
						 | 
					3840451fda | ||
| 
						 | 
					cfe9238882 | ||
| 
						 | 
					0dd46a3543 | ||
| 
						 | 
					f81e63663c | ||
| 
						 | 
					7109e3a17f | ||
| 
						 | 
					e0bd51941e | ||
| 
						 | 
					38f4e67ca7 | ||
| 
						 | 
					681d829227 | ||
| 
						 | 
					164e44c3d9 | ||
| 
						 | 
					2e1d156d66 | ||
| 
						 | 
					e863ad1547 | ||
| 
						 | 
					7091792694 | ||
| 
						 | 
					efd94b705d | ||
| 
						 | 
					9ec989e633 | ||
| 
						 | 
					a716a525c3 | ||
| 
						 | 
					11abfc9ae5 | ||
| 
						 | 
					227cef05b3 | ||
| 
						 | 
					81b0ffb92a | ||
| 
						 | 
					1d3681053b | ||
| 
						 | 
					93df13898f | ||
| 
						 | 
					8314554eb5 | ||
| 
						 | 
					b7c03dc27e | ||
| 
						 | 
					c7f2f609a9 | ||
| 
						 | 
					4c3de3a1ec | 
							
								
								
									
										5
									
								
								.changeset/clean-wolves-turn.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/clean-wolves-turn.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fix: Render newlines as spaces in class diagrams
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/crazy-loops-matter.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/crazy-loops-matter.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fix: Handle arrows correctly when auto number is enabled
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/deep-times-make.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/deep-times-make.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Add IDs in architecture diagrams
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/four-eyes-wish.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/four-eyes-wish.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fix: Ensure edge label color is applied when using classDef with edge IDs
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/hungry-baths-glow.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/hungry-baths-glow.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
 | 
				
			||||||
							
								
								
									
										7
									
								
								.changeset/hungry-guests-drive.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.changeset/hungry-guests-drive.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					'@mermaid-js/layout-tidy-tree': minor
 | 
				
			||||||
 | 
					'@mermaid-js/layout-elk': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/moody-fans-try.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/moody-fans-try.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fix: Resolve gantt chart crash due to invalid array length
 | 
				
			||||||
							
								
								
									
										5
									
								
								.changeset/proud-colts-smell.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/proud-colts-smell.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': minor
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					feat: Add IDs in architecture diagrams
 | 
				
			||||||
							
								
								
									
										9
									
								
								.changeset/revert-marked-dependency.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.changeset/revert-marked-dependency.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					'mermaid': patch
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					chore: revert marked dependency from ^15.0.7 to ^16.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Reverted marked package version to ^16.0.0 for better compatibility
 | 
				
			||||||
 | 
					- This is a dependency update that maintains API compatibility
 | 
				
			||||||
 | 
					- All tests pass with the updated version
 | 
				
			||||||
@@ -8,6 +8,7 @@ compositTitleSize
 | 
				
			|||||||
cose
 | 
					cose
 | 
				
			||||||
curv
 | 
					curv
 | 
				
			||||||
doublecircle
 | 
					doublecircle
 | 
				
			||||||
 | 
					elem
 | 
				
			||||||
elems
 | 
					elems
 | 
				
			||||||
gantt
 | 
					gantt
 | 
				
			||||||
gitgraph
 | 
					gitgraph
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/e2e-timings.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-timings.yml
									
									
									
									
										vendored
									
									
								
							@@ -58,7 +58,7 @@ jobs:
 | 
				
			|||||||
          echo "EOF" >> $GITHUB_OUTPUT
 | 
					          echo "EOF" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Commit and create pull request
 | 
					      - name: Commit and create pull request
 | 
				
			||||||
        uses: peter-evans/create-pull-request@18e469570b1cf0dfc11d60ec121099f8ff3e617a
 | 
					        uses: peter-evans/create-pull-request@915d841dae6a4f191bb78faf61a257411d7be4d2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          add-paths: |
 | 
					          add-paths: |
 | 
				
			||||||
            cypress/timings.json
 | 
					            cypress/timings.json
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,12 +98,12 @@ describe('Configuration', () => {
 | 
				
			|||||||
    it('should handle arrowMarkerAbsolute set to true', () => {
 | 
					    it('should handle arrowMarkerAbsolute set to true', () => {
 | 
				
			||||||
      renderGraph(
 | 
					      renderGraph(
 | 
				
			||||||
        `flowchart TD
 | 
					        `flowchart TD
 | 
				
			||||||
        A[Christmas] -->|Get money| B(Go shopping)
 | 
					    A[Christmas] -->|Get money| B(Go shopping)
 | 
				
			||||||
        B --> C{Let me think}
 | 
					    B --> C{Let me think}
 | 
				
			||||||
        C -->|One| D[Laptop]
 | 
					    C -->|One| D[Laptop]
 | 
				
			||||||
        C -->|Two| E[iPhone]
 | 
					    C -->|Two| E[iPhone]
 | 
				
			||||||
        C -->|Three| F[fa:fa-car Car]
 | 
					    C -->|Three| F[fa:fa-car Car]
 | 
				
			||||||
        `,
 | 
					    `,
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          arrowMarkerAbsolute: true,
 | 
					          arrowMarkerAbsolute: true,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -113,8 +113,7 @@ describe('Configuration', () => {
 | 
				
			|||||||
        cy.get('path')
 | 
					        cy.get('path')
 | 
				
			||||||
          .first()
 | 
					          .first()
 | 
				
			||||||
          .should('have.attr', 'marker-end')
 | 
					          .should('have.attr', 'marker-end')
 | 
				
			||||||
          .should('exist')
 | 
					          .and('include', 'url(http://localhost');
 | 
				
			||||||
          .and('include', 'url(http\\:\\/\\/localhost');
 | 
					 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('should not taint the initial configuration when using multiple directives', () => {
 | 
					    it('should not taint the initial configuration when using multiple directives', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,7 +109,7 @@ describe('Flowchart ELK', () => {
 | 
				
			|||||||
      const style = svg.attr('style');
 | 
					      const style = svg.attr('style');
 | 
				
			||||||
      expect(style).to.match(/^max-width: [\d.]+px;$/);
 | 
					      expect(style).to.match(/^max-width: [\d.]+px;$/);
 | 
				
			||||||
      const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
 | 
					      const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
 | 
				
			||||||
      verifyNumber(maxWidthValue, 380);
 | 
					      verifyNumber(maxWidthValue, 380, 15);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  it('8-elk: should render a flowchart when useMaxWidth is false', () => {
 | 
					  it('8-elk: should render a flowchart when useMaxWidth is false', () => {
 | 
				
			||||||
@@ -128,7 +128,7 @@ describe('Flowchart ELK', () => {
 | 
				
			|||||||
      const width = parseFloat(svg.attr('width'));
 | 
					      const width = parseFloat(svg.attr('width'));
 | 
				
			||||||
      // use within because the absolute value can be slightly different depending on the environment ±5%
 | 
					      // use within because the absolute value can be slightly different depending on the environment ±5%
 | 
				
			||||||
      // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
 | 
					      // expect(height).to.be.within(446 * 0.95, 446 * 1.05);
 | 
				
			||||||
      verifyNumber(width, 380);
 | 
					      verifyNumber(width, 380, 15);
 | 
				
			||||||
      expect(svg).to.not.have.attr('style');
 | 
					      expect(svg).to.not.have.attr('style');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1186,4 +1186,17 @@ end
 | 
				
			|||||||
      imgSnapshotTest(graph, { htmlLabels: false });
 | 
					      imgSnapshotTest(graph, { htmlLabels: false });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('V2 - 17: should apply class def colour to edge label', () => {
 | 
				
			||||||
 | 
					    imgSnapshotTest(
 | 
				
			||||||
 | 
					      ` graph LR
 | 
				
			||||||
 | 
					    id1(Start) link@-- "Label" -->id2(Stop)
 | 
				
			||||||
 | 
					    style id1 fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class id2 myClass
 | 
				
			||||||
 | 
					classDef myClass fill:#bbf,stroke:#f66,stroke-width:2px,color:white,stroke-dasharray: 5 5
 | 
				
			||||||
 | 
					class link myClass
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -803,4 +803,34 @@ describe('Gantt diagram', () => {
 | 
				
			|||||||
      {}
 | 
					      {}
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					  it('should handle numeric timestamps with dateFormat x', () => {
 | 
				
			||||||
 | 
					    imgSnapshotTest(
 | 
				
			||||||
 | 
					      `
 | 
				
			||||||
 | 
					     gantt
 | 
				
			||||||
 | 
					     title Process time profile (ms)
 | 
				
			||||||
 | 
					     dateFormat x
 | 
				
			||||||
 | 
					     axisFormat %L
 | 
				
			||||||
 | 
					     tickInterval 250millisecond
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     section Pipeline
 | 
				
			||||||
 | 
					     Parse JSON p1: 000, 120
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					      {}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  it('should handle numeric timestamps with dateFormat X', () => {
 | 
				
			||||||
 | 
					    imgSnapshotTest(
 | 
				
			||||||
 | 
					      `
 | 
				
			||||||
 | 
					     gantt
 | 
				
			||||||
 | 
					     title Process time profile (ms)
 | 
				
			||||||
 | 
					     dateFormat X
 | 
				
			||||||
 | 
					     axisFormat %L
 | 
				
			||||||
 | 
					     tickInterval 250millisecond
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     section Pipeline
 | 
				
			||||||
 | 
					     Parse JSON p1: 000, 120
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					      {}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,26 +32,8 @@
 | 
				
			|||||||
      href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
					      href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
				
			||||||
      rel="stylesheet"
 | 
					      rel="stylesheet"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
					 | 
				
			||||||
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
 | 
					 | 
				
			||||||
    <link
 | 
					 | 
				
			||||||
      href="https://fonts.googleapis.com/css2?family=Recursive:wght@300..1000&display=swap"
 | 
					 | 
				
			||||||
      rel="stylesheet"
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <style>
 | 
					    <style>
 | 
				
			||||||
      .recursive-mermaid {
 | 
					 | 
				
			||||||
        font-family: 'Recursive', sans-serif;
 | 
					 | 
				
			||||||
        font-optical-sizing: auto;
 | 
					 | 
				
			||||||
        font-weight: 500;
 | 
					 | 
				
			||||||
        font-style: normal;
 | 
					 | 
				
			||||||
        font-variation-settings:
 | 
					 | 
				
			||||||
          'slnt' 0,
 | 
					 | 
				
			||||||
          'CASL' 0,
 | 
					 | 
				
			||||||
          'CRSV' 0.5,
 | 
					 | 
				
			||||||
          'MONO' 0;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      body {
 | 
					      body {
 | 
				
			||||||
        /* background: rgb(221, 208, 208); */
 | 
					        /* background: rgb(221, 208, 208); */
 | 
				
			||||||
        /* background: #333; */
 | 
					        /* background: #333; */
 | 
				
			||||||
@@ -63,9 +45,7 @@
 | 
				
			|||||||
      h1 {
 | 
					      h1 {
 | 
				
			||||||
        color: grey;
 | 
					        color: grey;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      .mermaid {
 | 
					
 | 
				
			||||||
        border: 1px solid red;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      .mermaid2 {
 | 
					      .mermaid2 {
 | 
				
			||||||
        display: none;
 | 
					        display: none;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -103,11 +83,6 @@
 | 
				
			|||||||
        width: 100%;
 | 
					        width: 100%;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .class2 {
 | 
					 | 
				
			||||||
        fill: red;
 | 
					 | 
				
			||||||
        fill-opacity: 1;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      /* tspan {
 | 
					      /* tspan {
 | 
				
			||||||
              font-size: 6px !important;
 | 
					              font-size: 6px !important;
 | 
				
			||||||
            } */
 | 
					            } */
 | 
				
			||||||
@@ -130,76 +105,194 @@
 | 
				
			|||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: tidy-tree
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      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>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: tidy-tree
 | 
					        layout: elk
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      mindmap
 | 
					      flowchart-elk TB
 | 
				
			||||||
      root((mindmap is a long thing))
 | 
					      c1-->a2
 | 
				
			||||||
        A
 | 
					      subgraph one
 | 
				
			||||||
        B
 | 
					      a1-->a2
 | 
				
			||||||
        C
 | 
					      end
 | 
				
			||||||
        D
 | 
					      subgraph two
 | 
				
			||||||
      </pre
 | 
					      b1-->b2
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      subgraph three
 | 
				
			||||||
 | 
					      c1-->c2
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      one --> two
 | 
				
			||||||
 | 
					      three --> two
 | 
				
			||||||
 | 
					      two --> c2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: tidy-tree
 | 
					        layout: elk
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      mindmap
 | 
					      flowchart TB
 | 
				
			||||||
      root((mindmap))
 | 
					
 | 
				
			||||||
        A
 | 
					        process_C
 | 
				
			||||||
        B
 | 
					      subgraph container_Alpha
 | 
				
			||||||
      </pre
 | 
					        subgraph process_B
 | 
				
			||||||
 | 
					          pppB
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        subgraph process_A
 | 
				
			||||||
 | 
					          pppA
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        process_B-->|via_AWSBatch|container_Beta
 | 
				
			||||||
 | 
					        process_A-->|messages|container_Beta
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: tidy-tree
 | 
					        layout: elk
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      mindmap
 | 
					      flowchart TB
 | 
				
			||||||
      root((mindmap))
 | 
					      subgraph container_Beta
 | 
				
			||||||
        A
 | 
					        process_C
 | 
				
			||||||
          a
 | 
					      end
 | 
				
			||||||
            apa[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					      subgraph container_Alpha
 | 
				
			||||||
            apa2[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					        subgraph process_B
 | 
				
			||||||
          b
 | 
					          pppB
 | 
				
			||||||
          c
 | 
					        end
 | 
				
			||||||
          d
 | 
					        subgraph process_A
 | 
				
			||||||
        B
 | 
					          pppA
 | 
				
			||||||
            apa3[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					        end
 | 
				
			||||||
        D
 | 
					        process_B-->|via_AWSBatch|container_Beta
 | 
				
			||||||
          apa5[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					        process_A-->|messages|container_Beta
 | 
				
			||||||
          apa4[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      flowchart TB
 | 
				
			||||||
 | 
					      subgraph container_Beta
 | 
				
			||||||
 | 
					        process_C
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        process_B-->|via_AWSBatch|container_Beta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      classDiagram
 | 
				
			||||||
 | 
					      note "I love this diagram!\nDo you love it?"
 | 
				
			||||||
 | 
					      Class01 <|-- AveryLongClass : Cool
 | 
				
			||||||
 | 
					      <<interface>> Class01
 | 
				
			||||||
 | 
					      Class03 "1" *-- "*" Class04
 | 
				
			||||||
 | 
					      Class05 "1" o-- "many" Class06
 | 
				
			||||||
 | 
					      Class07 "1" .. "*" Class08
 | 
				
			||||||
 | 
					      Class09 "1" --> "*" C2 : Where am i?
 | 
				
			||||||
 | 
					      Class09 "*" --* "*" C3
 | 
				
			||||||
 | 
					      Class09 "1" --|> "1" Class07
 | 
				
			||||||
 | 
					      Class12 <|.. Class08
 | 
				
			||||||
 | 
					      Class11 ..>Class12
 | 
				
			||||||
 | 
					      Class07 : equals()
 | 
				
			||||||
 | 
					      Class07 : Object[] elementData
 | 
				
			||||||
 | 
					      Class01 : size()
 | 
				
			||||||
 | 
					      Class01 : int chimp
 | 
				
			||||||
 | 
					      Class01 : int gorilla
 | 
				
			||||||
 | 
					      Class01 : -int privateChimp
 | 
				
			||||||
 | 
					      Class01 : +int publicGorilla
 | 
				
			||||||
 | 
					      Class01 : #int protectedMarmoset
 | 
				
			||||||
 | 
					      Class08 <--> C2: Cool label
 | 
				
			||||||
 | 
					      class Class10 {
 | 
				
			||||||
 | 
					        <<service>>
 | 
				
			||||||
 | 
					        int id
 | 
				
			||||||
 | 
					        test()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      note for Class10 "Cool class\nI said it's very cool class!"
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      requirementDiagram
 | 
				
			||||||
 | 
					        requirement test_req {
 | 
				
			||||||
 | 
					        id: 1
 | 
				
			||||||
 | 
					        text: the test text.
 | 
				
			||||||
 | 
					        risk: high
 | 
				
			||||||
 | 
					        verifymethod: test
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        element test_entity {
 | 
				
			||||||
 | 
					        type: simulation
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_entity - satisfies -> test_req
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      flowchart-elk TB
 | 
				
			||||||
 | 
					      internet
 | 
				
			||||||
 | 
					      nat
 | 
				
			||||||
 | 
					      router
 | 
				
			||||||
 | 
					      compute1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      subgraph project
 | 
				
			||||||
 | 
					      router
 | 
				
			||||||
 | 
					      nat
 | 
				
			||||||
 | 
					        subgraph subnet1
 | 
				
			||||||
 | 
					          compute1
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      %% router --> subnet1
 | 
				
			||||||
 | 
					      subnet1  --> nat
 | 
				
			||||||
 | 
					      %% nat --> internet
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      flowchart-elk TB
 | 
				
			||||||
 | 
					      internet
 | 
				
			||||||
 | 
					      nat
 | 
				
			||||||
 | 
					      router
 | 
				
			||||||
 | 
					      lb1
 | 
				
			||||||
 | 
					      lb2
 | 
				
			||||||
 | 
					      compute1
 | 
				
			||||||
 | 
					      compute2
 | 
				
			||||||
 | 
					      subgraph project
 | 
				
			||||||
 | 
					      router
 | 
				
			||||||
 | 
					      nat
 | 
				
			||||||
 | 
					        subgraph subnet1
 | 
				
			||||||
 | 
					          compute1
 | 
				
			||||||
 | 
					          lb1
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        subgraph subnet2
 | 
				
			||||||
 | 
					          compute2
 | 
				
			||||||
 | 
					          lb2
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      internet --> router
 | 
				
			||||||
 | 
					      router --> subnet1 & subnet2
 | 
				
			||||||
 | 
					      subnet1 & subnet2 --> nat --> internet
 | 
				
			||||||
 | 
					</pre
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
@@ -227,91 +320,35 @@ treemap
 | 
				
			|||||||
    "Leaf 2.2": 25
 | 
					    "Leaf 2.2": 25
 | 
				
			||||||
    "Leaf 2.3": 12
 | 
					    "Leaf 2.3": 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
classDef class1   fill:red,color:blue,stroke:#FFD600;
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <pre id="diagram5" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					        flowchart:
 | 
				
			||||||
 | 
					          curve: rounded
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      flowchart LR
 | 
				
			||||||
 | 
					          I["fa:fa-code Text"] -- Mermaid js --> D["Use<br/>the<br/>editor!"]
 | 
				
			||||||
 | 
					          I --> D & D
 | 
				
			||||||
 | 
					          D@{ shape: question}
 | 
				
			||||||
 | 
					          I@{ shape: question}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
</pre
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
config:
 | 
					 | 
				
			||||||
  treemap:
 | 
					 | 
				
			||||||
    valueFormat: '$0,0'
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
treemap
 | 
					 | 
				
			||||||
"Budget"
 | 
					 | 
				
			||||||
    "Operations"
 | 
					 | 
				
			||||||
        "Salaries": 7000
 | 
					 | 
				
			||||||
        "Equipment": 2000
 | 
					 | 
				
			||||||
        "Supplies": 1000
 | 
					 | 
				
			||||||
    "Marketing"
 | 
					 | 
				
			||||||
        "Advertising": 4000
 | 
					 | 
				
			||||||
        "Events": 1000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</pre
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
    treemap
 | 
					 | 
				
			||||||
      title Accessible Treemap Title
 | 
					 | 
				
			||||||
      "Category A"
 | 
					 | 
				
			||||||
          "Item A1": 10
 | 
					 | 
				
			||||||
          "Item A2": 20
 | 
					 | 
				
			||||||
      "Category B"
 | 
					 | 
				
			||||||
          "Item B1": 15
 | 
					 | 
				
			||||||
          "Item B2": 25
 | 
					 | 
				
			||||||
    </pre>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: tidy-tree
 | 
					        layout: tidy-tree
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      mindmap
 | 
					      mindmap
 | 
				
			||||||
      root((mindmap))
 | 
					      root((mindmap))
 | 
				
			||||||
        a
 | 
					 | 
				
			||||||
          apa[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					 | 
				
			||||||
          apa2[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					 | 
				
			||||||
        b
 | 
					 | 
				
			||||||
          apa3[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					 | 
				
			||||||
          apa4[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    </pre>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: tidy-tree
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      flowchart TB
 | 
					 | 
				
			||||||
          A --> n0["1"]
 | 
					 | 
				
			||||||
          A --> n1["2"]
 | 
					 | 
				
			||||||
          A --> n2["3"]
 | 
					 | 
				
			||||||
          A --> n3["4"] --> Q & R & S & T
 | 
					 | 
				
			||||||
    </pre>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: elk
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      flowchart TB
 | 
					 | 
				
			||||||
          A --> n0["1"]
 | 
					 | 
				
			||||||
          A --> n1["2"]
 | 
					 | 
				
			||||||
          A --> n2["3"]
 | 
					 | 
				
			||||||
          A --> n3["4"] --> Q & R & S & T
 | 
					 | 
				
			||||||
    </pre>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: dagre
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      mindmap
 | 
					 | 
				
			||||||
      root((mindmap is a long thing))
 | 
					 | 
				
			||||||
        Origins
 | 
					        Origins
 | 
				
			||||||
          Long history
 | 
					          Long history
 | 
				
			||||||
          ::icon(fa fa-book)
 | 
					          ::icon(fa fa-book)
 | 
				
			||||||
          Popularisation
 | 
					          Popularisation
 | 
				
			||||||
            British popular psychology author Tony Buzan
 | 
					            British popular psychology author Tony Buzan
 | 
				
			||||||
        Research
 | 
					        Research
 | 
				
			||||||
          On effectiveness<br/>and features
 | 
					          On effectiveness<br/>and features
 | 
				
			||||||
          On Automatic creation
 | 
					          On Automatic creation
 | 
				
			||||||
            Uses
 | 
					            Uses
 | 
				
			||||||
                Creative techniques
 | 
					                Creative techniques
 | 
				
			||||||
@@ -320,128 +357,112 @@ treemap
 | 
				
			|||||||
        Tools
 | 
					        Tools
 | 
				
			||||||
          Pen and paper
 | 
					          Pen and paper
 | 
				
			||||||
          Mermaid
 | 
					          Mermaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: cose-bilkent
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      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>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: elk
 | 
					        layout: elk
 | 
				
			||||||
      ---
 | 
					        flowchart:
 | 
				
			||||||
      mindmap
 | 
					          curve: linear
 | 
				
			||||||
      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>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
      ---
 | 
					 | 
				
			||||||
      config:
 | 
					 | 
				
			||||||
        layout: cose-bilkent
 | 
					 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      flowchart LR
 | 
					      flowchart LR
 | 
				
			||||||
      root{mindmap} --- Origins --- Europe
 | 
					          A[A] --> B[B]
 | 
				
			||||||
      Origins --> Asia
 | 
					          A[A] --- B([C])
 | 
				
			||||||
      root --- Background --- Rich
 | 
					          A@{ shape: diamond}
 | 
				
			||||||
      Background --- Poor
 | 
					          %%B@{ shape: diamond}
 | 
				
			||||||
      subgraph apa
 | 
					 | 
				
			||||||
        Background
 | 
					 | 
				
			||||||
        Poor
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      config:
 | 
					      config:
 | 
				
			||||||
        layout: elk
 | 
					        layout: elk
 | 
				
			||||||
 | 
					        flowchart:
 | 
				
			||||||
 | 
					          curve: linear
 | 
				
			||||||
      ---
 | 
					      ---
 | 
				
			||||||
      flowchart LR
 | 
					      flowchart LR
 | 
				
			||||||
      root{mindmap} --- Origins --- Europe
 | 
					          A[A] -- Mermaid js --> B[B]
 | 
				
			||||||
      Origins --> Asia
 | 
					          A[A] -- Mermaid js --- B[B]
 | 
				
			||||||
      root --- Background --- Rich
 | 
					          A@{ shape: diamond}
 | 
				
			||||||
      Background --- Poor
 | 
					          B@{ shape: diamond}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
      flowchart
 | 
					      ---
 | 
				
			||||||
        D(("for D"))
 | 
					      config:
 | 
				
			||||||
    </pre>
 | 
					        layout: elk
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					        flowchart:
 | 
				
			||||||
 | 
					          curve: rounded
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
      flowchart LR
 | 
					      flowchart LR
 | 
				
			||||||
        A e1@==> B
 | 
					          D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
 | 
				
			||||||
        e1@{ animate: true}
 | 
					          I --> D & D
 | 
				
			||||||
 | 
					          D@{ shape: question}
 | 
				
			||||||
 | 
					          I@{ shape: question}
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					      ---
 | 
				
			||||||
  A e1@--> B
 | 
					      config:
 | 
				
			||||||
  classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
 | 
					        layout: elk
 | 
				
			||||||
  class e1 animate
 | 
					        flowchart:
 | 
				
			||||||
    </pre>
 | 
					          curve: rounded
 | 
				
			||||||
    <h2>infinite</h2>
 | 
					        elk:
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					          nodePlacementStrategy: NETWORK_SIMPLEX
 | 
				
			||||||
flowchart LR
 | 
					      ---
 | 
				
			||||||
  A e1@--> B
 | 
					      flowchart LR
 | 
				
			||||||
  classDef animate stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
 | 
					          D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
 | 
				
			||||||
  class e1 animate
 | 
					          D --> I & I
 | 
				
			||||||
    </pre>
 | 
					          a["a"]
 | 
				
			||||||
    <h2>Mermaid - edge-animation-slow</h2>
 | 
					          D@{ shape: trap-b}
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					          I@{ shape: lean-l}
 | 
				
			||||||
flowchart LR
 | 
					 | 
				
			||||||
  A e1@--> B
 | 
					 | 
				
			||||||
e1@{ animation: fast}
 | 
					 | 
				
			||||||
    </pre>
 | 
					 | 
				
			||||||
    <h2>Mermaid - edge-animation-fast</h2>
 | 
					 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					 | 
				
			||||||
flowchart LR
 | 
					 | 
				
			||||||
  A e1@--> B
 | 
					 | 
				
			||||||
  classDef animate stroke-dasharray: 1000,stroke-dashoffset: 1000,animation: dash 10s linear;
 | 
					 | 
				
			||||||
  class e1 edge-animation-fast
 | 
					 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					config:
 | 
				
			||||||
 | 
					  layout: elk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					---
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					 %% subgraph s1["Untitled subgraph"]
 | 
				
			||||||
 | 
					        C["Evaluate"]
 | 
				
			||||||
 | 
					 %% end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
info    </pre
 | 
					    B --> C
 | 
				
			||||||
    >
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					config:
 | 
				
			||||||
 | 
					  layout: elk
 | 
				
			||||||
 | 
					  flowchart:
 | 
				
			||||||
 | 
					    //curve: linear
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					flowchart LR
 | 
				
			||||||
 | 
					%% A ==> B
 | 
				
			||||||
 | 
					%% A2 --> B2
 | 
				
			||||||
 | 
					A{A} --> B((Bo boo)) & B & B & B
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      config:
 | 
				
			||||||
 | 
					        layout: elk
 | 
				
			||||||
 | 
					        theme: default
 | 
				
			||||||
 | 
					        look: classic
 | 
				
			||||||
 | 
					      ---
 | 
				
			||||||
 | 
					      flowchart LR
 | 
				
			||||||
 | 
					       subgraph s1["APA"]
 | 
				
			||||||
 | 
					              D{"Use the editor"}
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					       subgraph S2["S2"]
 | 
				
			||||||
 | 
					              s1
 | 
				
			||||||
 | 
					              I>"fa:fa-code Text"]
 | 
				
			||||||
 | 
					              E["E"]
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					          D -- Mermaid js --> I
 | 
				
			||||||
 | 
					          D --> I & E
 | 
				
			||||||
 | 
					          E --> I
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -466,7 +487,7 @@ config:
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -479,45 +500,7 @@ config:
 | 
				
			|||||||
      D-->I
 | 
					      D-->I
 | 
				
			||||||
      D-->I
 | 
					      D-->I
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <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="mermaid2">
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
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="mermaid2">
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -556,7 +539,7 @@ flowchart LR
 | 
				
			|||||||
    n8@{ shape: rect}
 | 
					    n8@{ shape: rect}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -572,7 +555,7 @@ flowchart LR
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -581,7 +564,7 @@ flowchart LR
 | 
				
			|||||||
    A{A} --> B & C
 | 
					    A{A} --> B & C
 | 
				
			||||||
</pre
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -593,7 +576,7 @@ flowchart LR
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
</pre
 | 
					</pre
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  layout: elk
 | 
					  layout: elk
 | 
				
			||||||
@@ -611,7 +594,7 @@ flowchart LR
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  kanban:
 | 
					  kanban:
 | 
				
			||||||
@@ -630,81 +613,81 @@ kanban
 | 
				
			|||||||
    task3[💻 Develop login feature]@{ ticket: 103 }
 | 
					    task3[💻 Develop login feature]@{ ticket: 103 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
					nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
					nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
				
			||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
					style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
					nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
				
			||||||
A:::AClass
 | 
					A:::AClass
 | 
				
			||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
					classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
 | 
					  nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
					nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
					nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
				
			||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
					style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
					nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
				
			||||||
A:::AClass
 | 
					A:::AClass
 | 
				
			||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
					classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
 | 
					  nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
					nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
					nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
				
			||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
					style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
					nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
				
			||||||
A:::AClass
 | 
					A:::AClass
 | 
				
			||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
					classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
					  nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
				
			||||||
  A:::AClass
 | 
					  A:::AClass
 | 
				
			||||||
  classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
					  classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
flowchart LR
 | 
					flowchart LR
 | 
				
			||||||
  nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
					  nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
				
			||||||
  style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
					  style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
kanban
 | 
					kanban
 | 
				
			||||||
  id2[In progress]
 | 
					  id2[In progress]
 | 
				
			||||||
    docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
 | 
					    docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
 | 
				
			||||||
    </pre>
 | 
					    </pre>
 | 
				
			||||||
    <pre id="diagram4" class="mermaid2">
 | 
					    <pre id="diagram4" class="mermaid">
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
config:
 | 
					config:
 | 
				
			||||||
  kanban:
 | 
					  kanban:
 | 
				
			||||||
@@ -768,18 +751,22 @@ kanban
 | 
				
			|||||||
        alert('It worked');
 | 
					        alert('It worked');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      await mermaid.initialize({
 | 
					      await mermaid.initialize({
 | 
				
			||||||
        // theme: 'forest',
 | 
					        // theme: 'base',
 | 
				
			||||||
        // theme: 'default',
 | 
					        // theme: 'default',
 | 
				
			||||||
        // theme: 'forest',
 | 
					        // theme: 'forest',
 | 
				
			||||||
        // handDrawnSeed: 12,
 | 
					        // handDrawnSeed: 12,
 | 
				
			||||||
        // look: 'handDrawn',
 | 
					        // look: 'handDrawn',
 | 
				
			||||||
        // 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
 | 
					        // 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
 | 
				
			||||||
        // layout: 'dagre',
 | 
					        // layout: 'dagre',
 | 
				
			||||||
        // layout: 'elk',
 | 
					        layout: 'elk',
 | 
				
			||||||
        // layout: 'fixed',
 | 
					        // layout: 'fixed',
 | 
				
			||||||
        // htmlLabels: false,
 | 
					        // htmlLabels: false,
 | 
				
			||||||
        flowchart: { titleTopMargin: 10 },
 | 
					        flowchart: { titleTopMargin: 10 },
 | 
				
			||||||
        fontFamily: "'Recursive', sans-serif",
 | 
					
 | 
				
			||||||
 | 
					        // fontFamily: 'Caveat',
 | 
				
			||||||
 | 
					        // fontFamily: 'Kalam',
 | 
				
			||||||
 | 
					        // fontFamily: 'courier',
 | 
				
			||||||
 | 
					        fontFamily: 'arial',
 | 
				
			||||||
        sequence: {
 | 
					        sequence: {
 | 
				
			||||||
          actorFontFamily: 'courier',
 | 
					          actorFontFamily: 'courier',
 | 
				
			||||||
          noteFontFamily: 'courier',
 | 
					          noteFontFamily: 'courier',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Interface: ExternalDiagramDefinition
 | 
					# Interface: ExternalDiagramDefinition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L94)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L96)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Properties
 | 
					## Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:94](https://github.com/me
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **detector**: `DiagramDetector`
 | 
					> **detector**: `DiagramDetector`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L96)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L98)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/me
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **id**: `string`
 | 
					> **id**: `string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L95)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L97)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,4 +34,4 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:95](https://github.com/me
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **loader**: `DiagramLoader`
 | 
					> **loader**: `DiagramLoader`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L97)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:99](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L99)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Interface: LayoutLoaderDefinition
 | 
					# Interface: LayoutLoaderDefinition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:21](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L21)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Properties
 | 
					## Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:21](https://github.co
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> `optional` **algorithm**: `string`
 | 
					> `optional` **algorithm**: `string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:27](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L27)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.co
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **loader**: `LayoutLoader`
 | 
					> **loader**: `LayoutLoader`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:23](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L23)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:26](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L26)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,4 +34,4 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:23](https://github.co
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **name**: `string`
 | 
					> **name**: `string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:22](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L22)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:25](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L25)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Interface: RenderOptions
 | 
					# Interface: RenderOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:7](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L7)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:10](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Properties
 | 
					## Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,4 +18,4 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:7](https://github.com
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> `optional` **algorithm**: `string`
 | 
					> `optional` **algorithm**: `string`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:8](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L8)
 | 
					Defined in: [packages/mermaid/src/rendering-util/render.ts:11](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L11)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,4 +12,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **SVG** = `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
					> **SVG** = `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L126)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L128)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,4 +12,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> **SVGGroup** = `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
					> **SVGGroup** = `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L128)
 | 
					Defined in: [packages/mermaid/src/diagram-api/types.ts:130](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L130)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,3 +38,5 @@ Each user journey is split into sections, these describe the part of the task
 | 
				
			|||||||
the user is trying to complete.
 | 
					the user is trying to complete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tasks syntax is `Task name: <score>: <comma separated list of actors>`
 | 
					Tasks syntax is `Task name: <score>: <comma separated list of actors>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Score is a number between 1 and 5, inclusive.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
  "version": "1.0.0",
 | 
					  "version": "1.0.0",
 | 
				
			||||||
  "description": "Mermaid examples package",
 | 
					  "description": "Mermaid examples package",
 | 
				
			||||||
  "author": "Sidharth Vinod",
 | 
					  "author": "Sidharth Vinod",
 | 
				
			||||||
 | 
					  "license": "MIT",
 | 
				
			||||||
  "type": "module",
 | 
					  "type": "module",
 | 
				
			||||||
  "module": "./dist/mermaid-examples.core.mjs",
 | 
					  "module": "./dist/mermaid-examples.core.mjs",
 | 
				
			||||||
  "types": "./dist/mermaid.d.ts",
 | 
					  "types": "./dist/mermaid.d.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,5 @@
 | 
				
			|||||||
# @mermaid-js/layout-elk
 | 
					# @mermaid-js/layout-elk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Minor Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Patch Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
 | 
					 | 
				
			||||||
  - mermaid@11.11.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 0.1.9
 | 
					## 0.1.9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Patch Changes
 | 
					### Patch Changes
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@mermaid-js/layout-elk",
 | 
					  "name": "@mermaid-js/layout-elk",
 | 
				
			||||||
  "version": "0.2.0",
 | 
					  "version": "0.1.9",
 | 
				
			||||||
  "description": "ELK layout engine for mermaid",
 | 
					  "description": "ELK layout engine for mermaid",
 | 
				
			||||||
  "module": "dist/mermaid-layout-elk.core.mjs",
 | 
					  "module": "dist/mermaid-layout-elk.core.mjs",
 | 
				
			||||||
  "types": "dist/layouts.d.ts",
 | 
					  "types": "dist/layouts.d.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										67
									
								
								packages/mermaid-layout-elk/src/__tests__/geometry.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								packages/mermaid-layout-elk/src/__tests__/geometry.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					import { describe, it, expect } from 'vitest';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  intersection,
 | 
				
			||||||
 | 
					  ensureTrulyOutside,
 | 
				
			||||||
 | 
					  makeInsidePoint,
 | 
				
			||||||
 | 
					  tryNodeIntersect,
 | 
				
			||||||
 | 
					  replaceEndpoint,
 | 
				
			||||||
 | 
					  type RectLike,
 | 
				
			||||||
 | 
					  type P,
 | 
				
			||||||
 | 
					} from '../geometry.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const approx = (a: number, b: number, eps = 1e-6) => Math.abs(a - b) < eps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('geometry helpers', () => {
 | 
				
			||||||
 | 
					  it('intersection: vertical approach hits bottom border', () => {
 | 
				
			||||||
 | 
					    const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
 | 
				
			||||||
 | 
					    const h = rect.height / 2; // 25
 | 
				
			||||||
 | 
					    const outside: P = { x: 0, y: 100 };
 | 
				
			||||||
 | 
					    const inside: P = { x: 0, y: 0 };
 | 
				
			||||||
 | 
					    const res = intersection(rect, outside, inside);
 | 
				
			||||||
 | 
					    expect(approx(res.x, 0)).toBe(true);
 | 
				
			||||||
 | 
					    expect(approx(res.y, h)).toBe(true);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('ensureTrulyOutside nudges near-boundary point outward', () => {
 | 
				
			||||||
 | 
					    const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
 | 
				
			||||||
 | 
					    // near bottom boundary (y ~ h)
 | 
				
			||||||
 | 
					    const near: P = { x: 0, y: rect.height / 2 - 0.2 };
 | 
				
			||||||
 | 
					    const out = ensureTrulyOutside(rect, near, 10);
 | 
				
			||||||
 | 
					    expect(out.y).toBeGreaterThan(rect.height / 2);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('makeInsidePoint keeps x for vertical and y from center', () => {
 | 
				
			||||||
 | 
					    const rect: RectLike = { x: 10, y: 5, width: 100, height: 50 };
 | 
				
			||||||
 | 
					    const outside: P = { x: 10, y: 40 };
 | 
				
			||||||
 | 
					    const center: P = { x: 99, y: -123 }; // center y should be used
 | 
				
			||||||
 | 
					    const inside = makeInsidePoint(rect, outside, center);
 | 
				
			||||||
 | 
					    expect(inside.x).toBe(outside.x);
 | 
				
			||||||
 | 
					    expect(inside.y).toBe(center.y);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('tryNodeIntersect returns null for wrong-side intersections', () => {
 | 
				
			||||||
 | 
					    const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
 | 
				
			||||||
 | 
					    const outside: P = { x: -50, y: 0 };
 | 
				
			||||||
 | 
					    const node = { intersect: () => ({ x: 10, y: 0 }) } as any; // right side of center
 | 
				
			||||||
 | 
					    const res = tryNodeIntersect(node, rect, outside);
 | 
				
			||||||
 | 
					    expect(res).toBeNull();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('replaceEndpoint dedup removes end/start appropriately', () => {
 | 
				
			||||||
 | 
					    const pts: P[] = [
 | 
				
			||||||
 | 
					      { x: 0, y: 0 },
 | 
				
			||||||
 | 
					      { x: 1, y: 1 },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    // remove duplicate end
 | 
				
			||||||
 | 
					    replaceEndpoint(pts, 'end', { x: 1, y: 1 });
 | 
				
			||||||
 | 
					    expect(pts.length).toBe(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const pts2: P[] = [
 | 
				
			||||||
 | 
					      { x: 0, y: 0 },
 | 
				
			||||||
 | 
					      { x: 1, y: 1 },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    // remove duplicate start
 | 
				
			||||||
 | 
					    replaceEndpoint(pts2, 'start', { x: 0, y: 0 });
 | 
				
			||||||
 | 
					    expect(pts2.length).toBe(1);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										209
									
								
								packages/mermaid-layout-elk/src/geometry.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								packages/mermaid-layout-elk/src/geometry.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					/* Geometry utilities extracted from render.ts for reuse and testing */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface P {
 | 
				
			||||||
 | 
					  x: number;
 | 
				
			||||||
 | 
					  y: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface RectLike {
 | 
				
			||||||
 | 
					  x: number; // center x
 | 
				
			||||||
 | 
					  y: number; // center y
 | 
				
			||||||
 | 
					  width: number;
 | 
				
			||||||
 | 
					  height: number;
 | 
				
			||||||
 | 
					  padding?: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface NodeLike {
 | 
				
			||||||
 | 
					  intersect?: (p: P) => P | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const EPS = 1;
 | 
				
			||||||
 | 
					export const PUSH_OUT = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const onBorder = (bounds: RectLike, p: P, tol = 0.5): boolean => {
 | 
				
			||||||
 | 
					  const halfW = bounds.width / 2;
 | 
				
			||||||
 | 
					  const halfH = bounds.height / 2;
 | 
				
			||||||
 | 
					  const left = bounds.x - halfW;
 | 
				
			||||||
 | 
					  const right = bounds.x + halfW;
 | 
				
			||||||
 | 
					  const top = bounds.y - halfH;
 | 
				
			||||||
 | 
					  const bottom = bounds.y + halfH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onLeft = Math.abs(p.x - left) <= tol && p.y >= top - tol && p.y <= bottom + tol;
 | 
				
			||||||
 | 
					  const onRight = Math.abs(p.x - right) <= tol && p.y >= top - tol && p.y <= bottom + tol;
 | 
				
			||||||
 | 
					  const onTop = Math.abs(p.y - top) <= tol && p.x >= left - tol && p.x <= right + tol;
 | 
				
			||||||
 | 
					  const onBottom = Math.abs(p.y - bottom) <= tol && p.x >= left - tol && p.x <= right + tol;
 | 
				
			||||||
 | 
					  return onLeft || onRight || onTop || onBottom;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Compute intersection between a rectangle (center x/y, width/height) and the line
 | 
				
			||||||
 | 
					 * segment from insidePoint -\> outsidePoint. Returns the point on the rectangle border.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This version avoids snapping to outsidePoint when certain variables evaluate to 0
 | 
				
			||||||
 | 
					 * (previously caused vertical top/bottom cases to miss the border). It only enforces
 | 
				
			||||||
 | 
					 * axis-constant behavior for purely vertical/horizontal approaches.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const intersection = (node: RectLike, outsidePoint: P, insidePoint: P): P => {
 | 
				
			||||||
 | 
					  const x = node.x;
 | 
				
			||||||
 | 
					  const y = node.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const dx = Math.abs(x - insidePoint.x);
 | 
				
			||||||
 | 
					  const w = node.width / 2;
 | 
				
			||||||
 | 
					  let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
 | 
				
			||||||
 | 
					  const h = node.height / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Q = Math.abs(outsidePoint.y - insidePoint.y);
 | 
				
			||||||
 | 
					  const R = Math.abs(outsidePoint.x - insidePoint.x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
 | 
				
			||||||
 | 
					    // Intersection is top or bottom of rect.
 | 
				
			||||||
 | 
					    const q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
 | 
				
			||||||
 | 
					    r = (R * q) / Q;
 | 
				
			||||||
 | 
					    const res = {
 | 
				
			||||||
 | 
					      x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
 | 
				
			||||||
 | 
					      y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Keep axis-constant special-cases only
 | 
				
			||||||
 | 
					    if (R === 0) {
 | 
				
			||||||
 | 
					      res.x = outsidePoint.x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Q === 0) {
 | 
				
			||||||
 | 
					      res.y = outsidePoint.y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Intersection on sides of rect
 | 
				
			||||||
 | 
					    if (insidePoint.x < outsidePoint.x) {
 | 
				
			||||||
 | 
					      r = outsidePoint.x - w - x;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      r = x - w - outsidePoint.x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const q = (Q * r) / R;
 | 
				
			||||||
 | 
					    let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
 | 
				
			||||||
 | 
					    let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Only handle axis-constant cases
 | 
				
			||||||
 | 
					    if (R === 0) {
 | 
				
			||||||
 | 
					      _x = outsidePoint.x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Q === 0) {
 | 
				
			||||||
 | 
					      _y = outsidePoint.y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return { x: _x, y: _y };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const outsideNode = (node: RectLike, point: P): boolean => {
 | 
				
			||||||
 | 
					  const x = node.x;
 | 
				
			||||||
 | 
					  const y = node.y;
 | 
				
			||||||
 | 
					  const dx = Math.abs(point.x - x);
 | 
				
			||||||
 | 
					  const dy = Math.abs(point.y - y);
 | 
				
			||||||
 | 
					  const w = node.width / 2;
 | 
				
			||||||
 | 
					  const h = node.height / 2;
 | 
				
			||||||
 | 
					  return dx >= w || dy >= h;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ensureTrulyOutside = (bounds: RectLike, p: P, push = PUSH_OUT): P => {
 | 
				
			||||||
 | 
					  const dx = Math.abs(p.x - bounds.x);
 | 
				
			||||||
 | 
					  const dy = Math.abs(p.y - bounds.y);
 | 
				
			||||||
 | 
					  const w = bounds.width / 2;
 | 
				
			||||||
 | 
					  const h = bounds.height / 2;
 | 
				
			||||||
 | 
					  if (Math.abs(dx - w) < EPS || Math.abs(dy - h) < EPS) {
 | 
				
			||||||
 | 
					    const dirX = p.x - bounds.x;
 | 
				
			||||||
 | 
					    const dirY = p.y - bounds.y;
 | 
				
			||||||
 | 
					    const len = Math.sqrt(dirX * dirX + dirY * dirY);
 | 
				
			||||||
 | 
					    if (len > 0) {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        x: bounds.x + (dirX / len) * (len + push),
 | 
				
			||||||
 | 
					        y: bounds.y + (dirY / len) * (len + push),
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return p;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const makeInsidePoint = (bounds: RectLike, outside: P, center: P): P => {
 | 
				
			||||||
 | 
					  const isVertical = Math.abs(outside.x - bounds.x) < EPS;
 | 
				
			||||||
 | 
					  const isHorizontal = Math.abs(outside.y - bounds.y) < EPS;
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    x: isVertical
 | 
				
			||||||
 | 
					      ? outside.x
 | 
				
			||||||
 | 
					      : outside.x < bounds.x
 | 
				
			||||||
 | 
					        ? bounds.x - bounds.width / 4
 | 
				
			||||||
 | 
					        : bounds.x + bounds.width / 4,
 | 
				
			||||||
 | 
					    y: isHorizontal ? outside.y : center.y,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const tryNodeIntersect = (node: NodeLike, bounds: RectLike, outside: P): P | null => {
 | 
				
			||||||
 | 
					  if (!node?.intersect) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const res = node.intersect(outside);
 | 
				
			||||||
 | 
					  if (!res) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const wrongSide =
 | 
				
			||||||
 | 
					    (outside.x < bounds.x && res.x > bounds.x) || (outside.x > bounds.x && res.x < bounds.x);
 | 
				
			||||||
 | 
					  if (wrongSide) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const dist = Math.hypot(outside.x - res.x, outside.y - res.y);
 | 
				
			||||||
 | 
					  if (dist <= EPS) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return res;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fallbackIntersection = (bounds: RectLike, outside: P, center: P): P => {
 | 
				
			||||||
 | 
					  const inside = makeInsidePoint(bounds, outside, center);
 | 
				
			||||||
 | 
					  return intersection(bounds, outside, inside);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const computeNodeIntersection = (
 | 
				
			||||||
 | 
					  node: NodeLike,
 | 
				
			||||||
 | 
					  bounds: RectLike,
 | 
				
			||||||
 | 
					  outside: P,
 | 
				
			||||||
 | 
					  center: P
 | 
				
			||||||
 | 
					): P => {
 | 
				
			||||||
 | 
					  const outside2 = ensureTrulyOutside(bounds, outside);
 | 
				
			||||||
 | 
					  return tryNodeIntersect(node, bounds, outside2) ?? fallbackIntersection(bounds, outside2, center);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const replaceEndpoint = (
 | 
				
			||||||
 | 
					  points: P[],
 | 
				
			||||||
 | 
					  which: 'start' | 'end',
 | 
				
			||||||
 | 
					  value: P | null | undefined,
 | 
				
			||||||
 | 
					  tol = 0.1
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  if (!value || points.length === 0) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (which === 'start') {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      points.length > 0 &&
 | 
				
			||||||
 | 
					      Math.abs(points[0].x - value.x) < tol &&
 | 
				
			||||||
 | 
					      Math.abs(points[0].y - value.y) < tol
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      // duplicate start remove it
 | 
				
			||||||
 | 
					      points.shift();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      points[0] = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    const last = points.length - 1;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      points.length > 0 &&
 | 
				
			||||||
 | 
					      Math.abs(points[last].x - value.x) < tol &&
 | 
				
			||||||
 | 
					      Math.abs(points[last].y - value.y) < tol
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      // duplicate end remove it
 | 
				
			||||||
 | 
					      points.pop();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      points[last] = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -1,11 +1,26 @@
 | 
				
			|||||||
 | 
					import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
 | 
				
			||||||
 | 
					// @ts-ignore TODO: Investigate D3 issue
 | 
				
			||||||
import { curveLinear } from 'd3';
 | 
					import { curveLinear } from 'd3';
 | 
				
			||||||
import ELK from 'elkjs/lib/elk.bundled.js';
 | 
					import ELK from 'elkjs/lib/elk.bundled.js';
 | 
				
			||||||
import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
 | 
					 | 
				
			||||||
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
 | 
					import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  type P,
 | 
				
			||||||
 | 
					  type RectLike,
 | 
				
			||||||
 | 
					  outsideNode,
 | 
				
			||||||
 | 
					  computeNodeIntersection,
 | 
				
			||||||
 | 
					  replaceEndpoint,
 | 
				
			||||||
 | 
					  onBorder,
 | 
				
			||||||
 | 
					} from './geometry.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Node = LayoutData['nodes'][number];
 | 
					type Node = LayoutData['nodes'][number];
 | 
				
			||||||
// Used to calculate distances in order to avoid floating number rounding issues when comparing floating numbers
 | 
					
 | 
				
			||||||
const epsilon = 0.0001;
 | 
					// Minimal structural type to avoid depending on d3 Selection typings
 | 
				
			||||||
 | 
					interface D3Selection<T extends Element> {
 | 
				
			||||||
 | 
					  node(): T | null;
 | 
				
			||||||
 | 
					  attr(name: string, value: string): D3Selection<T>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface LabelData {
 | 
					interface LabelData {
 | 
				
			||||||
  width: number;
 | 
					  width: number;
 | 
				
			||||||
  height: number;
 | 
					  height: number;
 | 
				
			||||||
@@ -16,18 +31,9 @@ interface LabelData {
 | 
				
			|||||||
interface NodeWithVertex extends Omit<Node, 'domId'> {
 | 
					interface NodeWithVertex extends Omit<Node, 'domId'> {
 | 
				
			||||||
  children?: LayoutData['nodes'];
 | 
					  children?: LayoutData['nodes'];
 | 
				
			||||||
  labelData?: LabelData;
 | 
					  labelData?: LabelData;
 | 
				
			||||||
  domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
 | 
					  domId?: D3Selection<SVGAElement | SVGGElement>;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
interface Point {
 | 
					 | 
				
			||||||
  x: number;
 | 
					 | 
				
			||||||
  y: number;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
function distance(p1?: Point, p2?: Point): number {
 | 
					 | 
				
			||||||
  if (!p1 || !p2) {
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const render = async (
 | 
					export const render = async (
 | 
				
			||||||
  data4Layout: LayoutData,
 | 
					  data4Layout: LayoutData,
 | 
				
			||||||
  svg: SVG,
 | 
					  svg: SVG,
 | 
				
			||||||
@@ -61,39 +67,26 @@ export const render = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Add the element to the DOM
 | 
					    // Add the element to the DOM
 | 
				
			||||||
    if (!node.isGroup) {
 | 
					    if (!node.isGroup) {
 | 
				
			||||||
      // Create a clean node object for ELK with only the properties it expects
 | 
					      const child = node as NodeWithVertex;
 | 
				
			||||||
      const child: NodeWithVertex = {
 | 
					 | 
				
			||||||
        id: node.id,
 | 
					 | 
				
			||||||
        width: node.width,
 | 
					 | 
				
			||||||
        height: node.height,
 | 
					 | 
				
			||||||
        // Store the original node data for later use
 | 
					 | 
				
			||||||
        label: node.label,
 | 
					 | 
				
			||||||
        isGroup: node.isGroup,
 | 
					 | 
				
			||||||
        shape: node.shape,
 | 
					 | 
				
			||||||
        padding: node.padding,
 | 
					 | 
				
			||||||
        cssClasses: node.cssClasses,
 | 
					 | 
				
			||||||
        cssStyles: node.cssStyles,
 | 
					 | 
				
			||||||
        look: node.look,
 | 
					 | 
				
			||||||
        // Include parentId for subgraph processing
 | 
					 | 
				
			||||||
        parentId: node.parentId,
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      graph.children.push(child);
 | 
					      graph.children.push(child);
 | 
				
			||||||
      nodeDb[node.id] = child;
 | 
					      nodeDb[node.id] = node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
 | 
					      const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
 | 
				
			||||||
      const boundingBox = childNodeEl.node()!.getBBox();
 | 
					      const boundingBox = childNodeEl.node()!.getBBox();
 | 
				
			||||||
      // Store the domId separately for rendering, not in the ELK graph
 | 
					      // Store the domId separately for rendering, not in the ELK graph
 | 
				
			||||||
      child.domId = childNodeEl;
 | 
					      child.domId = childNodeEl;
 | 
				
			||||||
      child.calcIntersect = node.calcIntersect;
 | 
					 | 
				
			||||||
      child.width = boundingBox.width;
 | 
					      child.width = boundingBox.width;
 | 
				
			||||||
      child.height = boundingBox.height;
 | 
					      child.height = boundingBox.height;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // A subgraph
 | 
					      // A subgraph
 | 
				
			||||||
      const child: NodeWithVertex & { children: NodeWithVertex[] } = {
 | 
					      const child: NodeWithVertex & { children: NodeWithVertex[] } = {
 | 
				
			||||||
        ...node,
 | 
					        ...node,
 | 
				
			||||||
 | 
					        domId: undefined,
 | 
				
			||||||
        children: [],
 | 
					        children: [],
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					      // Let elk render with the copy
 | 
				
			||||||
      graph.children.push(child);
 | 
					      graph.children.push(child);
 | 
				
			||||||
 | 
					      // Save the original containing the intersection function
 | 
				
			||||||
      nodeDb[node.id] = child;
 | 
					      nodeDb[node.id] = child;
 | 
				
			||||||
      await addVertices(nodeEl, nodeArr, child, node.id);
 | 
					      await addVertices(nodeEl, nodeArr, child, node.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -168,7 +161,7 @@ export const render = async (
 | 
				
			|||||||
            height: node.height,
 | 
					            height: node.height,
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          if (node.isGroup) {
 | 
					          if (node.isGroup) {
 | 
				
			||||||
            log.debug('id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
 | 
					            log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
 | 
				
			||||||
            const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
 | 
					            const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
 | 
				
			||||||
            // TODO use faster way of cloning
 | 
					            // TODO use faster way of cloning
 | 
				
			||||||
            const clusterNode = JSON.parse(JSON.stringify(node));
 | 
					            const clusterNode = JSON.parse(JSON.stringify(node));
 | 
				
			||||||
@@ -177,10 +170,10 @@ export const render = async (
 | 
				
			|||||||
            clusterNode.width = Math.max(clusterNode.width, node.labelData.width);
 | 
					            clusterNode.width = Math.max(clusterNode.width, node.labelData.width);
 | 
				
			||||||
            await insertCluster(subgraphEl, clusterNode);
 | 
					            await insertCluster(subgraphEl, clusterNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            log.debug('id (UIO)= ', node.id, node.width, node.shape, node.labels);
 | 
					            log.debug('Id (UIO)= ', node.id, node.width, node.shape, node.labels);
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            log.info(
 | 
					            log.info(
 | 
				
			||||||
              'id NODE = ',
 | 
					              'Id NODE = ',
 | 
				
			||||||
              node.id,
 | 
					              node.id,
 | 
				
			||||||
              node.x,
 | 
					              node.x,
 | 
				
			||||||
              node.y,
 | 
					              node.y,
 | 
				
			||||||
@@ -222,25 +215,19 @@ export const render = async (
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subgraphs.forEach(function (subgraph: { id: string | number }) {
 | 
					 | 
				
			||||||
      const data: any = { id: subgraph.id };
 | 
					 | 
				
			||||||
      if (parentLookupDb.parentById[subgraph.id] !== undefined) {
 | 
					 | 
				
			||||||
        data.parent = parentLookupDb.parentById[subgraph.id];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    return parentLookupDb;
 | 
					    return parentLookupDb;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getEdgeStartEndPoint = (edge: any) => {
 | 
					  const getEdgeStartEndPoint = (edge: any) => {
 | 
				
			||||||
    const source: any = edge.start;
 | 
					    // edge.start and edge.end are IDs (string/number) in our layout data
 | 
				
			||||||
    const target: any = edge.end;
 | 
					    const sourceId: string | number = edge.start;
 | 
				
			||||||
 | 
					    const targetId: string | number = edge.end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Save the original source and target
 | 
					    const source = sourceId;
 | 
				
			||||||
    const sourceId = source;
 | 
					    const target = targetId;
 | 
				
			||||||
    const targetId = target;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const startNode = nodeDb[edge.start.id];
 | 
					    const startNode = nodeDb[sourceId];
 | 
				
			||||||
    const endNode = nodeDb[edge.end.id];
 | 
					    const endNode = nodeDb[targetId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!startNode || !endNode) {
 | 
					    if (!startNode || !endNode) {
 | 
				
			||||||
      return { source, target };
 | 
					      return { source, target };
 | 
				
			||||||
@@ -263,6 +250,112 @@ export const render = async (
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Add edges to graph based on parsed graph definition
 | 
					   * Add edges to graph based on parsed graph definition
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 | 
					  // Edge helper maps and utilities (de-duplicated)
 | 
				
			||||||
 | 
					  const ARROW_MAP: Record<string, [string, string]> = {
 | 
				
			||||||
 | 
					    arrow_open: ['arrow_open', 'arrow_open'],
 | 
				
			||||||
 | 
					    arrow_cross: ['arrow_open', 'arrow_cross'],
 | 
				
			||||||
 | 
					    double_arrow_cross: ['arrow_cross', 'arrow_cross'],
 | 
				
			||||||
 | 
					    arrow_point: ['arrow_open', 'arrow_point'],
 | 
				
			||||||
 | 
					    double_arrow_point: ['arrow_point', 'arrow_point'],
 | 
				
			||||||
 | 
					    arrow_circle: ['arrow_open', 'arrow_circle'],
 | 
				
			||||||
 | 
					    double_arrow_circle: ['arrow_circle', 'arrow_circle'],
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const computeStroke = (
 | 
				
			||||||
 | 
					    stroke: string | undefined,
 | 
				
			||||||
 | 
					    defaultStyle?: string,
 | 
				
			||||||
 | 
					    defaultLabelStyle?: string
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    // Defaults correspond to 'normal'
 | 
				
			||||||
 | 
					    let thickness = 'normal';
 | 
				
			||||||
 | 
					    let pattern = 'solid';
 | 
				
			||||||
 | 
					    let style = '';
 | 
				
			||||||
 | 
					    let labelStyle = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (stroke === 'dotted') {
 | 
				
			||||||
 | 
					      pattern = 'dotted';
 | 
				
			||||||
 | 
					      style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
 | 
				
			||||||
 | 
					    } else if (stroke === 'thick') {
 | 
				
			||||||
 | 
					      thickness = 'thick';
 | 
				
			||||||
 | 
					      style = 'stroke-width: 3.5px;fill:none;';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // normal
 | 
				
			||||||
 | 
					      style = defaultStyle ?? 'fill:none;';
 | 
				
			||||||
 | 
					      if (defaultLabelStyle !== undefined) {
 | 
				
			||||||
 | 
					        labelStyle = defaultLabelStyle;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { thickness, pattern, style, labelStyle };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getCurve = (edgeInterpolate: any, edgesDefaultInterpolate: any, confCurve: any) => {
 | 
				
			||||||
 | 
					    if (edgeInterpolate !== undefined) {
 | 
				
			||||||
 | 
					      return interpolateToCurve(edgeInterpolate, curveLinear);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (edgesDefaultInterpolate !== undefined) {
 | 
				
			||||||
 | 
					      return interpolateToCurve(edgesDefaultInterpolate, curveLinear);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // @ts-ignore TODO: fix this
 | 
				
			||||||
 | 
					    return interpolateToCurve(confCurve, curveLinear);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const buildEdgeData = (
 | 
				
			||||||
 | 
					    edge: any,
 | 
				
			||||||
 | 
					    defaults: {
 | 
				
			||||||
 | 
					      defaultStyle?: string;
 | 
				
			||||||
 | 
					      defaultLabelStyle?: string;
 | 
				
			||||||
 | 
					      defaultInterpolate?: any;
 | 
				
			||||||
 | 
					      confCurve: any;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    common: any
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    const edgeData: any = { style: '', labelStyle: '' };
 | 
				
			||||||
 | 
					    edgeData.minlen = edge.length || 1;
 | 
				
			||||||
 | 
					    // maintain legacy behavior
 | 
				
			||||||
 | 
					    edge.text = edge.label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Arrowhead fill vs none
 | 
				
			||||||
 | 
					    edgeData.arrowhead = edge.type === 'arrow_open' ? 'none' : 'normal';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Arrow types
 | 
				
			||||||
 | 
					    const arrowMap = ARROW_MAP[edge.type] ?? ARROW_MAP.arrow_open;
 | 
				
			||||||
 | 
					    edgeData.arrowTypeStart = arrowMap[0];
 | 
				
			||||||
 | 
					    edgeData.arrowTypeEnd = arrowMap[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Optional edge label positioning flags
 | 
				
			||||||
 | 
					    edgeData.startLabelRight = edge.startLabelRight;
 | 
				
			||||||
 | 
					    edgeData.endLabelLeft = edge.endLabelLeft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Stroke
 | 
				
			||||||
 | 
					    const strokeRes = computeStroke(edge.stroke, defaults.defaultStyle, defaults.defaultLabelStyle);
 | 
				
			||||||
 | 
					    edgeData.thickness = strokeRes.thickness;
 | 
				
			||||||
 | 
					    edgeData.pattern = strokeRes.pattern;
 | 
				
			||||||
 | 
					    edgeData.style = (edgeData.style || '') + (strokeRes.style || '');
 | 
				
			||||||
 | 
					    edgeData.labelStyle = (edgeData.labelStyle || '') + (strokeRes.labelStyle || '');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Curve
 | 
				
			||||||
 | 
					    // @ts-ignore - defaults.confCurve is present at runtime but missing in type
 | 
				
			||||||
 | 
					    edgeData.curve = getCurve(edge.interpolate, defaults.defaultInterpolate, defaults.confCurve);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Arrowhead style + labelpos when we have label text
 | 
				
			||||||
 | 
					    const hasText = (edge?.text ?? '') !== '';
 | 
				
			||||||
 | 
					    if (hasText) {
 | 
				
			||||||
 | 
					      edgeData.arrowheadStyle = 'fill: #333';
 | 
				
			||||||
 | 
					      edgeData.labelpos = 'c';
 | 
				
			||||||
 | 
					    } else if (edge.style !== undefined) {
 | 
				
			||||||
 | 
					      edgeData.arrowheadStyle = 'fill: #333';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    edgeData.labelType = edge.labelType;
 | 
				
			||||||
 | 
					    edgeData.label = (edge?.text ?? '').replace(common.lineBreakRegex, '\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (edge.style === undefined) {
 | 
				
			||||||
 | 
					      edgeData.style = edgeData.style ?? 'stroke: #333; stroke-width: 1.5px;fill:none;';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
 | 
				
			||||||
 | 
					    return edgeData;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const addEdges = async function (
 | 
					  const addEdges = async function (
 | 
				
			||||||
    dataForLayout: { edges: any; direction?: string },
 | 
					    dataForLayout: { edges: any; direction?: string },
 | 
				
			||||||
    graph: {
 | 
					    graph: {
 | 
				
			||||||
@@ -284,7 +377,6 @@ export const render = async (
 | 
				
			|||||||
    const edges = dataForLayout.edges;
 | 
					    const edges = dataForLayout.edges;
 | 
				
			||||||
    const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
 | 
					    const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
 | 
				
			||||||
    const linkIdCnt: any = {};
 | 
					    const linkIdCnt: any = {};
 | 
				
			||||||
    const dir = dataForLayout.direction || 'DOWN';
 | 
					 | 
				
			||||||
    let defaultStyle: string | undefined;
 | 
					    let defaultStyle: string | undefined;
 | 
				
			||||||
    let defaultLabelStyle: string | undefined;
 | 
					    let defaultLabelStyle: string | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -314,105 +406,24 @@ export const render = async (
 | 
				
			|||||||
          linkIdCnt[linkIdBase]++;
 | 
					          linkIdCnt[linkIdBase]++;
 | 
				
			||||||
          log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
 | 
					          log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const linkId = linkIdBase + '_' + linkIdCnt[linkIdBase];
 | 
					        const linkId = linkIdBase; // + '_' + linkIdCnt[linkIdBase];
 | 
				
			||||||
        edge.id = linkId;
 | 
					        edge.id = linkId;
 | 
				
			||||||
        log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
 | 
					        log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
 | 
				
			||||||
        const linkNameStart = 'LS_' + edge.start;
 | 
					        const linkNameStart = 'LS_' + edge.start;
 | 
				
			||||||
        const linkNameEnd = 'LE_' + edge.end;
 | 
					        const linkNameEnd = 'LE_' + edge.end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const edgeData: any = { style: '', labelStyle: '' };
 | 
					 | 
				
			||||||
        edgeData.minlen = edge.length || 1;
 | 
					 | 
				
			||||||
        edge.text = edge.label;
 | 
					 | 
				
			||||||
        // Set link type for rendering
 | 
					 | 
				
			||||||
        if (edge.type === 'arrow_open') {
 | 
					 | 
				
			||||||
          edgeData.arrowhead = 'none';
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          edgeData.arrowhead = 'normal';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check of arrow types, placed here in order not to break old rendering
 | 
					 | 
				
			||||||
        edgeData.arrowTypeStart = 'arrow_open';
 | 
					 | 
				
			||||||
        edgeData.arrowTypeEnd = 'arrow_open';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* eslint-disable no-fallthrough */
 | 
					 | 
				
			||||||
        switch (edge.type) {
 | 
					 | 
				
			||||||
          case 'double_arrow_cross':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeStart = 'arrow_cross';
 | 
					 | 
				
			||||||
          case 'arrow_cross':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeEnd = 'arrow_cross';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
          case 'double_arrow_point':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeStart = 'arrow_point';
 | 
					 | 
				
			||||||
          case 'arrow_point':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeEnd = 'arrow_point';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
          case 'double_arrow_circle':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeStart = 'arrow_circle';
 | 
					 | 
				
			||||||
          case 'arrow_circle':
 | 
					 | 
				
			||||||
            edgeData.arrowTypeEnd = 'arrow_circle';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let style = '';
 | 
					 | 
				
			||||||
        let labelStyle = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        edgeData.startLabelRight = edge.startLabelRight;
 | 
					 | 
				
			||||||
        edgeData.endLabelLeft = edge.endLabelLeft;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch (edge.stroke) {
 | 
					 | 
				
			||||||
          case 'normal':
 | 
					 | 
				
			||||||
            style = 'fill:none;';
 | 
					 | 
				
			||||||
            if (defaultStyle !== undefined) {
 | 
					 | 
				
			||||||
              style = defaultStyle;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (defaultLabelStyle !== undefined) {
 | 
					 | 
				
			||||||
              labelStyle = defaultLabelStyle;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            edgeData.thickness = 'normal';
 | 
					 | 
				
			||||||
            edgeData.pattern = 'solid';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
          case 'dotted':
 | 
					 | 
				
			||||||
            edgeData.thickness = 'normal';
 | 
					 | 
				
			||||||
            edgeData.pattern = 'dotted';
 | 
					 | 
				
			||||||
            edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
          case 'thick':
 | 
					 | 
				
			||||||
            edgeData.thickness = 'thick';
 | 
					 | 
				
			||||||
            edgeData.pattern = 'solid';
 | 
					 | 
				
			||||||
            edgeData.style = 'stroke-width: 3.5px;fill:none;';
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        edgeData.style = edgeData.style += style;
 | 
					 | 
				
			||||||
        edgeData.labelStyle = edgeData.labelStyle += labelStyle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const conf = getConfig();
 | 
					        const conf = getConfig();
 | 
				
			||||||
        if (edge.interpolate !== undefined) {
 | 
					        const edgeData = buildEdgeData(
 | 
				
			||||||
          edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
 | 
					          edge,
 | 
				
			||||||
        } else if (edges.defaultInterpolate !== undefined) {
 | 
					          {
 | 
				
			||||||
          edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
 | 
					            defaultStyle,
 | 
				
			||||||
        } else {
 | 
					            defaultLabelStyle,
 | 
				
			||||||
          // @ts-ignore TODO: fix this
 | 
					            defaultInterpolate: edges.defaultInterpolate,
 | 
				
			||||||
          edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
 | 
					            // @ts-ignore - conf.curve exists at runtime but is missing from typing
 | 
				
			||||||
        }
 | 
					            confCurve: conf.curve,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
        if (edge.text === undefined) {
 | 
					          common
 | 
				
			||||||
          if (edge.style !== undefined) {
 | 
					        );
 | 
				
			||||||
            edgeData.arrowheadStyle = 'fill: #333';
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          edgeData.arrowheadStyle = 'fill: #333';
 | 
					 | 
				
			||||||
          edgeData.labelpos = 'c';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        edgeData.labelType = edge.labelType;
 | 
					 | 
				
			||||||
        edgeData.label = (edge?.text || '').replace(common.lineBreakRegex, '\n');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (edge.style === undefined) {
 | 
					 | 
				
			||||||
          edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        edgeData.id = linkId;
 | 
					        edgeData.id = linkId;
 | 
				
			||||||
        edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
 | 
					        edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
 | 
				
			||||||
@@ -421,13 +432,11 @@ export const render = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // calculate start and end points of the edge, note that the source and target
 | 
					        // calculate start and end points of the edge, note that the source and target
 | 
				
			||||||
        // can be modified for shapes that have ports
 | 
					        // can be modified for shapes that have ports
 | 
				
			||||||
        // @ts-ignore TODO: fix this
 | 
					
 | 
				
			||||||
        const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);
 | 
					        const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge);
 | 
				
			||||||
        log.debug('abc78 source and target', source, target);
 | 
					        log.debug('abc78 source and target', source, target);
 | 
				
			||||||
        // Add the edge to the graph
 | 
					        // Add the edge to the graph
 | 
				
			||||||
        graph.edges.push({
 | 
					        graph.edges.push({
 | 
				
			||||||
          // @ts-ignore TODO: fix this
 | 
					 | 
				
			||||||
          id: 'e' + edge.start + edge.end,
 | 
					 | 
				
			||||||
          ...edge,
 | 
					          ...edge,
 | 
				
			||||||
          sources: [source],
 | 
					          sources: [source],
 | 
				
			||||||
          targets: [target],
 | 
					          targets: [target],
 | 
				
			||||||
@@ -461,6 +470,7 @@ export const render = async (
 | 
				
			|||||||
      case 'RL':
 | 
					      case 'RL':
 | 
				
			||||||
        return 'LEFT';
 | 
					        return 'LEFT';
 | 
				
			||||||
      case 'TB':
 | 
					      case 'TB':
 | 
				
			||||||
 | 
					      case 'TD': // TD is an alias for TB in Mermaid
 | 
				
			||||||
        return 'DOWN';
 | 
					        return 'DOWN';
 | 
				
			||||||
      case 'BT':
 | 
					      case 'BT':
 | 
				
			||||||
        return 'UP';
 | 
					        return 'UP';
 | 
				
			||||||
@@ -484,6 +494,203 @@ export const render = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Node bounds helpers (global)
 | 
				
			||||||
 | 
					  const getEffectiveGroupWidth = (node: any): number => {
 | 
				
			||||||
 | 
					    const labelW = node?.labels?.[0]?.width ?? 0;
 | 
				
			||||||
 | 
					    const padding = node?.padding ?? 0;
 | 
				
			||||||
 | 
					    return Math.max(node.width ?? 0, labelW + padding);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const boundsFor = (node: any): RectLike => {
 | 
				
			||||||
 | 
					    const width = node?.isGroup ? getEffectiveGroupWidth(node) : node.width;
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      x: node.offset.posX + node.width / 2,
 | 
				
			||||||
 | 
					      y: node.offset.posY + node.height / 2,
 | 
				
			||||||
 | 
					      width,
 | 
				
			||||||
 | 
					      height: node.height,
 | 
				
			||||||
 | 
					      padding: node.padding,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  // Helper utilities for endpoint handling around cutter2
 | 
				
			||||||
 | 
					  type Side = 'start' | 'end';
 | 
				
			||||||
 | 
					  const approxEq = (a: number, b: number, eps = 1e-6) => Math.abs(a - b) < eps;
 | 
				
			||||||
 | 
					  const isCenterApprox = (pt: P, node: { x: number; y: number }) =>
 | 
				
			||||||
 | 
					    approxEq(pt.x, node.x) && approxEq(pt.y, node.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getCandidateBorderPoint = (
 | 
				
			||||||
 | 
					    points: P[],
 | 
				
			||||||
 | 
					    node: any,
 | 
				
			||||||
 | 
					    side: Side
 | 
				
			||||||
 | 
					  ): { candidate: P; centerApprox: boolean } => {
 | 
				
			||||||
 | 
					    if (!points?.length) {
 | 
				
			||||||
 | 
					      return { candidate: { x: node.x, y: node.y } as P, centerApprox: true };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (side === 'start') {
 | 
				
			||||||
 | 
					      const first = points[0];
 | 
				
			||||||
 | 
					      const centerApprox = isCenterApprox(first, node);
 | 
				
			||||||
 | 
					      const candidate = centerApprox && points.length > 1 ? points[1] : first;
 | 
				
			||||||
 | 
					      return { candidate, centerApprox };
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const last = points[points.length - 1];
 | 
				
			||||||
 | 
					      const centerApprox = isCenterApprox(last, node);
 | 
				
			||||||
 | 
					      const candidate = centerApprox && points.length > 1 ? points[points.length - 2] : last;
 | 
				
			||||||
 | 
					      return { candidate, centerApprox };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const dropAutoCenterPoint = (points: P[], side: Side, doDrop: boolean) => {
 | 
				
			||||||
 | 
					    if (!doDrop) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (side === 'start') {
 | 
				
			||||||
 | 
					      if (points.length > 0) {
 | 
				
			||||||
 | 
					        points.shift();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      if (points.length > 0) {
 | 
				
			||||||
 | 
					        points.pop();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const applyStartIntersectionIfNeeded = (points: P[], startNode: any, startBounds: RectLike) => {
 | 
				
			||||||
 | 
					    let firstOutsideStartIndex = -1;
 | 
				
			||||||
 | 
					    for (const [i, p] of points.entries()) {
 | 
				
			||||||
 | 
					      if (outsideNode(startBounds, p)) {
 | 
				
			||||||
 | 
					        firstOutsideStartIndex = i;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (firstOutsideStartIndex !== -1) {
 | 
				
			||||||
 | 
					      const outsidePointForStart = points[firstOutsideStartIndex];
 | 
				
			||||||
 | 
					      const startCenter = points[0];
 | 
				
			||||||
 | 
					      const startIntersection = computeNodeIntersection(
 | 
				
			||||||
 | 
					        startNode,
 | 
				
			||||||
 | 
					        startBounds,
 | 
				
			||||||
 | 
					        outsidePointForStart,
 | 
				
			||||||
 | 
					        startCenter
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      replaceEndpoint(points, 'start', startIntersection);
 | 
				
			||||||
 | 
					      log.debug('UIO cutter2: start-only intersection applied', { startIntersection });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const applyEndIntersectionIfNeeded = (points: P[], endNode: any, endBounds: RectLike) => {
 | 
				
			||||||
 | 
					    let outsideIndexForEnd = -1;
 | 
				
			||||||
 | 
					    for (let i = points.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					      if (outsideNode(endBounds, points[i])) {
 | 
				
			||||||
 | 
					        outsideIndexForEnd = i;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (outsideIndexForEnd !== -1) {
 | 
				
			||||||
 | 
					      const outsidePointForEnd = points[outsideIndexForEnd];
 | 
				
			||||||
 | 
					      const endCenter = points[points.length - 1];
 | 
				
			||||||
 | 
					      const endIntersection = computeNodeIntersection(
 | 
				
			||||||
 | 
					        endNode,
 | 
				
			||||||
 | 
					        endBounds,
 | 
				
			||||||
 | 
					        outsidePointForEnd,
 | 
				
			||||||
 | 
					        endCenter
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      replaceEndpoint(points, 'end', endIntersection);
 | 
				
			||||||
 | 
					      log.debug('UIO cutter2: end-only intersection applied', { endIntersection });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const cutter2 = (startNode: any, endNode: any, _points: any[]) => {
 | 
				
			||||||
 | 
					    const startBounds = boundsFor(startNode);
 | 
				
			||||||
 | 
					    const endBounds = boundsFor(endNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (_points.length === 0) {
 | 
				
			||||||
 | 
					      return [];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Copy the original points array
 | 
				
			||||||
 | 
					    const points: P[] = [..._points] as P[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The first point is the center of sNode, the last point is the center of eNode
 | 
				
			||||||
 | 
					    const startCenter = points[0];
 | 
				
			||||||
 | 
					    const endCenter = points[points.length - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Minimal, structured logging for diagnostics
 | 
				
			||||||
 | 
					    log.debug('PPP cutter2: bounds', { startBounds, endBounds });
 | 
				
			||||||
 | 
					    log.debug('PPP cutter2: original points', _points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let firstOutsideStartIndex = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Single iteration through the array
 | 
				
			||||||
 | 
					    for (const [i, point] of points.entries()) {
 | 
				
			||||||
 | 
					      if (firstOutsideStartIndex === -1 && outsideNode(startBounds, point)) {
 | 
				
			||||||
 | 
					        firstOutsideStartIndex = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (outsideNode(endBounds, point)) {
 | 
				
			||||||
 | 
					        // keep scanning; we'll also scan from the end for the last outside point
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Calculate intersection with start node if we found a point outside it
 | 
				
			||||||
 | 
					    if (firstOutsideStartIndex !== -1) {
 | 
				
			||||||
 | 
					      const outsidePointForStart = points[firstOutsideStartIndex];
 | 
				
			||||||
 | 
					      const startIntersection = computeNodeIntersection(
 | 
				
			||||||
 | 
					        startNode,
 | 
				
			||||||
 | 
					        startBounds,
 | 
				
			||||||
 | 
					        outsidePointForStart,
 | 
				
			||||||
 | 
					        startCenter
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      log.debug('UIO cutter2: start intersection', startIntersection);
 | 
				
			||||||
 | 
					      replaceEndpoint(points, 'start', startIntersection);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Calculate intersection with end node
 | 
				
			||||||
 | 
					    let outsidePointForEnd = null;
 | 
				
			||||||
 | 
					    let outsideIndexForEnd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = points.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					      if (outsideNode(endBounds, points[i])) {
 | 
				
			||||||
 | 
					        outsidePointForEnd = points[i];
 | 
				
			||||||
 | 
					        outsideIndexForEnd = i;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!outsidePointForEnd && points.length > 1) {
 | 
				
			||||||
 | 
					      outsidePointForEnd = points[points.length - 2];
 | 
				
			||||||
 | 
					      outsideIndexForEnd = points.length - 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (outsidePointForEnd) {
 | 
				
			||||||
 | 
					      const endIntersection = computeNodeIntersection(
 | 
				
			||||||
 | 
					        endNode,
 | 
				
			||||||
 | 
					        endBounds,
 | 
				
			||||||
 | 
					        outsidePointForEnd,
 | 
				
			||||||
 | 
					        endCenter
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      log.debug('UIO cutter2: end intersection', { endIntersection, outsideIndexForEnd });
 | 
				
			||||||
 | 
					      replaceEndpoint(points, 'end', endIntersection);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Final cleanup: Check if the last point is too close to the previous point
 | 
				
			||||||
 | 
					    if (points.length > 1) {
 | 
				
			||||||
 | 
					      const lastPoint = points[points.length - 1];
 | 
				
			||||||
 | 
					      const secondLastPoint = points[points.length - 2];
 | 
				
			||||||
 | 
					      const distance = Math.sqrt(
 | 
				
			||||||
 | 
					        (lastPoint.x - secondLastPoint.x) ** 2 + (lastPoint.y - secondLastPoint.y) ** 2
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (distance < 2) {
 | 
				
			||||||
 | 
					        log.debug('UIO cutter2: trimming tail point (too close)', {
 | 
				
			||||||
 | 
					          distance,
 | 
				
			||||||
 | 
					          lastPoint,
 | 
				
			||||||
 | 
					          secondLastPoint,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        points.pop();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log.debug('UIO cutter2: final points', points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return points;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // @ts-ignore - ELK is not typed
 | 
					  // @ts-ignore - ELK is not typed
 | 
				
			||||||
  const elk = new ELK();
 | 
					  const elk = new ELK();
 | 
				
			||||||
  const element = svg.select('g');
 | 
					  const element = svg.select('g');
 | 
				
			||||||
@@ -495,17 +702,19 @@ export const render = async (
 | 
				
			|||||||
    id: 'root',
 | 
					    id: 'root',
 | 
				
			||||||
    layoutOptions: {
 | 
					    layoutOptions: {
 | 
				
			||||||
      'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
 | 
					      'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
 | 
				
			||||||
      'elk.layered.crossingMinimization.forceNodeModelOrder':
 | 
					 | 
				
			||||||
        data4Layout.config.elk?.forceNodeModelOrder,
 | 
					 | 
				
			||||||
      'elk.layered.considerModelOrder.strategy': data4Layout.config.elk?.considerModelOrder,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      'elk.algorithm': algorithm,
 | 
					      'elk.algorithm': algorithm,
 | 
				
			||||||
      'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
 | 
					      'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
 | 
				
			||||||
      'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
 | 
					      'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
 | 
				
			||||||
      'elk.direction': 'DOWN',
 | 
					      'elk.direction': 'DOWN',
 | 
				
			||||||
      'spacing.baseValue': 35,
 | 
					      'spacing.baseValue': 40,
 | 
				
			||||||
 | 
					      'elk.layered.crossingMinimization.forceNodeModelOrder':
 | 
				
			||||||
 | 
					        data4Layout.config.elk?.forceNodeModelOrder,
 | 
				
			||||||
 | 
					      'elk.layered.considerModelOrder.strategy': data4Layout.config.elk?.considerModelOrder,
 | 
				
			||||||
      'elk.layered.unnecessaryBendpoints': true,
 | 
					      'elk.layered.unnecessaryBendpoints': true,
 | 
				
			||||||
      'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
 | 
					      'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // 'elk.layered.cycleBreaking.strategy': 'GREEDY_MODEL_ORDER',
 | 
				
			||||||
 | 
					      // 'elk.layered.cycleBreaking.strategy': 'MODEL_ORDER',
 | 
				
			||||||
      // 'spacing.nodeNode': 20,
 | 
					      // 'spacing.nodeNode': 20,
 | 
				
			||||||
      // 'spacing.nodeNodeBetweenLayers': 25,
 | 
					      // 'spacing.nodeNodeBetweenLayers': 25,
 | 
				
			||||||
      // 'spacing.edgeNode': 20,
 | 
					      // 'spacing.edgeNode': 20,
 | 
				
			||||||
@@ -513,22 +722,28 @@ export const render = async (
 | 
				
			|||||||
      // 'spacing.edgeEdge': 10,
 | 
					      // 'spacing.edgeEdge': 10,
 | 
				
			||||||
      // 'spacing.edgeEdgeBetweenLayers': 20,
 | 
					      // 'spacing.edgeEdgeBetweenLayers': 20,
 | 
				
			||||||
      // 'spacing.nodeSelfLoop': 20,
 | 
					      // 'spacing.nodeSelfLoop': 20,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Tweaking options
 | 
					      // Tweaking options
 | 
				
			||||||
 | 
					      // 'nodePlacement.favorStraightEdges': true,
 | 
				
			||||||
      // 'elk.layered.nodePlacement.favorStraightEdges': true,
 | 
					      // 'elk.layered.nodePlacement.favorStraightEdges': true,
 | 
				
			||||||
      // 'nodePlacement.feedbackEdges': true,
 | 
					      // 'nodePlacement.feedbackEdges': true,
 | 
				
			||||||
      // 'elk.layered.wrapping.multiEdge.improveCuts': true,
 | 
					      'elk.layered.wrapping.multiEdge.improveCuts': true,
 | 
				
			||||||
      // 'elk.layered.wrapping.multiEdge.improveWrappedEdges': true,
 | 
					      'elk.layered.wrapping.multiEdge.improveWrappedEdges': true,
 | 
				
			||||||
      // 'elk.layered.wrapping.strategy': 'MULTI_EDGE',
 | 
					      // 'elk.layered.wrapping.strategy': 'MULTI_EDGE',
 | 
				
			||||||
      // 'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',
 | 
					      // 'elk.layered.wrapping.strategy': 'SINGLE_EDGE',
 | 
				
			||||||
      // 'elk.layered.mergeHierarchyEdges': true,
 | 
					      'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',
 | 
				
			||||||
 | 
					      'elk.layered.mergeHierarchyEdges': true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // 'elk.layered.feedbackEdges': true,
 | 
					      // 'elk.layered.feedbackEdges': true,
 | 
				
			||||||
      // 'elk.layered.crossingMinimization.semiInteractive': true,
 | 
					      // 'elk.layered.crossingMinimization.semiInteractive': true,
 | 
				
			||||||
      // 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,
 | 
					      // 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,
 | 
				
			||||||
      // 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,
 | 
					      // 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,
 | 
				
			||||||
      // 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',
 | 
					      // 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',
 | 
				
			||||||
      // 'elk.insideSelfLoops.activate': true,
 | 
					      // 'elk.insideSelfLoops.activate': true,
 | 
				
			||||||
 | 
					      // 'elk.separateConnectedComponents': true,
 | 
				
			||||||
      // 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',
 | 
					      // 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',
 | 
				
			||||||
      // 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES
 | 
					      // 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES
 | 
				
			||||||
 | 
					      // 'elk.layered.considerModelOrder.strategy': 'EDGES', // NODES_AND_EDGES
 | 
				
			||||||
      // 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES
 | 
					      // 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    children: [],
 | 
					    children: [],
 | 
				
			||||||
@@ -538,7 +753,7 @@ export const render = async (
 | 
				
			|||||||
  log.info('Drawing flowchart using v4 renderer', elk);
 | 
					  log.info('Drawing flowchart using v4 renderer', elk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Set the direction of the graph based on the parsed information
 | 
					  // Set the direction of the graph based on the parsed information
 | 
				
			||||||
  const dir = data4Layout.direction || 'DOWN';
 | 
					  const dir = data4Layout.direction ?? 'DOWN';
 | 
				
			||||||
  elkGraph.layoutOptions['elk.direction'] = dir2ElkDirection(dir);
 | 
					  elkGraph.layoutOptions['elk.direction'] = dir2ElkDirection(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create the lookup db for the subgraphs and their children to used when creating
 | 
					  // Create the lookup db for the subgraphs and their children to used when creating
 | 
				
			||||||
@@ -569,15 +784,16 @@ export const render = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Subgraph
 | 
					    // Subgraph
 | 
				
			||||||
    if (parentLookupDb.childrenById[node.id] !== undefined) {
 | 
					    if (parentLookupDb.childrenById[node.id] !== undefined) {
 | 
				
			||||||
 | 
					      // Set label and adjust node width separately (avoid side effects in labels array)
 | 
				
			||||||
      node.labels = [
 | 
					      node.labels = [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          text: node.label,
 | 
					          text: node.label,
 | 
				
			||||||
          width: node?.labelData?.width || 50,
 | 
					          width: node?.labelData?.width ?? 50,
 | 
				
			||||||
          height: node?.labelData?.height || 50,
 | 
					          height: node?.labelData?.height ?? 50,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        (node.width = node.width + 2 * node.padding),
 | 
					 | 
				
			||||||
        log.debug('UIO node label', node?.labelData?.width, node.padding),
 | 
					 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					      node.width = node.width + 2 * node.padding;
 | 
				
			||||||
 | 
					      log.debug('UIO node label', node?.labelData?.width, node.padding);
 | 
				
			||||||
      node.layoutOptions = {
 | 
					      node.layoutOptions = {
 | 
				
			||||||
        'spacing.baseValue': 30,
 | 
					        'spacing.baseValue': 30,
 | 
				
			||||||
        'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
 | 
					        'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
 | 
				
			||||||
@@ -641,7 +857,7 @@ export const render = async (
 | 
				
			|||||||
  try {
 | 
					  try {
 | 
				
			||||||
    g = await elk.layout(elkGraph);
 | 
					    g = await elk.layout(elkGraph);
 | 
				
			||||||
    log.debug('APA01 after - success');
 | 
					    log.debug('APA01 after - success');
 | 
				
			||||||
    log.debug('APA01 layout result:', JSON.stringify(g, null, 2));
 | 
					    log.info('APA01 layout result:', JSON.stringify(g, null, 2));
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    log.error('APA01 ELK layout error:', error);
 | 
					    log.error('APA01 ELK layout error:', error);
 | 
				
			||||||
    throw error;
 | 
					    throw error;
 | 
				
			||||||
@@ -702,10 +918,10 @@ export const render = async (
 | 
				
			|||||||
          // sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);
 | 
					          // sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);
 | 
				
			||||||
          sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);
 | 
					          sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);
 | 
				
			||||||
          // sw = startNode.width;
 | 
					          // sw = startNode.width;
 | 
				
			||||||
          log.debug(
 | 
					          log.info(
 | 
				
			||||||
            'UIO width',
 | 
					            'UIO width',
 | 
				
			||||||
            startNode.id,
 | 
					            startNode.id,
 | 
				
			||||||
            startNode.with,
 | 
					            startNode.width,
 | 
				
			||||||
            'bbox.width=',
 | 
					            'bbox.width=',
 | 
				
			||||||
            bbox.width,
 | 
					            bbox.width,
 | 
				
			||||||
            'lw=',
 | 
					            'lw=',
 | 
				
			||||||
@@ -725,7 +941,7 @@ export const render = async (
 | 
				
			|||||||
          log.debug(
 | 
					          log.debug(
 | 
				
			||||||
            'UIO width',
 | 
					            'UIO width',
 | 
				
			||||||
            startNode.id,
 | 
					            startNode.id,
 | 
				
			||||||
            startNode.with,
 | 
					            startNode.width,
 | 
				
			||||||
            bbox.width,
 | 
					            bbox.width,
 | 
				
			||||||
            'EW = ',
 | 
					            'EW = ',
 | 
				
			||||||
            ew,
 | 
					            ew,
 | 
				
			||||||
@@ -733,38 +949,109 @@ export const render = async (
 | 
				
			|||||||
            startNode.innerHTML
 | 
					            startNode.innerHTML
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        startNode.x = startNode.offset.posX + startNode.width / 2;
 | 
				
			||||||
 | 
					        startNode.y = startNode.offset.posY + startNode.height / 2;
 | 
				
			||||||
 | 
					        endNode.x = endNode.offset.posX + endNode.width / 2;
 | 
				
			||||||
 | 
					        endNode.y = endNode.offset.posY + endNode.height / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (startNode.calcIntersect) {
 | 
					        // Only add center points for non-subgraph nodes or when the edge path doesn't already end near the target
 | 
				
			||||||
          const intersection = startNode.calcIntersect(
 | 
					        const shouldAddStartCenter = startNode.shape !== 'rect33';
 | 
				
			||||||
            {
 | 
					        const shouldAddEndCenter = endNode.shape !== 'rect33';
 | 
				
			||||||
              x: startNode.offset.posX + startNode.width / 2,
 | 
					 | 
				
			||||||
              y: startNode.offset.posY + startNode.height / 2,
 | 
					 | 
				
			||||||
              width: startNode.width,
 | 
					 | 
				
			||||||
              height: startNode.height,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            edge.points[0]
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (distance(intersection, edge.points[0]) > epsilon) {
 | 
					        if (shouldAddStartCenter) {
 | 
				
			||||||
            edge.points.unshift(intersection);
 | 
					          edge.points.unshift({
 | 
				
			||||||
          }
 | 
					            x: startNode.x,
 | 
				
			||||||
        }
 | 
					            y: startNode.y,
 | 
				
			||||||
        if (endNode.calcIntersect) {
 | 
					          });
 | 
				
			||||||
          const intersection = endNode.calcIntersect(
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              x: endNode.offset.posX + endNode.width / 2,
 | 
					 | 
				
			||||||
              y: endNode.offset.posY + endNode.height / 2,
 | 
					 | 
				
			||||||
              width: endNode.width,
 | 
					 | 
				
			||||||
              height: endNode.height,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            edge.points[edge.points.length - 1]
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (distance(intersection, edge.points[edge.points.length - 1]) > epsilon) {
 | 
					 | 
				
			||||||
            edge.points.push(intersection);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (shouldAddEndCenter) {
 | 
				
			||||||
 | 
					          edge.points.push({
 | 
				
			||||||
 | 
					            x: endNode.x,
 | 
				
			||||||
 | 
					            y: endNode.y,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Debug and sanitize points around cutter2
 | 
				
			||||||
 | 
					        const prevPoints = Array.isArray(edge.points) ? [...edge.points] : [];
 | 
				
			||||||
 | 
					        const endBounds = boundsFor(endNode);
 | 
				
			||||||
 | 
					        log.debug(
 | 
				
			||||||
 | 
					          'PPP cutter2: Points before cutter2:',
 | 
				
			||||||
 | 
					          JSON.stringify(edge.points),
 | 
				
			||||||
 | 
					          'endBounds:',
 | 
				
			||||||
 | 
					          endBounds,
 | 
				
			||||||
 | 
					          onBorder(endBounds, edge.points[edge.points.length - 1])
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        // Block for reducing variable scope and guardrails for the cutter function
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          const startBounds = boundsFor(startNode);
 | 
				
			||||||
 | 
					          const endBounds = boundsFor(endNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const startIsGroup = !!startNode?.isGroup;
 | 
				
			||||||
 | 
					          const endIsGroup = !!endNode?.isGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const { candidate: startCandidate, centerApprox: startCenterApprox } =
 | 
				
			||||||
 | 
					            getCandidateBorderPoint(prevPoints as P[], startNode, 'start');
 | 
				
			||||||
 | 
					          const { candidate: endCandidate, centerApprox: endCenterApprox } =
 | 
				
			||||||
 | 
					            getCandidateBorderPoint(prevPoints as P[], endNode, 'end');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const skipStart = startIsGroup && onBorder(startBounds, startCandidate);
 | 
				
			||||||
 | 
					          const skipEnd = endIsGroup && onBorder(endBounds, endCandidate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          dropAutoCenterPoint(prevPoints as P[], 'start', skipStart && startCenterApprox);
 | 
				
			||||||
 | 
					          dropAutoCenterPoint(prevPoints as P[], 'end', skipEnd && endCenterApprox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (skipStart || skipEnd) {
 | 
				
			||||||
 | 
					            if (!skipStart) {
 | 
				
			||||||
 | 
					              applyStartIntersectionIfNeeded(prevPoints as P[], startNode, startBounds);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!skipEnd) {
 | 
				
			||||||
 | 
					              applyEndIntersectionIfNeeded(prevPoints as P[], endNode, endBounds);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            log.debug('PPP cutter2: skipping cutter2 due to on-border group endpoint(s)', {
 | 
				
			||||||
 | 
					              skipStart,
 | 
				
			||||||
 | 
					              skipEnd,
 | 
				
			||||||
 | 
					              startCenterApprox,
 | 
				
			||||||
 | 
					              endCenterApprox,
 | 
				
			||||||
 | 
					              startCandidate,
 | 
				
			||||||
 | 
					              endCandidate,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            edge.points = prevPoints;
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            edge.points = cutter2(startNode, endNode, prevPoints);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        log.debug('PPP cutter2: Points after cutter2:', JSON.stringify(edge.points));
 | 
				
			||||||
 | 
					        const hasNaN = (pts: { x: number; y: number }[]) =>
 | 
				
			||||||
 | 
					          pts?.some((p) => !Number.isFinite(p?.x) || !Number.isFinite(p?.y));
 | 
				
			||||||
 | 
					        if (!Array.isArray(edge.points) || edge.points.length < 2 || hasNaN(edge.points)) {
 | 
				
			||||||
 | 
					          log.warn(
 | 
				
			||||||
 | 
					            'POI cutter2: Invalid points from cutter2, falling back to prevPoints',
 | 
				
			||||||
 | 
					            edge.points
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          // Fallback to previous points and strip any invalid ones just in case
 | 
				
			||||||
 | 
					          const cleaned = prevPoints.filter((p) => Number.isFinite(p?.x) && Number.isFinite(p?.y));
 | 
				
			||||||
 | 
					          edge.points = cleaned.length >= 2 ? cleaned : prevPoints;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        log.debug('UIO cutter2: Points after cutter2 (sanitized):', edge.points);
 | 
				
			||||||
 | 
					        // Remove consecutive duplicate points to avoid zero-length segments in path builders
 | 
				
			||||||
 | 
					        const deduped = edge.points.filter(
 | 
				
			||||||
 | 
					          (p: { x: number; y: number }, i: number, arr: { x: number; y: number }[]) => {
 | 
				
			||||||
 | 
					            if (i === 0) {
 | 
				
			||||||
 | 
					              return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const prev = arr[i - 1];
 | 
				
			||||||
 | 
					            return Math.abs(p.x - prev.x) > 1e-6 || Math.abs(p.y - prev.y) > 1e-6;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if (deduped.length !== edge.points.length) {
 | 
				
			||||||
 | 
					          log.debug('UIO cutter2: removed consecutive duplicate points', {
 | 
				
			||||||
 | 
					            before: edge.points,
 | 
				
			||||||
 | 
					            after: deduped,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        edge.points = deduped;
 | 
				
			||||||
        const paths = insertEdge(
 | 
					        const paths = insertEdge(
 | 
				
			||||||
          edgesEl,
 | 
					          edgesEl,
 | 
				
			||||||
          edge,
 | 
					          edge,
 | 
				
			||||||
@@ -772,8 +1059,10 @@ export const render = async (
 | 
				
			|||||||
          data4Layout.type,
 | 
					          data4Layout.type,
 | 
				
			||||||
          startNode,
 | 
					          startNode,
 | 
				
			||||||
          endNode,
 | 
					          endNode,
 | 
				
			||||||
          data4Layout.diagramId
 | 
					          data4Layout.diagramId,
 | 
				
			||||||
 | 
					          true
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        log.info('APA12 edge points after insert', JSON.stringify(edge.points));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
 | 
					        edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
 | 
				
			||||||
        edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
 | 
					        edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
# @mermaid-js/layout-tidy-tree
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 0.2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Minor Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Patch Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
 | 
					 | 
				
			||||||
  - mermaid@11.11.0
 | 
					 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@mermaid-js/layout-tidy-tree",
 | 
					  "name": "@mermaid-js/layout-tidy-tree",
 | 
				
			||||||
  "version": "0.2.0",
 | 
					  "version": "0.1.0",
 | 
				
			||||||
  "description": "Tidy-tree layout engine for mermaid",
 | 
					  "description": "Tidy-tree layout engine for mermaid",
 | 
				
			||||||
  "module": "dist/mermaid-layout-tidy-tree.core.mjs",
 | 
					  "module": "dist/mermaid-layout-tidy-tree.core.mjs",
 | 
				
			||||||
  "types": "dist/layouts.d.ts",
 | 
					  "types": "dist/layouts.d.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,5 @@
 | 
				
			|||||||
# mermaid
 | 
					# mermaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 11.11.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Minor Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Patch Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 11.10.0
 | 
					## 11.10.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Minor Changes
 | 
					### Minor Changes
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "mermaid",
 | 
					  "name": "mermaid",
 | 
				
			||||||
  "version": "11.11.0",
 | 
					  "version": "11.10.0",
 | 
				
			||||||
  "description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
 | 
					  "description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
 | 
				
			||||||
  "type": "module",
 | 
					  "type": "module",
 | 
				
			||||||
  "module": "./dist/mermaid.core.mjs",
 | 
					  "module": "./dist/mermaid.core.mjs",
 | 
				
			||||||
@@ -82,7 +82,7 @@
 | 
				
			|||||||
    "katex": "^0.16.22",
 | 
					    "katex": "^0.16.22",
 | 
				
			||||||
    "khroma": "^2.1.0",
 | 
					    "khroma": "^2.1.0",
 | 
				
			||||||
    "lodash-es": "^4.17.21",
 | 
					    "lodash-es": "^4.17.21",
 | 
				
			||||||
    "marked": "^15.0.7",
 | 
					    "marked": "^16.0.0",
 | 
				
			||||||
    "roughjs": "^4.6.6",
 | 
					    "roughjs": "^4.6.6",
 | 
				
			||||||
    "stylis": "^4.3.6",
 | 
					    "stylis": "^4.3.6",
 | 
				
			||||||
    "ts-dedent": "^2.2.0",
 | 
					    "ts-dedent": "^2.2.0",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ import type * as d3 from 'd3';
 | 
				
			|||||||
import type { SetOptional, SetRequired } from 'type-fest';
 | 
					import type { SetOptional, SetRequired } from 'type-fest';
 | 
				
			||||||
import type { Diagram } from '../Diagram.js';
 | 
					import type { Diagram } from '../Diagram.js';
 | 
				
			||||||
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
 | 
					import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
 | 
				
			||||||
 | 
					import type { DiagramOrientation } from '../diagrams/git/gitGraphTypes.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface DiagramMetadata {
 | 
					export interface DiagramMetadata {
 | 
				
			||||||
  title?: string;
 | 
					  title?: string;
 | 
				
			||||||
@@ -35,7 +36,8 @@ export interface DiagramDB {
 | 
				
			|||||||
  getAccTitle?: () => string;
 | 
					  getAccTitle?: () => string;
 | 
				
			||||||
  setAccDescription?: (description: string) => void;
 | 
					  setAccDescription?: (description: string) => void;
 | 
				
			||||||
  getAccDescription?: () => string;
 | 
					  getAccDescription?: () => string;
 | 
				
			||||||
 | 
					  getDirection?: () => string | undefined;
 | 
				
			||||||
 | 
					  setDirection?: (dir: DiagramOrientation) => void;
 | 
				
			||||||
  setDisplayMode?: (title: string) => void;
 | 
					  setDisplayMode?: (title: string) => void;
 | 
				
			||||||
  bindFunctions?: (element: Element) => void;
 | 
					  bindFunctions?: (element: Element) => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					import { describe } from 'vitest';
 | 
				
			||||||
 | 
					import { draw } from './architectureRenderer.js';
 | 
				
			||||||
 | 
					import { Diagram } from '../../Diagram.js';
 | 
				
			||||||
 | 
					import { addDetector } from '../../diagram-api/detectType.js';
 | 
				
			||||||
 | 
					import architectureDetector from './architectureDetector.js';
 | 
				
			||||||
 | 
					import { ensureNodeFromSelector, jsdomIt } from '../../tests/util.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { id, detector, loader } = architectureDetector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					addDetector(id, detector, loader); // Add architecture schemas to Mermaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('architecture diagram SVGs', () => {
 | 
				
			||||||
 | 
					  jsdomIt('should add ids', async () => {
 | 
				
			||||||
 | 
					    const svgNode = await drawDiagram(`
 | 
				
			||||||
 | 
					      architecture-beta
 | 
				
			||||||
 | 
					        group api(cloud)[API]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service db(database)[Database] in api
 | 
				
			||||||
 | 
					        service disk1(disk)[Storage] in api
 | 
				
			||||||
 | 
					        service disk2(disk)[Storage] in api
 | 
				
			||||||
 | 
					        service server(server)[Server] in api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db:L -- R:server
 | 
				
			||||||
 | 
					        disk1:T -- B:server
 | 
				
			||||||
 | 
					        disk2:T -- B:db
 | 
				
			||||||
 | 
					    `);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const nodesForGroup = svgNode.querySelectorAll(`#group-api`);
 | 
				
			||||||
 | 
					    expect(nodesForGroup.length).toBe(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const serviceIds = [...svgNode.querySelectorAll(`[id^=service-]`)].map(({ id }) => id).sort();
 | 
				
			||||||
 | 
					    expect(serviceIds).toStrictEqual([
 | 
				
			||||||
 | 
					      'service-db',
 | 
				
			||||||
 | 
					      'service-disk1',
 | 
				
			||||||
 | 
					      'service-disk2',
 | 
				
			||||||
 | 
					      'service-server',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const edgeIds = [...svgNode.querySelectorAll(`.edge[id^=L_]`)].map(({ id }) => id).sort();
 | 
				
			||||||
 | 
					    expect(edgeIds).toStrictEqual(['L_db_server_0', 'L_disk1_server_0', 'L_disk2_db_0']);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function drawDiagram(diagramText: string): Promise<Element> {
 | 
				
			||||||
 | 
					  const diagram = await Diagram.fromText(diagramText, {});
 | 
				
			||||||
 | 
					  await draw('NOT_USED', 'svg', '1.0.0', diagram);
 | 
				
			||||||
 | 
					  return ensureNodeFromSelector('#svg');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -20,6 +20,7 @@ import {
 | 
				
			|||||||
  type ArchitectureJunction,
 | 
					  type ArchitectureJunction,
 | 
				
			||||||
  type ArchitectureService,
 | 
					  type ArchitectureService,
 | 
				
			||||||
} from './architectureTypes.js';
 | 
					} from './architectureTypes.js';
 | 
				
			||||||
 | 
					import { getEdgeId } from '../../utils.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const drawEdges = async function (
 | 
					export const drawEdges = async function (
 | 
				
			||||||
  edgesEl: D3Element,
 | 
					  edgesEl: D3Element,
 | 
				
			||||||
@@ -91,7 +92,8 @@ export const drawEdges = async function (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        g.insert('path')
 | 
					        g.insert('path')
 | 
				
			||||||
          .attr('d', `M ${startX},${startY} L ${midX},${midY} L${endX},${endY} `)
 | 
					          .attr('d', `M ${startX},${startY} L ${midX},${midY} L${endX},${endY} `)
 | 
				
			||||||
          .attr('class', 'edge');
 | 
					          .attr('class', 'edge')
 | 
				
			||||||
 | 
					          .attr('id', getEdgeId(source, target, { prefix: 'L' }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sourceArrow) {
 | 
					        if (sourceArrow) {
 | 
				
			||||||
          const xShift = isArchitectureDirectionX(sourceDir)
 | 
					          const xShift = isArchitectureDirectionX(sourceDir)
 | 
				
			||||||
@@ -206,8 +208,9 @@ export const drawGroups = async function (
 | 
				
			|||||||
      if (data.type === 'group') {
 | 
					      if (data.type === 'group') {
 | 
				
			||||||
        const { h, w, x1, y1 } = node.boundingBox();
 | 
					        const { h, w, x1, y1 } = node.boundingBox();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        groupsEl
 | 
					        const groupsNode = groupsEl.append('rect');
 | 
				
			||||||
          .append('rect')
 | 
					        groupsNode
 | 
				
			||||||
 | 
					          .attr('id', `group-${data.id}`)
 | 
				
			||||||
          .attr('x', x1 + halfIconSize)
 | 
					          .attr('x', x1 + halfIconSize)
 | 
				
			||||||
          .attr('y', y1 + halfIconSize)
 | 
					          .attr('y', y1 + halfIconSize)
 | 
				
			||||||
          .attr('width', w)
 | 
					          .attr('width', w)
 | 
				
			||||||
@@ -262,6 +265,7 @@ export const drawGroups = async function (
 | 
				
			|||||||
              ')'
 | 
					              ')'
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        db.setElementForId(data.id, groupsNode);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
@@ -342,9 +346,9 @@ export const drawServices = async function (
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    serviceElem.attr('class', 'architecture-service');
 | 
					    serviceElem.attr('id', `service-${service.id}`).attr('class', 'architecture-service');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { width, height } = serviceElem._groups[0][0].getBBox();
 | 
					    const { width, height } = serviceElem.node().getBBox();
 | 
				
			||||||
    service.width = width;
 | 
					    service.width = width;
 | 
				
			||||||
    service.height = height;
 | 
					    service.height = height;
 | 
				
			||||||
    db.setElementForId(service.id, serviceElem);
 | 
					    db.setElementForId(service.id, serviceElem);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -268,7 +268,9 @@ const fixTaskDates = function (startTime, endTime, dateFormat, excludes, include
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const getStartDate = function (prevTime, dateFormat, str) {
 | 
					const getStartDate = function (prevTime, dateFormat, str) {
 | 
				
			||||||
  str = str.trim();
 | 
					  str = str.trim();
 | 
				
			||||||
 | 
					  if ((dateFormat.trim() === 'x' || dateFormat.trim() === 'X') && /^\d+$/.test(str)) {
 | 
				
			||||||
 | 
					    return new Date(Number(str));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  // Test for after
 | 
					  // Test for after
 | 
				
			||||||
  const afterRePattern = /^after\s+(?<ids>[\d\w- ]+)/;
 | 
					  const afterRePattern = /^after\s+(?<ids>[\d\w- ]+)/;
 | 
				
			||||||
  const afterStatement = afterRePattern.exec(str);
 | 
					  const afterStatement = afterRePattern.exec(str);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,7 @@ export class MindmapDB {
 | 
				
			|||||||
  private nodes: MindmapNode[] = [];
 | 
					  private nodes: MindmapNode[] = [];
 | 
				
			||||||
  private count = 0;
 | 
					  private count = 0;
 | 
				
			||||||
  private elements: Record<number, D3Element> = {};
 | 
					  private elements: Record<number, D3Element> = {};
 | 
				
			||||||
 | 
					  private baseLevel?: number;
 | 
				
			||||||
  public readonly nodeType: typeof nodeType;
 | 
					  public readonly nodeType: typeof nodeType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor() {
 | 
					  constructor() {
 | 
				
			||||||
@@ -54,6 +55,7 @@ export class MindmapDB {
 | 
				
			|||||||
    this.nodes = [];
 | 
					    this.nodes = [];
 | 
				
			||||||
    this.count = 0;
 | 
					    this.count = 0;
 | 
				
			||||||
    this.elements = {};
 | 
					    this.elements = {};
 | 
				
			||||||
 | 
					    this.baseLevel = undefined;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public getParent(level: number): MindmapNode | null {
 | 
					  public getParent(level: number): MindmapNode | null {
 | 
				
			||||||
@@ -72,6 +74,17 @@ export class MindmapDB {
 | 
				
			|||||||
  public addNode(level: number, id: string, descr: string, type: number): void {
 | 
					  public addNode(level: number, id: string, descr: string, type: number): void {
 | 
				
			||||||
    log.info('addNode', level, id, descr, type);
 | 
					    log.info('addNode', level, id, descr, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let isRoot = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.nodes.length === 0) {
 | 
				
			||||||
 | 
					      this.baseLevel = level;
 | 
				
			||||||
 | 
					      level = 0;
 | 
				
			||||||
 | 
					      isRoot = true;
 | 
				
			||||||
 | 
					    } else if (this.baseLevel !== undefined) {
 | 
				
			||||||
 | 
					      level = level - this.baseLevel;
 | 
				
			||||||
 | 
					      isRoot = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const conf = getConfig();
 | 
					    const conf = getConfig();
 | 
				
			||||||
    let padding = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
 | 
					    let padding = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,6 +105,7 @@ export class MindmapDB {
 | 
				
			|||||||
      children: [],
 | 
					      children: [],
 | 
				
			||||||
      width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
 | 
					      width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
 | 
				
			||||||
      padding,
 | 
					      padding,
 | 
				
			||||||
 | 
					      isRoot,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const parent = this.getParent(level);
 | 
					    const parent = this.getParent(level);
 | 
				
			||||||
@@ -99,7 +113,7 @@ export class MindmapDB {
 | 
				
			|||||||
      parent.children.push(node);
 | 
					      parent.children.push(node);
 | 
				
			||||||
      this.nodes.push(node);
 | 
					      this.nodes.push(node);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      if (this.nodes.length === 0) {
 | 
					      if (isRoot) {
 | 
				
			||||||
        this.nodes.push(node);
 | 
					        this.nodes.push(node);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        throw new Error(
 | 
					        throw new Error(
 | 
				
			||||||
@@ -204,8 +218,7 @@ export class MindmapDB {
 | 
				
			|||||||
    // Build CSS classes for the node
 | 
					    // Build CSS classes for the node
 | 
				
			||||||
    const cssClasses = ['mindmap-node'];
 | 
					    const cssClasses = ['mindmap-node'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add section-specific classes
 | 
					    if (node.isRoot === true) {
 | 
				
			||||||
    if (node.level === 0) {
 | 
					 | 
				
			||||||
      // Root node gets special classes
 | 
					      // Root node gets special classes
 | 
				
			||||||
      cssClasses.push('section-root', 'section--1');
 | 
					      cssClasses.push('section-root', 'section--1');
 | 
				
			||||||
    } else if (node.section !== undefined) {
 | 
					    } else if (node.section !== undefined) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ export interface MindmapNode {
 | 
				
			|||||||
  icon?: string;
 | 
					  icon?: string;
 | 
				
			||||||
  x?: number;
 | 
					  x?: number;
 | 
				
			||||||
  y?: number;
 | 
					  y?: number;
 | 
				
			||||||
 | 
					  isRoot?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type FilledMindMapNode = RequiredDeep<MindmapNode>;
 | 
					export type FilledMindMapNode = RequiredDeep<MindmapNode>;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,13 @@
 | 
				
			|||||||
import mermaid, { type MermaidConfig } from 'mermaid';
 | 
					import mermaid, { type MermaidConfig } from 'mermaid';
 | 
				
			||||||
import zenuml from '../../../../../mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
 | 
					import zenuml from '../../../../../mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
 | 
				
			||||||
 | 
					import tidyTreeLayout from '../../../../../mermaid-layout-tidy-tree/dist/mermaid-layout-tidy-tree.core.mjs';
 | 
				
			||||||
 | 
					import layouts from '../../../../../mermaid-layout-elk/dist/mermaid-layout-elk.core.mjs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const init = mermaid.registerExternalDiagrams([zenuml]);
 | 
					const init = Promise.all([
 | 
				
			||||||
 | 
					  mermaid.registerExternalDiagrams([zenuml]),
 | 
				
			||||||
 | 
					  mermaid.registerLayoutLoaders(layouts),
 | 
				
			||||||
 | 
					  mermaid.registerLayoutLoaders(tidyTreeLayout),
 | 
				
			||||||
 | 
					]);
 | 
				
			||||||
mermaid.registerIconPacks([
 | 
					mermaid.registerIconPacks([
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    name: 'logos',
 | 
					    name: 'logos',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@
 | 
				
			|||||||
    "pathe": "^2.0.3",
 | 
					    "pathe": "^2.0.3",
 | 
				
			||||||
    "unocss": "^66.4.2",
 | 
					    "unocss": "^66.4.2",
 | 
				
			||||||
    "unplugin-vue-components": "^28.4.0",
 | 
					    "unplugin-vue-components": "^28.4.0",
 | 
				
			||||||
    "vite": "^6.1.1",
 | 
					    "vite": "^7.0.0",
 | 
				
			||||||
    "vite-plugin-pwa": "^1.0.0",
 | 
					    "vite-plugin-pwa": "^1.0.0",
 | 
				
			||||||
    "vitepress": "1.6.3",
 | 
					    "vitepress": "1.6.3",
 | 
				
			||||||
    "workbox-window": "^7.3.0"
 | 
					    "workbox-window": "^7.3.0"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,3 +20,5 @@ Each user journey is split into sections, these describe the part of the task
 | 
				
			|||||||
the user is trying to complete.
 | 
					the user is trying to complete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tasks syntax is `Task name: <score>: <comma separated list of actors>`
 | 
					Tasks syntax is `Task name: <score>: <comma separated list of actors>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Score is a number between 1 and 5, inclusive.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,10 @@ const virtualModuleId = 'virtual:mermaid-config';
 | 
				
			|||||||
const resolvedVirtualModuleId = '\0' + virtualModuleId;
 | 
					const resolvedVirtualModuleId = '\0' + virtualModuleId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineConfig({
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  build: {
 | 
				
			||||||
 | 
					    // Vite v7 changes the default target and drops old browser support
 | 
				
			||||||
 | 
					    target: 'modules',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  optimizeDeps: {
 | 
					  optimizeDeps: {
 | 
				
			||||||
    // vitepress is aliased with replacement `join(DIST_CLIENT_PATH, '/index')`
 | 
					    // vitepress is aliased with replacement `join(DIST_CLIENT_PATH, '/index')`
 | 
				
			||||||
    // This needs to be excluded from optimization
 | 
					    // This needs to be excluded from optimization
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,9 @@ import { internalHelpers } from '../internals.js';
 | 
				
			|||||||
import { log } from '../logger.js';
 | 
					import { log } from '../logger.js';
 | 
				
			||||||
import type { LayoutData } from './types.js';
 | 
					import type { LayoutData } from './types.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// console.log('MUST be removed, this only for keeping dev server working');
 | 
				
			||||||
 | 
					// import tmp from './layout-algorithms/dagre/index.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface RenderOptions {
 | 
					export interface RenderOptions {
 | 
				
			||||||
  algorithm?: string;
 | 
					  algorithm?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,13 @@
 | 
				
			|||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
					import { getConfig } from '../../diagram-api/diagramAPI.js';
 | 
				
			||||||
import { evaluate, getUrl } from '../../diagrams/common/common.js';
 | 
					import { evaluate } from '../../diagrams/common/common.js';
 | 
				
			||||||
import { log } from '../../logger.js';
 | 
					import { log } from '../../logger.js';
 | 
				
			||||||
import { createText } from '../createText.js';
 | 
					import { createText } from '../createText.js';
 | 
				
			||||||
import utils from '../../utils.js';
 | 
					import utils from '../../utils.js';
 | 
				
			||||||
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
 | 
					import {
 | 
				
			||||||
 | 
					  getLineFunctionsWithOffset,
 | 
				
			||||||
 | 
					  markerOffsets,
 | 
				
			||||||
 | 
					  markerOffsets2,
 | 
				
			||||||
 | 
					} from '../../utils/lineWithOffset.js';
 | 
				
			||||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
 | 
					import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@@ -25,10 +29,10 @@ import {
 | 
				
			|||||||
import rough from 'roughjs';
 | 
					import rough from 'roughjs';
 | 
				
			||||||
import createLabel from './createLabel.js';
 | 
					import createLabel from './createLabel.js';
 | 
				
			||||||
import { addEdgeMarkers } from './edgeMarker.ts';
 | 
					import { addEdgeMarkers } from './edgeMarker.ts';
 | 
				
			||||||
import { isLabelStyle } from './shapes/handDrawnShapeStyles.js';
 | 
					import { isLabelStyle, styles2String } from './shapes/handDrawnShapeStyles.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const edgeLabels = new Map();
 | 
					export const edgeLabels = new Map();
 | 
				
			||||||
const terminalLabels = new Map();
 | 
					export const terminalLabels = new Map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const clear = () => {
 | 
					export const clear = () => {
 | 
				
			||||||
  edgeLabels.clear();
 | 
					  edgeLabels.clear();
 | 
				
			||||||
@@ -43,8 +47,10 @@ export const getLabelStyles = (styleArray) => {
 | 
				
			|||||||
export const insertEdgeLabel = async (elem, edge) => {
 | 
					export const insertEdgeLabel = async (elem, edge) => {
 | 
				
			||||||
  let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
 | 
					  let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { labelStyles } = styles2String(edge);
 | 
				
			||||||
 | 
					  edge.labelStyle = labelStyles;
 | 
				
			||||||
  const labelElement = await createText(elem, edge.label, {
 | 
					  const labelElement = await createText(elem, edge.label, {
 | 
				
			||||||
    style: getLabelStyles(edge.labelStyle),
 | 
					    style: edge.labelStyle,
 | 
				
			||||||
    useHtmlLabels,
 | 
					    useHtmlLabels,
 | 
				
			||||||
    addSvgBackground: true,
 | 
					    addSvgBackground: true,
 | 
				
			||||||
    isNode: false,
 | 
					    isNode: false,
 | 
				
			||||||
@@ -55,7 +61,7 @@ export const insertEdgeLabel = async (elem, edge) => {
 | 
				
			|||||||
  const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
 | 
					  const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create inner g, label, this will be positioned now for centering the text
 | 
					  // Create inner g, label, this will be positioned now for centering the text
 | 
				
			||||||
  const label = edgeLabel.insert('g').attr('class', 'label');
 | 
					  const label = edgeLabel.insert('g').attr('class', 'label').attr('data-id', edge.id);
 | 
				
			||||||
  label.node().appendChild(labelElement);
 | 
					  label.node().appendChild(labelElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Center the label
 | 
					  // Center the label
 | 
				
			||||||
@@ -438,7 +444,33 @@ const fixCorners = function (lineData) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  return newLineData;
 | 
					  return newLineData;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
 | 
					const generateDashArray = (len, oValueS, oValueE) => {
 | 
				
			||||||
 | 
					  const middleLength = len - oValueS - oValueE;
 | 
				
			||||||
 | 
					  const dashLength = 2; // Length of each dash
 | 
				
			||||||
 | 
					  const gapLength = 2; // Length of each gap
 | 
				
			||||||
 | 
					  const dashGapPairLength = dashLength + gapLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Calculate number of complete dash-gap pairs that can fit
 | 
				
			||||||
 | 
					  const numberOfPairs = Math.floor(middleLength / dashGapPairLength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Generate the middle pattern array
 | 
				
			||||||
 | 
					  const middlePattern = Array(numberOfPairs).fill(`${dashLength} ${gapLength}`).join(' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Combine all parts
 | 
				
			||||||
 | 
					  const dashArray = `0 ${oValueS} ${middlePattern} ${oValueE}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return dashArray;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const insertEdge = function (
 | 
				
			||||||
 | 
					  elem,
 | 
				
			||||||
 | 
					  edge,
 | 
				
			||||||
 | 
					  clusterDb,
 | 
				
			||||||
 | 
					  diagramType,
 | 
				
			||||||
 | 
					  startNode,
 | 
				
			||||||
 | 
					  endNode,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					  skipIntersect = false
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
  const { handDrawnSeed } = getConfig();
 | 
					  const { handDrawnSeed } = getConfig();
 | 
				
			||||||
  let points = edge.points;
 | 
					  let points = edge.points;
 | 
				
			||||||
  let pointsHasChanged = false;
 | 
					  let pointsHasChanged = false;
 | 
				
			||||||
@@ -452,11 +484,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
    edgeClassStyles.push(edge.cssCompiledStyles[key]);
 | 
					    edgeClassStyles.push(edge.cssCompiledStyles[key]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (head.intersect && tail.intersect) {
 | 
					  log.debug('UIO intersect check', edge.points, head.x, tail.x);
 | 
				
			||||||
 | 
					  if (head.intersect && tail.intersect && !skipIntersect) {
 | 
				
			||||||
    points = points.slice(1, edge.points.length - 1);
 | 
					    points = points.slice(1, edge.points.length - 1);
 | 
				
			||||||
    points.unshift(tail.intersect(points[0]));
 | 
					    points.unshift(tail.intersect(points[0]));
 | 
				
			||||||
    log.debug(
 | 
					    log.debug(
 | 
				
			||||||
      'Last point APA12',
 | 
					      'Last point UIO',
 | 
				
			||||||
      edge.start,
 | 
					      edge.start,
 | 
				
			||||||
      '-->',
 | 
					      '-->',
 | 
				
			||||||
      edge.end,
 | 
					      edge.end,
 | 
				
			||||||
@@ -466,6 +499,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
    points.push(head.intersect(points[points.length - 1]));
 | 
					    points.push(head.intersect(points[points.length - 1]));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  const pointsStr = btoa(JSON.stringify(points));
 | 
				
			||||||
  if (edge.toCluster) {
 | 
					  if (edge.toCluster) {
 | 
				
			||||||
    log.info('to cluster abc88', clusterDb.get(edge.toCluster));
 | 
					    log.info('to cluster abc88', clusterDb.get(edge.toCluster));
 | 
				
			||||||
    points = cutPathAtIntersect(edge.points, clusterDb.get(edge.toCluster).node);
 | 
					    points = cutPathAtIntersect(edge.points, clusterDb.get(edge.toCluster).node);
 | 
				
			||||||
@@ -529,6 +563,10 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
      curve = curveBasis;
 | 
					      curve = curveBasis;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // if (edge.curve) {
 | 
				
			||||||
 | 
					  //   curve = edge.curve;
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { x, y } = getLineFunctionsWithOffset(edge);
 | 
					  const { x, y } = getLineFunctionsWithOffset(edge);
 | 
				
			||||||
  const lineFunction = line().x(x).y(y).curve(curve);
 | 
					  const lineFunction = line().x(x).y(y).curve(curve);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -560,10 +598,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
      strokeClasses += ' edge-pattern-solid';
 | 
					      strokeClasses += ' edge-pattern-solid';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  let svgPath;
 | 
					  let svgPath;
 | 
				
			||||||
  let linePath = lineFunction(lineData);
 | 
					  let linePath =
 | 
				
			||||||
  const edgeStyles = Array.isArray(edge.style) ? edge.style : edge.style ? [edge.style] : [];
 | 
					    edge.curve === 'rounded'
 | 
				
			||||||
 | 
					      ? generateRoundedPath(applyMarkerOffsetsToPoints(lineData, edge), 5)
 | 
				
			||||||
 | 
					      : lineFunction(lineData);
 | 
				
			||||||
 | 
					  const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
 | 
				
			||||||
  let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:'));
 | 
					  let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let animatedEdge = false;
 | 
				
			||||||
  if (edge.look === 'handDrawn') {
 | 
					  if (edge.look === 'handDrawn') {
 | 
				
			||||||
    const rc = rough.svg(elem);
 | 
					    const rc = rough.svg(elem);
 | 
				
			||||||
    Object.assign([], lineData);
 | 
					    Object.assign([], lineData);
 | 
				
			||||||
@@ -594,7 +636,10 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
      animationClass = ' edge-animation-' + edge.animation;
 | 
					      animationClass = ' edge-animation-' + edge.animation;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const pathStyle = stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles;
 | 
					    const pathStyle =
 | 
				
			||||||
 | 
					      (stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles) +
 | 
				
			||||||
 | 
					      ';' +
 | 
				
			||||||
 | 
					      (edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '');
 | 
				
			||||||
    svgPath = elem
 | 
					    svgPath = elem
 | 
				
			||||||
      .append('path')
 | 
					      .append('path')
 | 
				
			||||||
      .attr('d', linePath)
 | 
					      .attr('d', linePath)
 | 
				
			||||||
@@ -604,11 +649,39 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
        ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : '') + (animationClass ?? '')
 | 
					        ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : '') + (animationClass ?? '')
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
      .attr('style', pathStyle);
 | 
					      .attr('style', pathStyle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
 | 
				
			||||||
    strokeColor = pathStyle.match(/stroke:([^;]+)/)?.[1];
 | 
					    strokeColor = pathStyle.match(/stroke:([^;]+)/)?.[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Possible fix to remove eslint-disable-next-line
 | 
				
			||||||
 | 
					    //strokeColor = /stroke:([^;]+)/.exec(pathStyle)?.[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animatedEdge =
 | 
				
			||||||
 | 
					      edge.animate === true || !!edge.animation || stylesFromClasses.includes('animation');
 | 
				
			||||||
 | 
					    const pathNode = svgPath.node();
 | 
				
			||||||
 | 
					    const len = typeof pathNode.getTotalLength === 'function' ? pathNode.getTotalLength() : 0;
 | 
				
			||||||
 | 
					    const oValueS = markerOffsets2[edge.arrowTypeStart] || 0;
 | 
				
			||||||
 | 
					    const oValueE = markerOffsets2[edge.arrowTypeEnd] || 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (edge.look === 'neo' && !animatedEdge) {
 | 
				
			||||||
 | 
					      const dashArray =
 | 
				
			||||||
 | 
					        edge.pattern === 'dotted' || edge.pattern === 'dashed'
 | 
				
			||||||
 | 
					          ? generateDashArray(len, oValueS, oValueE)
 | 
				
			||||||
 | 
					          : `0 ${oValueS} ${len - oValueS - oValueE} ${oValueE}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // No offset needed because we already start with a zero-length dash that effectively sets us up for a gap at the start.
 | 
				
			||||||
 | 
					      const mOffset = `stroke-dasharray: ${dashArray}; stroke-dashoffset: 0;`;
 | 
				
			||||||
 | 
					      svgPath.attr('style', mOffset + svgPath.attr('style'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // DEBUG code, DO NOT REMOVE
 | 
					  // MC Special
 | 
				
			||||||
  // adds a red circle at each edge coordinate
 | 
					  svgPath.attr('data-edge', true);
 | 
				
			||||||
 | 
					  svgPath.attr('data-et', 'edge');
 | 
				
			||||||
 | 
					  svgPath.attr('data-id', edge.id);
 | 
				
			||||||
 | 
					  svgPath.attr('data-points', pointsStr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // DEBUG code, adds a red circle at each edge coordinate
 | 
				
			||||||
  // cornerPoints.forEach((point) => {
 | 
					  // cornerPoints.forEach((point) => {
 | 
				
			||||||
  //   elem
 | 
					  //   elem
 | 
				
			||||||
  //     .append('circle')
 | 
					  //     .append('circle')
 | 
				
			||||||
@@ -618,19 +691,27 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
  //     .attr('cx', point.x)
 | 
					  //     .attr('cx', point.x)
 | 
				
			||||||
  //     .attr('cy', point.y);
 | 
					  //     .attr('cy', point.y);
 | 
				
			||||||
  // });
 | 
					  // });
 | 
				
			||||||
  // lineData.forEach((point) => {
 | 
					  if (edge.showPoints) {
 | 
				
			||||||
  //   elem
 | 
					    lineData.forEach((point) => {
 | 
				
			||||||
  //     .append('circle')
 | 
					      elem
 | 
				
			||||||
  //     .style('stroke', 'red')
 | 
					        .append('circle')
 | 
				
			||||||
  //     .style('fill', 'red')
 | 
					        .style('stroke', 'red')
 | 
				
			||||||
  //     .attr('r', 1)
 | 
					        .style('fill', 'red')
 | 
				
			||||||
  //     .attr('cx', point.x)
 | 
					        .attr('r', 1)
 | 
				
			||||||
  //     .attr('cy', point.y);
 | 
					        .attr('cx', point.x)
 | 
				
			||||||
  // });
 | 
					        .attr('cy', point.y);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let url = '';
 | 
					  let url = '';
 | 
				
			||||||
  if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
 | 
					  if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
 | 
				
			||||||
    url = getUrl(true);
 | 
					    url =
 | 
				
			||||||
 | 
					      window.location.protocol +
 | 
				
			||||||
 | 
					      '//' +
 | 
				
			||||||
 | 
					      window.location.host +
 | 
				
			||||||
 | 
					      window.location.pathname +
 | 
				
			||||||
 | 
					      window.location.search;
 | 
				
			||||||
 | 
					    url = url.replace(/\(/g, '\\(').replace(/\)/g, '\\)');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  log.info('arrowTypeStart', edge.arrowTypeStart);
 | 
					  log.info('arrowTypeStart', edge.arrowTypeStart);
 | 
				
			||||||
  log.info('arrowTypeEnd', edge.arrowTypeEnd);
 | 
					  log.info('arrowTypeEnd', edge.arrowTypeEnd);
 | 
				
			||||||
@@ -649,3 +730,134 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
				
			|||||||
  paths.originalPath = edge.points;
 | 
					  paths.originalPath = edge.points;
 | 
				
			||||||
  return paths;
 | 
					  return paths;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generates SVG path data with rounded corners from an array of points.
 | 
				
			||||||
 | 
					 * @param {Array} points - Array of points in the format [{x: Number, y: Number}, ...]
 | 
				
			||||||
 | 
					 * @param {Number} radius - The radius of the rounded corners
 | 
				
			||||||
 | 
					 * @returns {String} - SVG path data string
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function generateRoundedPath(points, radius) {
 | 
				
			||||||
 | 
					  if (points.length < 2) {
 | 
				
			||||||
 | 
					    return '';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let path = '';
 | 
				
			||||||
 | 
					  const size = points.length;
 | 
				
			||||||
 | 
					  const epsilon = 1e-5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					    const currPoint = points[i];
 | 
				
			||||||
 | 
					    const prevPoint = points[i - 1];
 | 
				
			||||||
 | 
					    const nextPoint = points[i + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (i === 0) {
 | 
				
			||||||
 | 
					      // Move to the first point
 | 
				
			||||||
 | 
					      path += `M${currPoint.x},${currPoint.y}`;
 | 
				
			||||||
 | 
					    } else if (i === size - 1) {
 | 
				
			||||||
 | 
					      // Last point, draw a straight line to the final point
 | 
				
			||||||
 | 
					      path += `L${currPoint.x},${currPoint.y}`;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // Calculate vectors for incoming and outgoing segments
 | 
				
			||||||
 | 
					      const dx1 = currPoint.x - prevPoint.x;
 | 
				
			||||||
 | 
					      const dy1 = currPoint.y - prevPoint.y;
 | 
				
			||||||
 | 
					      const dx2 = nextPoint.x - currPoint.x;
 | 
				
			||||||
 | 
					      const dy2 = nextPoint.y - currPoint.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const len1 = Math.hypot(dx1, dy1);
 | 
				
			||||||
 | 
					      const len2 = Math.hypot(dx2, dy2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Prevent division by zero
 | 
				
			||||||
 | 
					      if (len1 < epsilon || len2 < epsilon) {
 | 
				
			||||||
 | 
					        path += `L${currPoint.x},${currPoint.y}`;
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Normalize the vectors
 | 
				
			||||||
 | 
					      const nx1 = dx1 / len1;
 | 
				
			||||||
 | 
					      const ny1 = dy1 / len1;
 | 
				
			||||||
 | 
					      const nx2 = dx2 / len2;
 | 
				
			||||||
 | 
					      const ny2 = dy2 / len2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Calculate the angle between the vectors
 | 
				
			||||||
 | 
					      const dot = nx1 * nx2 + ny1 * ny2;
 | 
				
			||||||
 | 
					      // Clamp the dot product to avoid numerical issues with acos
 | 
				
			||||||
 | 
					      const clampedDot = Math.max(-1, Math.min(1, dot));
 | 
				
			||||||
 | 
					      const angle = Math.acos(clampedDot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Skip rounding if the angle is too small or too close to 180 degrees
 | 
				
			||||||
 | 
					      if (angle < epsilon || Math.abs(Math.PI - angle) < epsilon) {
 | 
				
			||||||
 | 
					        path += `L${currPoint.x},${currPoint.y}`;
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Calculate the distance to offset the control point
 | 
				
			||||||
 | 
					      const cutLen = Math.min(radius / Math.sin(angle / 2), len1 / 2, len2 / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Calculate the start and end points of the curve
 | 
				
			||||||
 | 
					      const startX = currPoint.x - nx1 * cutLen;
 | 
				
			||||||
 | 
					      const startY = currPoint.y - ny1 * cutLen;
 | 
				
			||||||
 | 
					      const endX = currPoint.x + nx2 * cutLen;
 | 
				
			||||||
 | 
					      const endY = currPoint.y + ny2 * cutLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Draw the line to the start of the curve
 | 
				
			||||||
 | 
					      path += `L${startX},${startY}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Draw the quadratic Bezier curve
 | 
				
			||||||
 | 
					      path += `Q${currPoint.x},${currPoint.y} ${endX},${endY}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return path;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// Helper function to calculate delta and angle between two points
 | 
				
			||||||
 | 
					function calculateDeltaAndAngle(point1, point2) {
 | 
				
			||||||
 | 
					  if (!point1 || !point2) {
 | 
				
			||||||
 | 
					    return { angle: 0, deltaX: 0, deltaY: 0 };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const deltaX = point2.x - point1.x;
 | 
				
			||||||
 | 
					  const deltaY = point2.y - point1.y;
 | 
				
			||||||
 | 
					  const angle = Math.atan2(deltaY, deltaX);
 | 
				
			||||||
 | 
					  return { angle, deltaX, deltaY };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to adjust the first and last points of the points array
 | 
				
			||||||
 | 
					function applyMarkerOffsetsToPoints(points, edge) {
 | 
				
			||||||
 | 
					  // Copy the points array to avoid mutating the original data
 | 
				
			||||||
 | 
					  const newPoints = points.map((point) => ({ ...point }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle the first point (start of the edge)
 | 
				
			||||||
 | 
					  if (points.length >= 2 && markerOffsets[edge.arrowTypeStart]) {
 | 
				
			||||||
 | 
					    const offsetValue = markerOffsets[edge.arrowTypeStart];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const point1 = points[0];
 | 
				
			||||||
 | 
					    const point2 = points[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { angle } = calculateDeltaAndAngle(point1, point2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const offsetX = offsetValue * Math.cos(angle);
 | 
				
			||||||
 | 
					    const offsetY = offsetValue * Math.sin(angle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newPoints[0].x = point1.x + offsetX;
 | 
				
			||||||
 | 
					    newPoints[0].y = point1.y + offsetY;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle the last point (end of the edge)
 | 
				
			||||||
 | 
					  const n = points.length;
 | 
				
			||||||
 | 
					  if (n >= 2 && markerOffsets[edge.arrowTypeEnd]) {
 | 
				
			||||||
 | 
					    const offsetValue = markerOffsets[edge.arrowTypeEnd];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const point1 = points[n - 1];
 | 
				
			||||||
 | 
					    const point2 = points[n - 2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { angle } = calculateDeltaAndAngle(point2, point1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const offsetX = offsetValue * Math.cos(angle);
 | 
				
			||||||
 | 
					    const offsetY = offsetValue * Math.sin(angle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newPoints[n - 1].x = point1.x - offsetX;
 | 
				
			||||||
 | 
					    newPoints[n - 1].y = point1.y - offsetY;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return newPoints;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,11 @@ export const compileStyles = (node: Node) => {
 | 
				
			|||||||
  // the array is the styles of node from the classes it is using
 | 
					  // the array is the styles of node from the classes it is using
 | 
				
			||||||
  // node.cssStyles is an array of styles directly set on the node
 | 
					  // node.cssStyles is an array of styles directly set on the node
 | 
				
			||||||
  // concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
 | 
					  // concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
 | 
				
			||||||
  const stylesMap = styles2Map([...(node.cssCompiledStyles || []), ...(node.cssStyles || [])]);
 | 
					  const stylesMap = styles2Map([
 | 
				
			||||||
 | 
					    ...(node.cssCompiledStyles || []),
 | 
				
			||||||
 | 
					    ...(node.cssStyles || []),
 | 
				
			||||||
 | 
					    ...(node.labelStyle || []),
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
  return { stylesMap, stylesArray: [...stylesMap] };
 | 
					  return { stylesMap, stylesArray: [...stylesMap] };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,12 +4,22 @@ import type { EdgeData, Point } from '../types.js';
 | 
				
			|||||||
// under any transparent markers.
 | 
					// under any transparent markers.
 | 
				
			||||||
// The offsets are calculated from the markers' dimensions.
 | 
					// The offsets are calculated from the markers' dimensions.
 | 
				
			||||||
export const markerOffsets = {
 | 
					export const markerOffsets = {
 | 
				
			||||||
  aggregation: 18,
 | 
					  aggregation: 17.25,
 | 
				
			||||||
  extension: 18,
 | 
					  extension: 17.25,
 | 
				
			||||||
  composition: 18,
 | 
					  composition: 17.25,
 | 
				
			||||||
  dependency: 6,
 | 
					  dependency: 6,
 | 
				
			||||||
  lollipop: 13.5,
 | 
					  lollipop: 13.5,
 | 
				
			||||||
  arrow_point: 4,
 | 
					  arrow_point: 4,
 | 
				
			||||||
 | 
					  //arrow_cross: 24,
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// We need to draw the lines a bit shorter to avoid drawing
 | 
				
			||||||
 | 
					// under any transparent markers.
 | 
				
			||||||
 | 
					// The offsets are calculated from the markers' dimensions.
 | 
				
			||||||
 | 
					export const markerOffsets2 = {
 | 
				
			||||||
 | 
					  arrow_point: 9,
 | 
				
			||||||
 | 
					  arrow_cross: 12.5,
 | 
				
			||||||
 | 
					  arrow_circle: 12.5,
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -104,6 +114,7 @@ export const getLineFunctionsWithOffset = (
 | 
				
			|||||||
        adjustment *= DIRECTION === 'right' ? -1 : 1;
 | 
					        adjustment *= DIRECTION === 'right' ? -1 : 1;
 | 
				
			||||||
        offset += adjustment;
 | 
					        offset += adjustment;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return pointTransformer(d).x + offset;
 | 
					      return pointTransformer(d).x + offset;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    y: function (
 | 
					    y: function (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,5 @@
 | 
				
			|||||||
# mermaid
 | 
					# mermaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 11.11.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Minor Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Patch Changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 11.10.0
 | 
					## 11.10.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Minor Changes
 | 
					### Minor Changes
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "@mermaid-js/tiny",
 | 
					  "name": "@mermaid-js/tiny",
 | 
				
			||||||
  "version": "11.11.0",
 | 
					  "version": "11.10.0",
 | 
				
			||||||
  "description": "Tiny version of mermaid",
 | 
					  "description": "Tiny version of mermaid",
 | 
				
			||||||
  "type": "commonjs",
 | 
					  "type": "commonjs",
 | 
				
			||||||
  "main": "./dist/mermaid.tiny.js",
 | 
					  "main": "./dist/mermaid.tiny.js",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2120
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2120
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -11,7 +11,6 @@ pushd packages/mermaid
 | 
				
			|||||||
# Append commit hash to version
 | 
					# Append commit hash to version
 | 
				
			||||||
jq ".version = .version + \"+${COMMIT_REF:0:7}\"" package.json > package.tmp.json
 | 
					jq ".version = .version + \"+${COMMIT_REF:0:7}\"" package.json > package.tmp.json
 | 
				
			||||||
mv package.tmp.json package.json
 | 
					mv package.tmp.json package.json
 | 
				
			||||||
yarn link
 | 
					 | 
				
			||||||
popd
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pnpm run -r clean
 | 
					pnpm run -r clean
 | 
				
			||||||
@@ -26,13 +25,14 @@ cd mermaid-live-editor
 | 
				
			|||||||
git clean -xdf
 | 
					git clean -xdf
 | 
				
			||||||
rm -rf docs/
 | 
					rm -rf docs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# We have to use npm instead of yarn because it causes trouble in netlify
 | 
					# Tells PNPM that mermaid-live-editor is not part of this workspace
 | 
				
			||||||
 | 
					touch pnpm-workspace.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install dependencies
 | 
					# Install dependencies
 | 
				
			||||||
yarn install
 | 
					pnpm install --frozen-lockfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Link local mermaid to live editor
 | 
					# Link local mermaid to live editor
 | 
				
			||||||
yarn link mermaid     
 | 
					pnpm link ../packages/mermaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Force Build the site
 | 
					# Force Build the site
 | 
				
			||||||
yarn run build
 | 
					pnpm run build
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user