mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-04 04:44:08 +01:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
			mermaid@11
			...
			6097-elk-g
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8277579259 | ||
| 
						 | 
					8336d1cf2d | ||
| 
						 | 
					3c93e4640a | ||
| 
						 | 
					0c28593ea5 | ||
| 
						 | 
					33d8b1a78d | ||
| 
						 | 
					1e3ea13323 | ||
| 
						 | 
					4c8c48cde9 | ||
| 
						 | 
					c8e50276e8 | ||
| 
						 | 
					1e6419a63f | 
							
								
								
									
										5
									
								
								.changeset/hungry-guests-drive.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changeset/hungry-guests-drive.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
'@mermaid-js/layout-elk': patch
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fix: Updated offset calculations for diamond shape when handling intersections
 | 
			
		||||
@@ -900,6 +900,153 @@ flowchart LR
 | 
			
		||||
    n7@{ shape: rect}
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-1: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      subgraph S2
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
      D{"Use the editor"}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-2: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
      subgraph s0["APA"]
 | 
			
		||||
      subgraph s8["APA"]
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
        D{"X"}
 | 
			
		||||
        E[Q]
 | 
			
		||||
      end
 | 
			
		||||
      subgraph s3["BAPA"]
 | 
			
		||||
        F[Q]
 | 
			
		||||
        I
 | 
			
		||||
      end
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      I{"X"}
 | 
			
		||||
      end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-3: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
        D{"Use the editor"}
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
      D-->I
 | 
			
		||||
      D-->I
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-4: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
 subgraph s1["Untitled subgraph"]
 | 
			
		||||
        n1["Evaluate"]
 | 
			
		||||
        n2["Option 1"]
 | 
			
		||||
        n3["Option 2"]
 | 
			
		||||
        n4["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
 subgraph s2["Untitled subgraph"]
 | 
			
		||||
        n5["Evaluate"]
 | 
			
		||||
        n6["Option 1"]
 | 
			
		||||
        n7["Option 2"]
 | 
			
		||||
        n8["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
    A["Start"] -- Some text --> B("Continue")
 | 
			
		||||
    B --> C{"Evaluate"}
 | 
			
		||||
    C -- One --> D["Option 1"]
 | 
			
		||||
    C -- Two --> E["Option 2"]
 | 
			
		||||
    C -- Three --> F["fa:fa-car Option 3"]
 | 
			
		||||
    n1 -- One --> n2
 | 
			
		||||
    n1 -- Two --> n3
 | 
			
		||||
    n1 -- Three --> n4
 | 
			
		||||
    n5 -- One --> n6
 | 
			
		||||
    n5 -- Two --> n7
 | 
			
		||||
    n5 -- Three --> n8
 | 
			
		||||
    n1@{ shape: diam}
 | 
			
		||||
    n2@{ shape: rect}
 | 
			
		||||
    n3@{ shape: rect}
 | 
			
		||||
    n4@{ shape: rect}
 | 
			
		||||
    n5@{ shape: diam}
 | 
			
		||||
    n6@{ shape: rect}
 | 
			
		||||
    n7@{ shape: rect}
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('6088-5: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
      it('6088-6: should handle diamond shape intersections', () => {
 | 
			
		||||
        imgSnapshotTest(
 | 
			
		||||
          `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
    subgraph "subbe"
 | 
			
		||||
      A
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
          { flowchart: { titleTopMargin: 0 } }
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -88,33 +88,84 @@
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
 subgraph s1["Untitled subgraph"]
 | 
			
		||||
        n1["Evaluate"]
 | 
			
		||||
        n2["Option 1"]
 | 
			
		||||
        n3["Option 2"]
 | 
			
		||||
        n4["fa:fa-car Option 3"]
 | 
			
		||||
  end
 | 
			
		||||
    n1 -- One --> n2
 | 
			
		||||
    n1 -- Two --> n3
 | 
			
		||||
    n1 -- Three --> n4
 | 
			
		||||
    n5
 | 
			
		||||
    n1@{ shape: diam}
 | 
			
		||||
    n2@{ shape: rect}
 | 
			
		||||
    n3@{ shape: rect}
 | 
			
		||||
    n4@{ shape: rect}
 | 
			
		||||
    A["Start"] -- Some text --> B("Continue")
 | 
			
		||||
    B --> C{"Evaluate"}
 | 
			
		||||
    C -- One --> D["Option 1"]
 | 
			
		||||
    C -- Two --> E["Option 2"]
 | 
			
		||||
    C -- Three --> F["fa:fa-car Option 3"]
 | 
			
		||||
 %% subgraph s1["Untitled subgraph"]
 | 
			
		||||
        C{"Evaluate"}
 | 
			
		||||
 %% end
 | 
			
		||||
 | 
			
		||||
    B --> C
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
%% A ==> B
 | 
			
		||||
%% A2 --> B2
 | 
			
		||||
      D --> I((I the Circle))
 | 
			
		||||
            D --> I
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      subgraph S2
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
      D{"Use the editor"}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I(("fa:fa-code Text"))
 | 
			
		||||
            D --> I
 | 
			
		||||
           D --> E --> I
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
      subgraph s0["APA"]
 | 
			
		||||
      subgraph s8["APA"]
 | 
			
		||||
      subgraph s1["APA"]
 | 
			
		||||
        D{"X"}
 | 
			
		||||
        E[Q]
 | 
			
		||||
      end
 | 
			
		||||
      subgraph s3["BAPA"]
 | 
			
		||||
        F[Q]
 | 
			
		||||
        I
 | 
			
		||||
      end
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
            D --> I
 | 
			
		||||
 | 
			
		||||
      I{"X"}
 | 
			
		||||
      end
 | 
			
		||||
      end
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
      flowchart LR
 | 
			
		||||
      a
 | 
			
		||||
        D{"Use the editor"}
 | 
			
		||||
 | 
			
		||||
      D -- Mermaid js --> I{"fa:fa-code Text"}
 | 
			
		||||
      D-->I
 | 
			
		||||
      D-->I
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
@@ -155,7 +206,7 @@ flowchart LR
 | 
			
		||||
    n8@{ shape: rect}
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
@@ -171,7 +222,7 @@ flowchart LR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
@@ -180,7 +231,19 @@ flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
</pre
 | 
			
		||||
    >
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
    A{A} --> B & C
 | 
			
		||||
    subgraph "subbe"
 | 
			
		||||
      A
 | 
			
		||||
    end
 | 
			
		||||
</pre
 | 
			
		||||
    >
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  layout: elk
 | 
			
		||||
@@ -198,7 +261,7 @@ flowchart LR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  kanban:
 | 
			
		||||
@@ -217,81 +280,81 @@ kanban
 | 
			
		||||
    task3[💻 Develop login feature]@{ ticket: 103 }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
			
		||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
 | 
			
		||||
A:::AClass
 | 
			
		||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
			
		||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
 | 
			
		||||
A:::AClass
 | 
			
		||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
			
		||||
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
			
		||||
style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
 | 
			
		||||
A:::AClass
 | 
			
		||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
  nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
			
		||||
  A:::AClass
 | 
			
		||||
  classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
flowchart LR
 | 
			
		||||
  nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
 | 
			
		||||
  style A fill:#f9f,stroke:#333,stroke-width:4px
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
kanban
 | 
			
		||||
  id2[In progress]
 | 
			
		||||
    docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
 | 
			
		||||
    </pre>
 | 
			
		||||
    <pre id="diagram4" class="mermaid2">
 | 
			
		||||
    <pre id="diagram4" class="mermaid">
 | 
			
		||||
---
 | 
			
		||||
config:
 | 
			
		||||
  kanban:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								cypress/platform/shape-tester.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								cypress/platform/shape-tester.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
<html>
 | 
			
		||||
  <head>
 | 
			
		||||
    <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
 | 
			
		||||
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
 | 
			
		||||
    <link
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
 | 
			
		||||
      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=Kalam:wght@300;400;700&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
 | 
			
		||||
    <style>
 | 
			
		||||
      body {
 | 
			
		||||
        font-family: 'Arial';
 | 
			
		||||
        background-color: #333;
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="diagram"></div>
 | 
			
		||||
    <script type="module">
 | 
			
		||||
      import mermaid from './mermaid.esm.mjs';
 | 
			
		||||
      import layouts from './mermaid-layout-elk.esm.mjs';
 | 
			
		||||
      mermaid.registerLayoutLoaders(layouts);
 | 
			
		||||
      mermaid.parseError = function (err, hash) {
 | 
			
		||||
        console.error('Mermaid error: ', err);
 | 
			
		||||
      };
 | 
			
		||||
      mermaid.initialize({
 | 
			
		||||
        startOnLoad: false,
 | 
			
		||||
        //look: 'handdrawn',
 | 
			
		||||
        // layout: 'fixed',
 | 
			
		||||
        theme: 'dark',
 | 
			
		||||
        //layout: 'elk',
 | 
			
		||||
        fontFamily: 'Kalam',
 | 
			
		||||
        logLevel: 1,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      let shape = 'card';
 | 
			
		||||
      // let simplified = true;
 | 
			
		||||
      let simplified = false;
 | 
			
		||||
      let algorithm = 'elk';
 | 
			
		||||
      // let algorithm = 'dagre';
 | 
			
		||||
      let code = `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: ${algorithm}
 | 
			
		||||
---
 | 
			
		||||
flowchart TD
 | 
			
		||||
A["Abrakadabra"] --> C["C"] & D["I am a circle"] & n4["Untitled Node"]
 | 
			
		||||
D@{ shape: diamond}
 | 
			
		||||
    B["Bombrakadombra"] --> D & C & D
 | 
			
		||||
    C --> E["E"] & B
 | 
			
		||||
    D --> E & A
 | 
			
		||||
    n4 --> C
 | 
			
		||||
    A@{ shape: ${shape}}
 | 
			
		||||
    B@{ shape: ${shape}}
 | 
			
		||||
    C@{ shape: ${shape}}
 | 
			
		||||
    D@{ shape: ${shape}}
 | 
			
		||||
    E@{ shape: ${shape}}
 | 
			
		||||
    n4@{ shape: ${shape}}
 | 
			
		||||
 | 
			
		||||
          `;
 | 
			
		||||
      if (simplified) {
 | 
			
		||||
        code = `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: ${algorithm}
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
A["Abrakadabra"] --> C["C"] & C & C & C & C
 | 
			
		||||
%% A["Abrakadabra"] --> C
 | 
			
		||||
    A@{ shape: ${shape}}
 | 
			
		||||
    C@{ shape: ${shape}}
 | 
			
		||||
 | 
			
		||||
          `;
 | 
			
		||||
      }
 | 
			
		||||
      console.log(code);
 | 
			
		||||
      const { svg } = await mermaid.render('the-id-of-the-svg', code, undefined, undefined);
 | 
			
		||||
      const elem = document.querySelector('#diagram');
 | 
			
		||||
      elem.innerHTML = svg;
 | 
			
		||||
    </script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -4,7 +4,8 @@ import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from '
 | 
			
		||||
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
interface LabelData {
 | 
			
		||||
  width: number;
 | 
			
		||||
  height: number;
 | 
			
		||||
@@ -17,7 +18,16 @@ interface NodeWithVertex extends Omit<Node, 'domId'> {
 | 
			
		||||
  labelData?: LabelData;
 | 
			
		||||
  domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 (
 | 
			
		||||
  data4Layout: LayoutData,
 | 
			
		||||
  svg: SVG,
 | 
			
		||||
@@ -60,6 +70,7 @@ export const render = async (
 | 
			
		||||
      const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
 | 
			
		||||
      const boundingBox = childNodeEl.node()!.getBBox();
 | 
			
		||||
      child.domId = childNodeEl;
 | 
			
		||||
      child.calcIntersect = node.calcIntersect;
 | 
			
		||||
      child.width = boundingBox.width;
 | 
			
		||||
      child.height = boundingBox.height;
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -459,305 +470,6 @@ export const render = async (
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function intersectLine(
 | 
			
		||||
    p1: { y: number; x: number },
 | 
			
		||||
    p2: { y: number; x: number },
 | 
			
		||||
    q1: { x: any; y: any },
 | 
			
		||||
    q2: { x: any; y: any }
 | 
			
		||||
  ) {
 | 
			
		||||
    log.debug('UIO intersectLine', p1, p2, q1, q2);
 | 
			
		||||
    // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
 | 
			
		||||
    // p7 and p473.
 | 
			
		||||
 | 
			
		||||
    // let a1, a2, b1, b2, c1, c2;
 | 
			
		||||
    // let r1, r2, r3, r4;
 | 
			
		||||
    // let denom, offset, num;
 | 
			
		||||
    // let x, y;
 | 
			
		||||
 | 
			
		||||
    // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
 | 
			
		||||
    // b1 y + c1 = 0.
 | 
			
		||||
    const a1 = p2.y - p1.y;
 | 
			
		||||
    const b1 = p1.x - p2.x;
 | 
			
		||||
    const c1 = p2.x * p1.y - p1.x * p2.y;
 | 
			
		||||
 | 
			
		||||
    // Compute r3 and r4.
 | 
			
		||||
    const r3 = a1 * q1.x + b1 * q1.y + c1;
 | 
			
		||||
    const r4 = a1 * q2.x + b1 * q2.y + c1;
 | 
			
		||||
 | 
			
		||||
    const epsilon = 1e-6;
 | 
			
		||||
 | 
			
		||||
    // Check signs of r3 and r4. If both point 3 and point 4 lie on
 | 
			
		||||
    // same side of line 1, the line segments do not intersect.
 | 
			
		||||
    if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
 | 
			
		||||
      return /*DON'T_INTERSECT*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
 | 
			
		||||
    const a2 = q2.y - q1.y;
 | 
			
		||||
    const b2 = q1.x - q2.x;
 | 
			
		||||
    const c2 = q2.x * q1.y - q1.x * q2.y;
 | 
			
		||||
 | 
			
		||||
    // Compute r1 and r2
 | 
			
		||||
    const r1 = a2 * p1.x + b2 * p1.y + c2;
 | 
			
		||||
    const r2 = a2 * p2.x + b2 * p2.y + c2;
 | 
			
		||||
 | 
			
		||||
    // Check signs of r1 and r2. If both point 1 and point 2 lie
 | 
			
		||||
    // on same side of second line segment, the line segments do
 | 
			
		||||
    // not intersect.
 | 
			
		||||
    if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
 | 
			
		||||
      return /*DON'T_INTERSECT*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Line segments intersect: compute intersection point.
 | 
			
		||||
    const denom = a1 * b2 - a2 * b1;
 | 
			
		||||
    if (denom === 0) {
 | 
			
		||||
      return /*COLLINEAR*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const offset = Math.abs(denom / 2);
 | 
			
		||||
 | 
			
		||||
    // The denom/2 is to get rounding instead of truncating. It
 | 
			
		||||
    // is added or subtracted to the numerator, depending upon the
 | 
			
		||||
    // sign of the numerator.
 | 
			
		||||
    let num = b1 * c2 - b2 * c1;
 | 
			
		||||
    const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
 | 
			
		||||
    num = a2 * c1 - a1 * c2;
 | 
			
		||||
    const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
 | 
			
		||||
    return { x: x, y: y };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sameSign(r1: number, r2: number) {
 | 
			
		||||
    return r1 * r2 > 0;
 | 
			
		||||
  }
 | 
			
		||||
  const diamondIntersection = (
 | 
			
		||||
    bounds: { x: any; y: any; width: any; height: any },
 | 
			
		||||
    outsidePoint: { x: number; y: number },
 | 
			
		||||
    insidePoint: any
 | 
			
		||||
  ) => {
 | 
			
		||||
    const x1 = bounds.x;
 | 
			
		||||
    const y1 = bounds.y;
 | 
			
		||||
 | 
			
		||||
    const w = bounds.width; //+ bounds.padding;
 | 
			
		||||
    const h = bounds.height; // + bounds.padding;
 | 
			
		||||
 | 
			
		||||
    const polyPoints = [
 | 
			
		||||
      { x: x1, y: y1 - h / 2 },
 | 
			
		||||
      { x: x1 + w / 2, y: y1 },
 | 
			
		||||
      { x: x1, y: y1 + h / 2 },
 | 
			
		||||
      { x: x1 - w / 2, y: y1 },
 | 
			
		||||
    ];
 | 
			
		||||
    log.debug(
 | 
			
		||||
      `APA16 diamondIntersection calc abc89:
 | 
			
		||||
  outsidePoint: ${JSON.stringify(outsidePoint)}
 | 
			
		||||
  insidePoint : ${JSON.stringify(insidePoint)}
 | 
			
		||||
  node-bounds       : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
 | 
			
		||||
      JSON.stringify(polyPoints)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const intersections = [];
 | 
			
		||||
 | 
			
		||||
    let minX = Number.POSITIVE_INFINITY;
 | 
			
		||||
    let minY = Number.POSITIVE_INFINITY;
 | 
			
		||||
 | 
			
		||||
    polyPoints.forEach(function (entry) {
 | 
			
		||||
      minX = Math.min(minX, entry.x);
 | 
			
		||||
      minY = Math.min(minY, entry.y);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const left = x1 - w / 2 - minX;
 | 
			
		||||
    const top = y1 - h / 2 - minY;
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < polyPoints.length; i++) {
 | 
			
		||||
      const p1 = polyPoints[i];
 | 
			
		||||
      const p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
 | 
			
		||||
      const intersect = intersectLine(
 | 
			
		||||
        bounds,
 | 
			
		||||
        outsidePoint,
 | 
			
		||||
        { x: left + p1.x, y: top + p1.y },
 | 
			
		||||
        { x: left + p2.x, y: top + p2.y }
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (intersect) {
 | 
			
		||||
        intersections.push(intersect);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!intersections.length) {
 | 
			
		||||
      return bounds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log.debug('UIO intersections', intersections);
 | 
			
		||||
 | 
			
		||||
    if (intersections.length > 1) {
 | 
			
		||||
      // More intersections, find the one nearest to edge end point
 | 
			
		||||
      intersections.sort(function (p, q) {
 | 
			
		||||
        const pdx = p.x - outsidePoint.x;
 | 
			
		||||
        const pdy = p.y - outsidePoint.y;
 | 
			
		||||
        const distp = Math.sqrt(pdx * pdx + pdy * pdy);
 | 
			
		||||
 | 
			
		||||
        const qdx = q.x - outsidePoint.x;
 | 
			
		||||
        const qdy = q.y - outsidePoint.y;
 | 
			
		||||
        const distq = Math.sqrt(qdx * qdx + qdy * qdy);
 | 
			
		||||
 | 
			
		||||
        return distp < distq ? -1 : distp === distq ? 0 : 1;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return intersections[0];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const intersection = (
 | 
			
		||||
    node: { x: any; y: any; width: number; height: number },
 | 
			
		||||
    outsidePoint: { x: number; y: number },
 | 
			
		||||
    insidePoint: { x: number; y: number }
 | 
			
		||||
  ) => {
 | 
			
		||||
    log.debug(`intersection calc abc89:
 | 
			
		||||
  outsidePoint: ${JSON.stringify(outsidePoint)}
 | 
			
		||||
  insidePoint : ${JSON.stringify(insidePoint)}
 | 
			
		||||
  node        : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
 | 
			
		||||
    const x = node.x;
 | 
			
		||||
    const y = node.y;
 | 
			
		||||
 | 
			
		||||
    const dx = Math.abs(x - insidePoint.x);
 | 
			
		||||
    // const dy = Math.abs(y - insidePoint.y);
 | 
			
		||||
    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,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (r === 0) {
 | 
			
		||||
        res.x = outsidePoint.x;
 | 
			
		||||
        res.y = outsidePoint.y;
 | 
			
		||||
      }
 | 
			
		||||
      if (R === 0) {
 | 
			
		||||
        res.x = outsidePoint.x;
 | 
			
		||||
      }
 | 
			
		||||
      if (Q === 0) {
 | 
			
		||||
        res.y = outsidePoint.y;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); // cspell: disable-line
 | 
			
		||||
 | 
			
		||||
      return res;
 | 
			
		||||
    } else {
 | 
			
		||||
      // Intersection onn sides of rect
 | 
			
		||||
      if (insidePoint.x < outsidePoint.x) {
 | 
			
		||||
        r = outsidePoint.x - w - x;
 | 
			
		||||
      } else {
 | 
			
		||||
        // r = outsidePoint.x - w - x;
 | 
			
		||||
        r = x - w - outsidePoint.x;
 | 
			
		||||
      }
 | 
			
		||||
      const q = (Q * r) / R;
 | 
			
		||||
      //  OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;
 | 
			
		||||
      // OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
 | 
			
		||||
      let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
 | 
			
		||||
      // let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
 | 
			
		||||
      let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
 | 
			
		||||
      log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
 | 
			
		||||
      if (r === 0) {
 | 
			
		||||
        _x = outsidePoint.x;
 | 
			
		||||
        _y = outsidePoint.y;
 | 
			
		||||
      }
 | 
			
		||||
      if (R === 0) {
 | 
			
		||||
        _x = outsidePoint.x;
 | 
			
		||||
      }
 | 
			
		||||
      if (Q === 0) {
 | 
			
		||||
        _y = outsidePoint.y;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return { x: _x, y: _y };
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  const outsideNode = (
 | 
			
		||||
    node: { x: any; y: any; width: number; height: number },
 | 
			
		||||
    point: { x: number; y: number }
 | 
			
		||||
  ) => {
 | 
			
		||||
    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;
 | 
			
		||||
    if (dx >= w || dy >= h) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  };
 | 
			
		||||
  /**
 | 
			
		||||
   * This function will page a path and node where the last point(s) in the path is inside the node
 | 
			
		||||
   * and return an update path ending by the border of the node.
 | 
			
		||||
   */
 | 
			
		||||
  const cutPathAtIntersect = (
 | 
			
		||||
    _points: any[],
 | 
			
		||||
    bounds: { x: any; y: any; width: any; height: any; padding: any },
 | 
			
		||||
    isDiamond: boolean
 | 
			
		||||
  ) => {
 | 
			
		||||
    log.debug('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
 | 
			
		||||
    const points: any[] = [];
 | 
			
		||||
    let lastPointOutside = _points[0];
 | 
			
		||||
    let isInside = false;
 | 
			
		||||
    _points.forEach((point: any) => {
 | 
			
		||||
      // const node = clusterDb[edge.toCluster].node;
 | 
			
		||||
      log.debug(' checking point', point, bounds);
 | 
			
		||||
 | 
			
		||||
      // check if point is inside the boundary rect
 | 
			
		||||
      if (!outsideNode(bounds, point) && !isInside) {
 | 
			
		||||
        // First point inside the rect found
 | 
			
		||||
        // Calc the intersection coord between the point anf the last point outside the rect
 | 
			
		||||
        let inter;
 | 
			
		||||
 | 
			
		||||
        if (isDiamond) {
 | 
			
		||||
          const inter2 = diamondIntersection(bounds, lastPointOutside, point);
 | 
			
		||||
          const distance = Math.sqrt(
 | 
			
		||||
            (lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
 | 
			
		||||
          );
 | 
			
		||||
          if (distance > 1) {
 | 
			
		||||
            inter = inter2;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (!inter) {
 | 
			
		||||
          inter = intersection(bounds, lastPointOutside, point);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check case where the intersection is the same as the last point
 | 
			
		||||
        let pointPresent = false;
 | 
			
		||||
        points.forEach((p) => {
 | 
			
		||||
          pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
 | 
			
		||||
        });
 | 
			
		||||
        // if (!pointPresent) {
 | 
			
		||||
        if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
 | 
			
		||||
          points.push(inter);
 | 
			
		||||
        } else {
 | 
			
		||||
          log.debug('abc88 no intersect', inter, points);
 | 
			
		||||
        }
 | 
			
		||||
        // points.push(inter);
 | 
			
		||||
        isInside = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        // Outside
 | 
			
		||||
        log.debug('abc88 outside', point, lastPointOutside, points);
 | 
			
		||||
        lastPointOutside = point;
 | 
			
		||||
        // points.push(point);
 | 
			
		||||
        if (!isInside) {
 | 
			
		||||
          points.push(point);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    return points;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // @ts-ignore - ELK is not typed
 | 
			
		||||
  const elk = new ELK();
 | 
			
		||||
  const element = svg.select('g');
 | 
			
		||||
@@ -880,9 +592,10 @@ export const render = async (
 | 
			
		||||
      setIncludeChildrenPolicy(target, ancestorId);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // const copy = JSON.parse(JSON.stringify({ ...elkGraph }));
 | 
			
		||||
  // console.log('APA13 layout before', copy);
 | 
			
		||||
  const g = await elk.layout(elkGraph);
 | 
			
		||||
 | 
			
		||||
  // console.log('APA13 layout', JSON.parse(JSON.stringify(g)));
 | 
			
		||||
  // debugger;
 | 
			
		||||
  await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
 | 
			
		||||
  g.edges?.map(
 | 
			
		||||
@@ -906,7 +619,7 @@ export const render = async (
 | 
			
		||||
 | 
			
		||||
      const offset = calcOffset(sourceId, targetId, parentLookupDb);
 | 
			
		||||
      log.debug(
 | 
			
		||||
        'offset',
 | 
			
		||||
        'APA18 offset',
 | 
			
		||||
        offset,
 | 
			
		||||
        sourceId,
 | 
			
		||||
        ' ==> ',
 | 
			
		||||
@@ -969,49 +682,58 @@ export const render = async (
 | 
			
		||||
            startNode.innerHTML
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
        if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
 | 
			
		||||
          edge.points.unshift({
 | 
			
		||||
            x: startNode.x + startNode.width / 2 + offset.x,
 | 
			
		||||
            y: startNode.y + startNode.height / 2 + offset.y,
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
 | 
			
		||||
          const x = endNode.x + endNode.width / 2 + offset.x;
 | 
			
		||||
          // Add a point at the center of the diamond
 | 
			
		||||
          if (
 | 
			
		||||
            Math.abs(edge.points[edge.points.length - 1].y - endNode.y - offset.y) > 0.01 ||
 | 
			
		||||
            Math.abs(edge.points[edge.points.length - 1].x - x) > 0.001
 | 
			
		||||
          ) {
 | 
			
		||||
            edge.points.push({
 | 
			
		||||
              x: endNode.x + endNode.width / 2 + offset.x,
 | 
			
		||||
              y: endNode.y + endNode.height / 2 + offset.y,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (startNode.calcIntersect) {
 | 
			
		||||
          // console.log(
 | 
			
		||||
          //   'APA13 calculating start intersection start node',
 | 
			
		||||
          //   startNode.id,
 | 
			
		||||
          //   startNode.x,
 | 
			
		||||
          //   startNode.y,
 | 
			
		||||
          //   'w:',
 | 
			
		||||
          //   startNode.width,
 | 
			
		||||
          //   'h:',
 | 
			
		||||
          //   startNode.height,
 | 
			
		||||
          //   '\nPos',
 | 
			
		||||
          //   edge.points[0]
 | 
			
		||||
          // );
 | 
			
		||||
          const intersection = startNode.calcIntersect(
 | 
			
		||||
            {
 | 
			
		||||
              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) {
 | 
			
		||||
            edge.points.unshift(intersection);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        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 (edge.id === 'L_n4_C_10_0') {
 | 
			
		||||
          // console.log('APA14 lineData', edge.points, 'intersection:', intersection);
 | 
			
		||||
          // console.log(
 | 
			
		||||
          //   'APA14! calculating end intersection\ndistance:',
 | 
			
		||||
          //   distance(intersection, edge.points[edge.points.length - 1])
 | 
			
		||||
          // );
 | 
			
		||||
          // }
 | 
			
		||||
 | 
			
		||||
        edge.points = cutPathAtIntersect(
 | 
			
		||||
          edge.points.reverse(),
 | 
			
		||||
          {
 | 
			
		||||
            x: startNode.x + startNode.width / 2 + offset.x,
 | 
			
		||||
            y: startNode.y + startNode.height / 2 + offset.y,
 | 
			
		||||
            width: sw,
 | 
			
		||||
            height: startNode.height,
 | 
			
		||||
            padding: startNode.padding,
 | 
			
		||||
          },
 | 
			
		||||
          startNode.shape === 'diamond' || startNode.shape === 'diam'
 | 
			
		||||
        ).reverse();
 | 
			
		||||
 | 
			
		||||
        edge.points = cutPathAtIntersect(
 | 
			
		||||
          edge.points,
 | 
			
		||||
          {
 | 
			
		||||
            x: endNode.x + ew / 2 + endNode.offset.x,
 | 
			
		||||
            y: endNode.y + endNode.height / 2 + endNode.offset.y,
 | 
			
		||||
            width: ew,
 | 
			
		||||
            height: endNode.height,
 | 
			
		||||
            padding: endNode.padding,
 | 
			
		||||
          },
 | 
			
		||||
          endNode.shape === 'diamond' || endNode.shape === 'diam'
 | 
			
		||||
        );
 | 
			
		||||
          if (distance(intersection, edge.points[edge.points.length - 1]) > epsilon) {
 | 
			
		||||
            // console.log('APA13! distance ok\nintersection:', intersection);
 | 
			
		||||
            edge.points.push(intersection);
 | 
			
		||||
            // console.log('APA13! distance ok\npoints:', edge.points);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const paths = insertEdge(
 | 
			
		||||
          edgesEl,
 | 
			
		||||
@@ -1022,7 +744,6 @@ export const render = async (
 | 
			
		||||
          endNode,
 | 
			
		||||
          data4Layout.diagramId
 | 
			
		||||
        );
 | 
			
		||||
        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.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,8 @@ import { createText } from '../createText.js';
 | 
			
		||||
import utils from '../../utils.js';
 | 
			
		||||
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
 | 
			
		||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
 | 
			
		||||
import { curveBasis, line, select } from 'd3';
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
import { curveBasis, curveLinear, line, select } from 'd3';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import createLabel from './createLabel.js';
 | 
			
		||||
import { addEdgeMarkers } from './edgeMarker.ts';
 | 
			
		||||
@@ -335,6 +336,40 @@ const cutPathAtIntersect = (_points, boundaryNode) => {
 | 
			
		||||
  return points;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const adjustForArrowHeads = function (lineData, size = 5, shouldLog = false) {
 | 
			
		||||
  const newLineData = [...lineData];
 | 
			
		||||
  const lastPoint = lineData[lineData.length - 1];
 | 
			
		||||
  const secondLastPoint = lineData[lineData.length - 2];
 | 
			
		||||
 | 
			
		||||
  const distanceBetweenLastPoints = Math.sqrt(
 | 
			
		||||
    (lastPoint.x - secondLastPoint.x) ** 2 + (lastPoint.y - secondLastPoint.y) ** 2
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (shouldLog) {
 | 
			
		||||
    log.debug('APA14 distanceBetweenLastPoints', distanceBetweenLastPoints);
 | 
			
		||||
  }
 | 
			
		||||
  if (distanceBetweenLastPoints < size) {
 | 
			
		||||
    // Calculate the direction vector from the last point to the second last point
 | 
			
		||||
    const directionX = secondLastPoint.x - lastPoint.x;
 | 
			
		||||
    const directionY = secondLastPoint.y - lastPoint.y;
 | 
			
		||||
 | 
			
		||||
    // Normalize the direction vector
 | 
			
		||||
    const magnitude = Math.sqrt(directionX ** 2 + directionY ** 2);
 | 
			
		||||
    const normalizedX = directionX / magnitude;
 | 
			
		||||
    const normalizedY = directionY / magnitude;
 | 
			
		||||
 | 
			
		||||
    // Calculate the new position for the second last point
 | 
			
		||||
    const adjustedSecondLastPoint = {
 | 
			
		||||
      x: lastPoint.x + normalizedX * size,
 | 
			
		||||
      y: lastPoint.y + normalizedY * size,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Replace the second last point in the new line data
 | 
			
		||||
    newLineData[newLineData.length - 2] = adjustedSecondLastPoint;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return newLineData;
 | 
			
		||||
};
 | 
			
		||||
function extractCornerPoints(points) {
 | 
			
		||||
  const cornerPoints = [];
 | 
			
		||||
  const cornerPointPositions = [];
 | 
			
		||||
@@ -422,6 +457,109 @@ const fixCorners = function (lineData) {
 | 
			
		||||
  return newLineData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const generateRoundedPath = (points, radius, endPosition) => {
 | 
			
		||||
  if (points.length < 2) {
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // console.trace('here', points);
 | 
			
		||||
  const path = [];
 | 
			
		||||
  const startPoint = points[0];
 | 
			
		||||
 | 
			
		||||
  path.push(`M ${startPoint.x},${startPoint.y}`);
 | 
			
		||||
 | 
			
		||||
  for (let i = 1; i < points.length - 1; i++) {
 | 
			
		||||
    const currPoint = points[i];
 | 
			
		||||
    const nextPoint = points[i + 1];
 | 
			
		||||
    const prevPoint = points[i - 1];
 | 
			
		||||
 | 
			
		||||
    // Calculate vectors
 | 
			
		||||
    const v1 = { x: currPoint.x - prevPoint.x, y: currPoint.y - prevPoint.y };
 | 
			
		||||
    const v2 = { x: nextPoint.x - currPoint.x, y: nextPoint.y - currPoint.y };
 | 
			
		||||
 | 
			
		||||
    // Normalize vectors
 | 
			
		||||
    const v1Length = Math.hypot(v1.x, v1.y);
 | 
			
		||||
    const v2Length = Math.hypot(v2.x, v2.y);
 | 
			
		||||
    const v1Normalized = { x: v1.x / v1Length, y: v1.y / v1Length };
 | 
			
		||||
    const v2Normalized = { x: v2.x / v2Length, y: v2.y / v2Length };
 | 
			
		||||
 | 
			
		||||
    // Calculate tangent points
 | 
			
		||||
    const tangentLength = Math.min(radius, v1Length / 2, v2Length / 2);
 | 
			
		||||
    const tangent1 = {
 | 
			
		||||
      x: currPoint.x - v1Normalized.x * tangentLength,
 | 
			
		||||
      y: currPoint.y - v1Normalized.y * tangentLength,
 | 
			
		||||
    };
 | 
			
		||||
    const tangent2 = {
 | 
			
		||||
      x: currPoint.x + v2Normalized.x * tangentLength,
 | 
			
		||||
      y: currPoint.y + v2Normalized.y * tangentLength,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (endPosition) {
 | 
			
		||||
      const { bottomY, leftX, rightX, topY } = endPosition;
 | 
			
		||||
      if (startPoint.pos === 'b' && tangent1.y > topY) {
 | 
			
		||||
        tangent1.y = topY;
 | 
			
		||||
        tangent2.y = topY;
 | 
			
		||||
        currPoint.y = topY;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 't' && tangent1.y < bottomY) {
 | 
			
		||||
        tangent1.y = bottomY;
 | 
			
		||||
        tangent2.y = bottomY;
 | 
			
		||||
        currPoint.y = bottomY;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 'l' && tangent1.x < rightX) {
 | 
			
		||||
        tangent1.x = rightX;
 | 
			
		||||
        tangent2.x = rightX;
 | 
			
		||||
        currPoint.x = rightX;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 'r' && tangent1.x > leftX) {
 | 
			
		||||
        tangent1.x = leftX;
 | 
			
		||||
        tangent2.x = leftX;
 | 
			
		||||
        currPoint.x = leftX;
 | 
			
		||||
      }
 | 
			
		||||
      if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
 | 
			
		||||
        path.push(
 | 
			
		||||
          `L ${tangent1.x},${tangent1.y}`,
 | 
			
		||||
          `Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
 | 
			
		||||
        path.push(
 | 
			
		||||
          `L ${tangent1.x},${tangent1.y}`,
 | 
			
		||||
          `Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Last point
 | 
			
		||||
  const lastPoint = points[points.length - 1];
 | 
			
		||||
  if (endPosition) {
 | 
			
		||||
    if (startPoint.pos === 'b') {
 | 
			
		||||
      if (endPosition?.topY && points[1].y > endPosition?.topY && points[2].y > endPosition?.topY) {
 | 
			
		||||
        points[1].y = endPosition?.topY;
 | 
			
		||||
        points[2].y = endPosition?.topY;
 | 
			
		||||
      }
 | 
			
		||||
      path.push(`L ${lastPoint.x},${endPosition.topY}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 't') {
 | 
			
		||||
      if (points[1].y < endPosition.bottomY) {
 | 
			
		||||
        points[1].y = endPosition.bottomY;
 | 
			
		||||
        points[2].y = endPosition.bottomY;
 | 
			
		||||
      }
 | 
			
		||||
      path.push(`L ${lastPoint.x},${endPosition.bottomY}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 'l') {
 | 
			
		||||
      path.push(`L ${endPosition.rightX},${lastPoint.y}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 'r') {
 | 
			
		||||
      path.push(`L ${endPosition.leftX},${lastPoint.y}`);
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    path.push(`L ${lastPoint.x},${lastPoint.y}`);
 | 
			
		||||
  }
 | 
			
		||||
  return path.join(' ');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
 | 
			
		||||
  const { handDrawnSeed } = getConfig();
 | 
			
		||||
  let points = edge.points;
 | 
			
		||||
@@ -462,14 +600,21 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let lineData = points.filter((p) => !Number.isNaN(p.y));
 | 
			
		||||
  lineData = adjustForArrowHeads(lineData, 4, edge.id === 'L_n4_C_10_0');
 | 
			
		||||
  lineData = fixCorners(lineData);
 | 
			
		||||
  // if (edge.id === 'L_n4_C_10_0') {
 | 
			
		||||
  //   console.log('APA14 lineData', lineData);
 | 
			
		||||
  // }
 | 
			
		||||
  // lineData = adjustForArrowHeads(lineData);
 | 
			
		||||
  let curve = curveBasis;
 | 
			
		||||
  // let curve = curveLinear;
 | 
			
		||||
  if (edge.curve) {
 | 
			
		||||
    curve = edge.curve;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { x, y } = getLineFunctionsWithOffset(edge);
 | 
			
		||||
  const lineFunction = line().x(x).y(y).curve(curve);
 | 
			
		||||
  // const lineFunction = line().curve(curve);
 | 
			
		||||
 | 
			
		||||
  let strokeClasses;
 | 
			
		||||
  switch (edge.thickness) {
 | 
			
		||||
@@ -500,6 +645,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
  }
 | 
			
		||||
  let svgPath;
 | 
			
		||||
  let linePath = lineFunction(lineData);
 | 
			
		||||
  // let linePath = generateRoundedPath(lineData, 5);
 | 
			
		||||
  const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
 | 
			
		||||
  if (edge.look === 'handDrawn') {
 | 
			
		||||
    const rc = rough.svg(elem);
 | 
			
		||||
@@ -531,21 +677,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
 | 
			
		||||
  // DEBUG code, DO NOT REMOVE
 | 
			
		||||
  // adds a red circle at each edge coordinate
 | 
			
		||||
  // cornerPoints.forEach((point) => {
 | 
			
		||||
  // points.forEach((point) => {
 | 
			
		||||
  //   elem
 | 
			
		||||
  //     .append('circle')
 | 
			
		||||
  //     .style('stroke', 'blue')
 | 
			
		||||
  //     .style('fill', 'blue')
 | 
			
		||||
  //     .attr('r', 3)
 | 
			
		||||
  //     .attr('cx', point.x)
 | 
			
		||||
  //     .attr('cy', point.y);
 | 
			
		||||
  // });
 | 
			
		||||
  // lineData.forEach((point) => {
 | 
			
		||||
  //   elem
 | 
			
		||||
  //     .append('circle')
 | 
			
		||||
  //     .style('stroke', 'blue')
 | 
			
		||||
  //     .style('fill', 'blue')
 | 
			
		||||
  //     .attr('r', 3)
 | 
			
		||||
  //     .style('stroke', 'red')
 | 
			
		||||
  //     .style('fill', 'red')
 | 
			
		||||
  //     .attr('r', 1)
 | 
			
		||||
  //     .attr('cx', point.x)
 | 
			
		||||
  //     .attr('cy', point.y);
 | 
			
		||||
  // });
 | 
			
		||||
 
 | 
			
		||||
@@ -2,64 +2,87 @@
 | 
			
		||||
 * Returns the point at which two lines, p and q, intersect or returns undefined if they do not intersect.
 | 
			
		||||
 */
 | 
			
		||||
function intersectLine(p1, p2, q1, q2) {
 | 
			
		||||
  // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
 | 
			
		||||
  // p7 and p473.
 | 
			
		||||
  {
 | 
			
		||||
    // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
 | 
			
		||||
    // p7 and p473.
 | 
			
		||||
 | 
			
		||||
  var a1, a2, b1, b2, c1, c2;
 | 
			
		||||
  var r1, r2, r3, r4;
 | 
			
		||||
  var denom, offset, num;
 | 
			
		||||
  var x, y;
 | 
			
		||||
    // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
 | 
			
		||||
    // b1 y + c1 = 0.
 | 
			
		||||
    const a1 = p2.y - p1.y;
 | 
			
		||||
    const b1 = p1.x - p2.x;
 | 
			
		||||
    const c1 = p2.x * p1.y - p1.x * p2.y;
 | 
			
		||||
 | 
			
		||||
  // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
 | 
			
		||||
  // b1 y + c1 = 0.
 | 
			
		||||
  a1 = p2.y - p1.y;
 | 
			
		||||
  b1 = p1.x - p2.x;
 | 
			
		||||
  c1 = p2.x * p1.y - p1.x * p2.y;
 | 
			
		||||
    // Compute r3 and r4.
 | 
			
		||||
    const r3 = a1 * q1.x + b1 * q1.y + c1;
 | 
			
		||||
    const r4 = a1 * q2.x + b1 * q2.y + c1;
 | 
			
		||||
 | 
			
		||||
  // Compute r3 and r4.
 | 
			
		||||
  r3 = a1 * q1.x + b1 * q1.y + c1;
 | 
			
		||||
  r4 = a1 * q2.x + b1 * q2.y + c1;
 | 
			
		||||
    const epsilon = 1e-6;
 | 
			
		||||
 | 
			
		||||
  // Check signs of r3 and r4. If both point 3 and point 4 lie on
 | 
			
		||||
  // same side of line 1, the line segments do not intersect.
 | 
			
		||||
  if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
 | 
			
		||||
    return /*DON'T_INTERSECT*/;
 | 
			
		||||
    // Check signs of r3 and r4. If both point 3 and point 4 lie on
 | 
			
		||||
    // same side of line 1, the line segments do not intersect.
 | 
			
		||||
    if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
 | 
			
		||||
      return /*DON'T_INTERSECT*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
 | 
			
		||||
    const a2 = q2.y - q1.y;
 | 
			
		||||
    const b2 = q1.x - q2.x;
 | 
			
		||||
    const c2 = q2.x * q1.y - q1.x * q2.y;
 | 
			
		||||
 | 
			
		||||
    // Compute r1 and r2
 | 
			
		||||
    const r1 = a2 * p1.x + b2 * p1.y + c2;
 | 
			
		||||
    const r2 = a2 * p2.x + b2 * p2.y + c2;
 | 
			
		||||
 | 
			
		||||
    // Check signs of r1 and r2. If both point 1 and point 2 lie
 | 
			
		||||
    // on same side of second line segment, the line segments do
 | 
			
		||||
    // not intersect.
 | 
			
		||||
    if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
 | 
			
		||||
      return /*DON'T_INTERSECT*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Line segments intersect: compute intersection point.
 | 
			
		||||
    const denom = a1 * b2 - a2 * b1;
 | 
			
		||||
    if (denom === 0) {
 | 
			
		||||
      return /*COLLINEAR*/;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const offset = Math.abs(denom / 2);
 | 
			
		||||
 | 
			
		||||
    // The denom/2 is to get rounding instead of truncating. It
 | 
			
		||||
    // is added or subtracted to the numerator, depending upon the
 | 
			
		||||
    // sign of the numerator.
 | 
			
		||||
    let num = b1 * c2 - b2 * c1;
 | 
			
		||||
    const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
 | 
			
		||||
    num = a2 * c1 - a1 * c2;
 | 
			
		||||
    const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
    // console.log(
 | 
			
		||||
    //   'APA13 intersectLine intersection',
 | 
			
		||||
    //   '\np1: (',
 | 
			
		||||
    //   p1.x,
 | 
			
		||||
    //   p1.y,
 | 
			
		||||
    //   ')',
 | 
			
		||||
    //   '\np2: (',
 | 
			
		||||
    //   p2.x,
 | 
			
		||||
    //   p2.y,
 | 
			
		||||
    //   ')',
 | 
			
		||||
    //   '\nq1: (',
 | 
			
		||||
    //   q1.x,
 | 
			
		||||
    //   q1.y,
 | 
			
		||||
    //   ')',
 | 
			
		||||
    //   '\np1: (',
 | 
			
		||||
    //   q2.x,
 | 
			
		||||
    //   q2.y,
 | 
			
		||||
    //   ')',
 | 
			
		||||
    //   'offset:',
 | 
			
		||||
    //   offset,
 | 
			
		||||
    //   '\nintersection: (',
 | 
			
		||||
    //   x,
 | 
			
		||||
    //   y,
 | 
			
		||||
    //   ')'
 | 
			
		||||
    // );
 | 
			
		||||
    return { x: x, y: y };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
 | 
			
		||||
  a2 = q2.y - q1.y;
 | 
			
		||||
  b2 = q1.x - q2.x;
 | 
			
		||||
  c2 = q2.x * q1.y - q1.x * q2.y;
 | 
			
		||||
 | 
			
		||||
  // Compute r1 and r2
 | 
			
		||||
  r1 = a2 * p1.x + b2 * p1.y + c2;
 | 
			
		||||
  r2 = a2 * p2.x + b2 * p2.y + c2;
 | 
			
		||||
 | 
			
		||||
  // Check signs of r1 and r2. If both point 1 and point 2 lie
 | 
			
		||||
  // on same side of second line segment, the line segments do
 | 
			
		||||
  // not intersect.
 | 
			
		||||
  if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
 | 
			
		||||
    return /*DON'T_INTERSECT*/;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Line segments intersect: compute intersection point.
 | 
			
		||||
  denom = a1 * b2 - a2 * b1;
 | 
			
		||||
  if (denom === 0) {
 | 
			
		||||
    return /*COLLINEAR*/;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  offset = Math.abs(denom / 2);
 | 
			
		||||
 | 
			
		||||
  // The denom/2 is to get rounding instead of truncating. It
 | 
			
		||||
  // is added or subtracted to the numerator, depending upon the
 | 
			
		||||
  // sign of the numerator.
 | 
			
		||||
  num = b1 * c2 - b2 * c1;
 | 
			
		||||
  x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
 | 
			
		||||
  num = a2 * c1 - a1 * c2;
 | 
			
		||||
  y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
 | 
			
		||||
  return { x: x, y: y };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sameSign(r1, r2) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import intersectLine from './intersect-line.js';
 | 
			
		||||
function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
  let x1 = node.x;
 | 
			
		||||
  let y1 = node.y;
 | 
			
		||||
 | 
			
		||||
  // console.trace('APA14 intersectPolygon', x1, y1, polyPoints, point);
 | 
			
		||||
  let intersections = [];
 | 
			
		||||
 | 
			
		||||
  let minX = Number.POSITIVE_INFINITY;
 | 
			
		||||
@@ -24,7 +24,7 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
 | 
			
		||||
  let left = x1 - node.width / 2 - minX;
 | 
			
		||||
  let top = y1 - node.height / 2 - minY;
 | 
			
		||||
 | 
			
		||||
  // console.log('APA13 intersectPolygon2 ', left, y1);
 | 
			
		||||
  for (let i = 0; i < polyPoints.length; i++) {
 | 
			
		||||
    let p1 = polyPoints[i];
 | 
			
		||||
    let p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
 | 
			
		||||
@@ -34,7 +34,9 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
      { x: left + p1.x, y: top + p1.y },
 | 
			
		||||
      { x: left + p2.x, y: top + p2.y }
 | 
			
		||||
    );
 | 
			
		||||
    // console.log('APA13 intersectPolygon3 ', intersect);
 | 
			
		||||
    if (intersect) {
 | 
			
		||||
      // console.log('APA13 intersectPolygon4 ', intersect);
 | 
			
		||||
      intersections.push(intersect);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -42,6 +44,7 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
  if (!intersections.length) {
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('APA12 intersectPolygon5 ');
 | 
			
		||||
 | 
			
		||||
  if (intersections.length > 1) {
 | 
			
		||||
    // More intersections, find the one nearest to edge end point
 | 
			
		||||
@@ -54,6 +57,8 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
      let qdy = q.y - point.y;
 | 
			
		||||
      let distq = Math.sqrt(qdx * qdx + qdy * qdy);
 | 
			
		||||
 | 
			
		||||
      // console.log('APA12 intersectPolygon6 ');
 | 
			
		||||
 | 
			
		||||
      return distp < distq ? -1 : distp === distq ? 0 : 1;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles } = styles2String(node);
 | 
			
		||||
@@ -37,6 +38,11 @@ export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, circleElem);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Circle intersect', node, radius, point);
 | 
			
		||||
    return intersect.circle(node, radius, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function generateArcPoints(
 | 
			
		||||
  x1: number,
 | 
			
		||||
@@ -70,7 +71,15 @@ function generateArcPoints(
 | 
			
		||||
 | 
			
		||||
  return points;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getPoints(w: number, h: number, rx: number, ry: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: w / 2, y: -h / 2 },
 | 
			
		||||
    { x: -w / 2, y: -h / 2 },
 | 
			
		||||
    ...generateArcPoints(-w / 2, -h / 2, -w / 2, h / 2, rx, ry, false),
 | 
			
		||||
    { x: w / 2, y: h / 2 },
 | 
			
		||||
    ...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true),
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
  node.labelStyle = labelStyles;
 | 
			
		||||
@@ -84,13 +93,7 @@ export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
  // let shape: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
 | 
			
		||||
  const { cssStyles } = node;
 | 
			
		||||
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: w / 2, y: -h / 2 },
 | 
			
		||||
    { x: -w / 2, y: -h / 2 },
 | 
			
		||||
    ...generateArcPoints(-w / 2, -h / 2, -w / 2, h / 2, rx, ry, false),
 | 
			
		||||
    { x: w / 2, y: h / 2 },
 | 
			
		||||
    ...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true),
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getPoints(w, h, rx, ry);
 | 
			
		||||
 | 
			
		||||
  // @ts-expect-error -- Passing a D3.Selection seems to work for some reason
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
@@ -118,6 +121,16 @@ export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, bowTieRectShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
 | 
			
		||||
    const ry = h / 2;
 | 
			
		||||
    const rx = ry / (2.5 + h / 50);
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(w, h, rx, ry);
 | 
			
		||||
    return intersect.polygon(bounds, points, point);
 | 
			
		||||
  };
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,25 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import { createPathFromPoints } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
// const createPathFromPoints = (points: { x: number; y: number }[]): string => {
 | 
			
		||||
//   const pointStrings = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`);
 | 
			
		||||
//   pointStrings.push('Z');
 | 
			
		||||
//   return pointStrings.join(' ');
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
function getPoints(w: number, h: number, padding: number) {
 | 
			
		||||
  const left = 0;
 | 
			
		||||
  const right = w;
 | 
			
		||||
  const top = -h;
 | 
			
		||||
  const bottom = 0;
 | 
			
		||||
  return [
 | 
			
		||||
    { x: left + padding, y: top },
 | 
			
		||||
    { x: right, y: top },
 | 
			
		||||
    { x: right, y: bottom },
 | 
			
		||||
    { x: left, y: bottom },
 | 
			
		||||
    { x: left, y: top + padding },
 | 
			
		||||
    { x: left + padding, y: top },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
  node.labelStyle = labelStyles;
 | 
			
		||||
@@ -22,18 +30,8 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
 | 
			
		||||
  const h = bbox.height + node.padding;
 | 
			
		||||
  const padding = 12;
 | 
			
		||||
  const w = bbox.width + node.padding + padding;
 | 
			
		||||
  const left = 0;
 | 
			
		||||
  const right = w;
 | 
			
		||||
  const top = -h;
 | 
			
		||||
  const bottom = 0;
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: left + padding, y: top },
 | 
			
		||||
    { x: right, y: top },
 | 
			
		||||
    { x: right, y: bottom },
 | 
			
		||||
    { x: left, y: bottom },
 | 
			
		||||
    { x: left, y: top + padding },
 | 
			
		||||
    { x: left + padding, y: top },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const points = getPoints(w, h, padding);
 | 
			
		||||
 | 
			
		||||
  let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
 | 
			
		||||
  const { cssStyles } = node;
 | 
			
		||||
@@ -62,6 +60,17 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const padding = 12;
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(w, h, padding);
 | 
			
		||||
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,15 @@ import rough from 'roughjs';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { createPathFromPoints, getNodeClasses } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
function getPoints(s: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: 0, y: s / 2 },
 | 
			
		||||
    { x: s / 2, y: 0 },
 | 
			
		||||
    { x: 0, y: -s / 2 },
 | 
			
		||||
    { x: -s / 2, y: 0 },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { nodeStyles } = styles2String(node);
 | 
			
		||||
  node.label = '';
 | 
			
		||||
@@ -16,12 +24,7 @@ export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
 | 
			
		||||
 | 
			
		||||
  const s = Math.max(28, node.width ?? 0);
 | 
			
		||||
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: 0, y: s / 2 },
 | 
			
		||||
    { x: s / 2, y: 0 },
 | 
			
		||||
    { x: 0, y: -s / 2 },
 | 
			
		||||
    { x: -s / 2, y: 0 },
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getPoints(s);
 | 
			
		||||
 | 
			
		||||
  // @ts-expect-error -- Passing a D3.Selection seems to work for some reason
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
@@ -47,6 +50,13 @@ export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
 | 
			
		||||
  node.width = 28;
 | 
			
		||||
  node.height = 28;
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const s = Math.max(28, bounds.width ?? 0);
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(s);
 | 
			
		||||
    return intersect.circle(bounds, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -35,7 +36,10 @@ export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, circleElem);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Circle intersect', node, radius, point);
 | 
			
		||||
    return intersect.circle(node, radius, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { textHelper } from '../../../diagrams/class/shapeUtil.js';
 | 
			
		||||
import { evaluate } from '../../../diagrams/common/common.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const config = getConfig();
 | 
			
		||||
@@ -199,6 +200,9 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    return intersect.rect(bounds, point);
 | 
			
		||||
  };
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function createLine(r: number) {
 | 
			
		||||
  const xAxis45 = Math.cos(Math.PI / 4); // cosine of 45 degrees
 | 
			
		||||
@@ -57,6 +58,11 @@ export function crossedCircle<T extends SVGGraphicsElement>(parent: D3Selection<
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, crossedCircle);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const radius = Math.max(30, bounds?.width ?? 0);
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('crossedCircle intersect', node, { radius, point });
 | 
			
		||||
    const pos = intersect.circle(node, radius, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function generateCirclePoints(
 | 
			
		||||
  centerX: number,
 | 
			
		||||
@@ -35,6 +36,21 @@ function generateCirclePoints(
 | 
			
		||||
  return points;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRectPoints(w: number, h: number, radius: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
    { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
    { x: -w / 2 - radius, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270),
 | 
			
		||||
    ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180),
 | 
			
		||||
    { x: -w / 2 - radius, y: h / 2 },
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
    { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
    { x: w / 2, y: h / 2 + radius },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function curlyBraceLeft<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
  node: Node
 | 
			
		||||
@@ -57,18 +73,7 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const rectPoints = [
 | 
			
		||||
    { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
    { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
    { x: -w / 2 - radius, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270),
 | 
			
		||||
    ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180),
 | 
			
		||||
    { x: -w / 2 - radius, y: h / 2 },
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
    { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
    { x: w / 2, y: h / 2 + radius },
 | 
			
		||||
  ];
 | 
			
		||||
  const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
 | 
			
		||||
  // @ts-expect-error -- Passing a D3.Selection seems to work for some reason
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
@@ -105,6 +110,15 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, curlyBraceLeftShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const radius = Math.max(5, h * 0.1);
 | 
			
		||||
 | 
			
		||||
    const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
    return intersect.polygon(bounds, rectPoints, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, rectPoints, point);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function generateCirclePoints(
 | 
			
		||||
  centerX: number,
 | 
			
		||||
@@ -35,6 +36,21 @@ function generateCirclePoints(
 | 
			
		||||
  return points;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getRectPoints(w: number, h: number, radius: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
    { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
    { x: w / 2 + radius, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
 | 
			
		||||
    { x: w / 2 + radius, y: h / 2 },
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
    { x: w / 2, y: h / 2 + radius },
 | 
			
		||||
    { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function curlyBraceRight<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
  node: Node
 | 
			
		||||
@@ -57,18 +73,7 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const rectPoints = [
 | 
			
		||||
    { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
    { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
    { x: w / 2 + radius, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
 | 
			
		||||
    { x: w / 2 + radius, y: h / 2 },
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
    { x: w / 2, y: h / 2 + radius },
 | 
			
		||||
    { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
  ];
 | 
			
		||||
  const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
 | 
			
		||||
  // @ts-expect-error -- Passing a D3.Selection seems to work for some reason
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
@@ -105,6 +110,15 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, curlyBraceRightShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const radius = Math.max(5, h * 0.1);
 | 
			
		||||
 | 
			
		||||
    const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
    return intersect.polygon(bounds, rectPoints, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, rectPoints, point);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function generateCirclePoints(
 | 
			
		||||
  centerX: number,
 | 
			
		||||
@@ -35,6 +36,25 @@ function generateCirclePoints(
 | 
			
		||||
  return points;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const getRectPoints = (w: number, h: number, radius: number) => [
 | 
			
		||||
  { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
  { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
  ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
  { x: -w / 2 - radius, y: -radius },
 | 
			
		||||
  ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
 | 
			
		||||
  ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
 | 
			
		||||
  { x: -w / 2 - radius, y: h / 2 },
 | 
			
		||||
  ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
  { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
  { x: w / 2 - radius - radius / 2, y: h / 2 + radius },
 | 
			
		||||
  ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180),
 | 
			
		||||
  { x: w / 2 - radius / 2, y: radius },
 | 
			
		||||
  ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90),
 | 
			
		||||
  ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0),
 | 
			
		||||
  { x: w / 2 - radius / 2, y: -radius },
 | 
			
		||||
  ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export async function curlyBraces<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
  node: Node
 | 
			
		||||
@@ -66,24 +86,7 @@ export async function curlyBraces<T extends SVGGraphicsElement>(
 | 
			
		||||
    ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const rectPoints = [
 | 
			
		||||
    { x: w / 2, y: -h / 2 - radius },
 | 
			
		||||
    { x: -w / 2, y: -h / 2 - radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
 | 
			
		||||
    { x: -w / 2 - radius, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
 | 
			
		||||
    ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
 | 
			
		||||
    { x: -w / 2 - radius, y: h / 2 },
 | 
			
		||||
    ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
 | 
			
		||||
    { x: -w / 2, y: h / 2 + radius },
 | 
			
		||||
    { x: w / 2 - radius - radius / 2, y: h / 2 + radius },
 | 
			
		||||
    ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180),
 | 
			
		||||
    { x: w / 2 - radius / 2, y: radius },
 | 
			
		||||
    ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90),
 | 
			
		||||
    ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0),
 | 
			
		||||
    { x: w / 2 - radius / 2, y: -radius },
 | 
			
		||||
    ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
 | 
			
		||||
  ];
 | 
			
		||||
  const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
 | 
			
		||||
  // @ts-expect-error -- Passing a D3.Selection seems to work for some reason
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
@@ -124,6 +127,15 @@ export async function curlyBraces<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, curlyBracesShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const radius = Math.max(5, h * 0.1);
 | 
			
		||||
 | 
			
		||||
    const rectPoints = getRectPoints(w, h, radius);
 | 
			
		||||
    return intersect.polygon(bounds, rectPoints, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, rectPoints, point);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,16 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
const getTrapezoidPoints = (rw: number, tw: number, totalHeight: number, radius: number) => [
 | 
			
		||||
  { x: rw, y: 0 },
 | 
			
		||||
  { x: tw, y: 0 },
 | 
			
		||||
  { x: 0, y: totalHeight / 2 },
 | 
			
		||||
  { x: tw, y: totalHeight },
 | 
			
		||||
  { x: rw, y: totalHeight },
 | 
			
		||||
  ...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export async function curvedTrapezoid<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -39,14 +49,7 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
 | 
			
		||||
  const rw = totalWidth - radius;
 | 
			
		||||
  const tw = totalHeight / 4;
 | 
			
		||||
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: rw, y: 0 },
 | 
			
		||||
    { x: tw, y: 0 },
 | 
			
		||||
    { x: 0, y: totalHeight / 2 },
 | 
			
		||||
    { x: tw, y: totalHeight },
 | 
			
		||||
    { x: rw, y: totalHeight },
 | 
			
		||||
    ...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90),
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getTrapezoidPoints(rw, tw, totalHeight, radius);
 | 
			
		||||
 | 
			
		||||
  const pathData = createPathFromPoints(points);
 | 
			
		||||
  const shapeNode = rc.path(pathData, options);
 | 
			
		||||
@@ -66,6 +69,20 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const radius = h / 2;
 | 
			
		||||
 | 
			
		||||
    const totalWidth = w,
 | 
			
		||||
      totalHeight = h;
 | 
			
		||||
    const rw = totalWidth - radius;
 | 
			
		||||
    const tw = totalHeight / 4;
 | 
			
		||||
    const points = getTrapezoidPoints(rw, tw, totalHeight, radius);
 | 
			
		||||
 | 
			
		||||
    return intersect.polygon(bounds, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createCylinderPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -96,22 +97,24 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
    `translate(${-(bbox.width / 2) - (bbox.x - (bbox.left ?? 0))}, ${-(bbox.height / 2) + (node.padding ?? 0) / 1.5 - (bbox.y - (bbox.top ?? 0))})`
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
    const x = pos.x - (node.x ?? 0);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const rx = w / 2;
 | 
			
		||||
    const ry = rx / (2.5 + w / 50);
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const pos = intersect.rect(bounds, point);
 | 
			
		||||
    const x = pos.x - (bounds.x ?? 0);
 | 
			
		||||
    if (
 | 
			
		||||
      rx != 0 &&
 | 
			
		||||
      (Math.abs(x) < (node.width ?? 0) / 2 ||
 | 
			
		||||
        (Math.abs(x) == (node.width ?? 0) / 2 &&
 | 
			
		||||
          Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
 | 
			
		||||
      (Math.abs(x) < (w ?? 0) / 2 ||
 | 
			
		||||
        (Math.abs(x) == (w ?? 0) / 2 && Math.abs(pos.y - (bounds.y ?? 0)) > (h ?? 0) / 2 - ry))
 | 
			
		||||
    ) {
 | 
			
		||||
      let y = ry * ry * (1 - (x * x) / (rx * rx));
 | 
			
		||||
      if (y > 0) {
 | 
			
		||||
        y = Math.sqrt(y);
 | 
			
		||||
      }
 | 
			
		||||
      y = ry - y;
 | 
			
		||||
      if (point.y - (node.y ?? 0) > 0) {
 | 
			
		||||
      if (point.y - (bounds.y ?? 0) > 0) {
 | 
			
		||||
        y = -y;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -121,5 +124,14 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
    return pos;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point: Point) {
 | 
			
		||||
    return this.calcIntersect
 | 
			
		||||
      ? this.calcIntersect(
 | 
			
		||||
          { x: node.x ?? 0, y: node.y ?? 0, width: node.width ?? 0, height: node.height ?? 0 },
 | 
			
		||||
          point
 | 
			
		||||
        )
 | 
			
		||||
      : { x: 0, y: 0 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function dividedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -62,6 +63,10 @@ export async function dividedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    return intersect.rect(bounds, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createCylinderPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -91,29 +92,36 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, cylinder);
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
    const x = pos.x - (node.x ?? 0);
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const pos = intersect.rect(bounds, point);
 | 
			
		||||
    const x = pos.x - (bounds.x ?? 0);
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      rx != 0 &&
 | 
			
		||||
      (Math.abs(x) < (node.width ?? 0) / 2 ||
 | 
			
		||||
        (Math.abs(x) == (node.width ?? 0) / 2 &&
 | 
			
		||||
          Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
 | 
			
		||||
      (Math.abs(x) < (bounds.width ?? 0) / 2 ||
 | 
			
		||||
        (Math.abs(x) == (bounds.width ?? 0) / 2 &&
 | 
			
		||||
          Math.abs(pos.y - (bounds.y ?? 0)) > (bounds.height ?? 0) / 2 - ry))
 | 
			
		||||
    ) {
 | 
			
		||||
      let y = ry * ry * (1 - (x * x) / (rx * rx));
 | 
			
		||||
      if (y != 0) {
 | 
			
		||||
        y = Math.sqrt(y);
 | 
			
		||||
      }
 | 
			
		||||
      y = ry - y;
 | 
			
		||||
      if (point.y - (node.y ?? 0) > 0) {
 | 
			
		||||
      if (point.y - (bounds.y ?? 0) > 0) {
 | 
			
		||||
        y = -y;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      pos.y += y;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
    return pos;
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return this.calcIntersect
 | 
			
		||||
      ? this.calcIntersect(
 | 
			
		||||
          { x: node.x ?? 0, y: node.y ?? 0, width: node.width ?? 0, height: node.height ?? 0 },
 | 
			
		||||
          point
 | 
			
		||||
        )
 | 
			
		||||
      : { x: 0, y: 0 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function doublecircle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -62,6 +63,11 @@ export async function doublecircle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, circleGroup);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('DoubleCircle intersect', node, outerRadius, point);
 | 
			
		||||
    return intersect.circle(node, outerRadius, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function drawRect<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -62,6 +63,10 @@ export async function drawRect<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    return intersect.rect(bounds, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { getNodeClasses, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export function filledCircle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -46,6 +47,11 @@ export function filledCircle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, filledCircle);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('filledCircle intersect', node, { radius, point });
 | 
			
		||||
    const pos = intersect.circle(node, radius, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,15 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { createPathFromPoints } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function getPoints(tw: number, h: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: 0, y: -h },
 | 
			
		||||
    { x: tw, y: -h },
 | 
			
		||||
    { x: tw / 2, y: 0 },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function flippedTriangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -19,11 +28,7 @@ export async function flippedTriangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  const h = w + bbox.height;
 | 
			
		||||
 | 
			
		||||
  const tw = w + bbox.height;
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: 0, y: -h },
 | 
			
		||||
    { x: tw, y: -h },
 | 
			
		||||
    { x: tw / 2, y: 0 },
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getPoints(tw, h);
 | 
			
		||||
 | 
			
		||||
  const { cssStyles } = node;
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +64,16 @@ export async function flippedTriangle<T extends SVGGraphicsElement>(
 | 
			
		||||
    `translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))}, ${-h / 2 + (node.padding ?? 0) / 2 + (bbox.y - (bbox.top ?? 0))})`
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
 | 
			
		||||
    const tw = w + bounds.height;
 | 
			
		||||
    const points = getPoints(tw, h);
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Triangle intersect', node, points, point);
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { getNodeClasses, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export function forkJoin<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -59,6 +60,10 @@ export function forkJoin<T extends SVGGraphicsElement>(
 | 
			
		||||
    node.width += padding / 2 || 0;
 | 
			
		||||
    node.height += padding / 2 || 0;
 | 
			
		||||
  }
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    return intersect.rect(bounds, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -63,6 +64,12 @@ export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Pill intersect', node, { radius, point });
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createHexagonPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -72,6 +73,12 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -52,6 +53,18 @@ export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selectio
 | 
			
		||||
 | 
			
		||||
  // label.attr('transform', `translate(${-bbox.width / 2}, ${(h/2)})`); // To transform text below hourglass shape
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const { width: w, height: h } = bounds;
 | 
			
		||||
    const points = [
 | 
			
		||||
      { x: 0, y: 0 },
 | 
			
		||||
      { x: w, y: 0 },
 | 
			
		||||
      { x: 0, y: h },
 | 
			
		||||
      { x: w, y: h },
 | 
			
		||||
    ];
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Pill intersect', node, { points });
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function icon<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -97,6 +98,12 @@ export async function icon<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, outerShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('iconSquare intersect', node, point);
 | 
			
		||||
    if (!node.label) {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function iconCircle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -94,6 +95,12 @@ export async function iconCircle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, outerShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('iconSquare intersect', node, point);
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShap
 | 
			
		||||
import { createRoundedRectPathD } from './roundedRectPath.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function iconRounded<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -104,6 +105,12 @@ export async function iconRounded<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, outerShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('iconSquare intersect', node, point);
 | 
			
		||||
    if (!node.label) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
 | 
			
		||||
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function iconSquare<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -104,6 +105,12 @@ export async function iconSquare<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, outerShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('iconSquare intersect', node, point);
 | 
			
		||||
    if (!node.label) {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function imageSquare<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -108,6 +109,12 @@ export async function imageSquare<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, outerShape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('iconSquare intersect', node, point);
 | 
			
		||||
    if (!node.label) {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,21 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
// export const createInvertedTrapezoidPathD = (
 | 
			
		||||
//   x: number,
 | 
			
		||||
//   y: number,
 | 
			
		||||
//   width: number,
 | 
			
		||||
//   height: number
 | 
			
		||||
// ): string => {
 | 
			
		||||
//   return [
 | 
			
		||||
//     `M${x + height / 6},${y}`,
 | 
			
		||||
//     `L${x + width - height / 6},${y}`,
 | 
			
		||||
//     `L${x + width + (2 * height) / 6},${y - height}`,
 | 
			
		||||
//     `L${x - (2 * height) / 6},${y - height}`,
 | 
			
		||||
//     'Z',
 | 
			
		||||
//   ].join(' ');
 | 
			
		||||
// };
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function inv_trapezoid<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -70,6 +56,12 @@ export async function inv_trapezoid<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
 | 
			
		||||
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
const colorFromPriority = (priority: NonNullable<KanbanNode['priority']>) => {
 | 
			
		||||
  switch (priority) {
 | 
			
		||||
@@ -155,6 +156,12 @@ export async function kanbanItem<T extends SVGGraphicsElement>(
 | 
			
		||||
  updateNodeBounds(kanbanNode, rect);
 | 
			
		||||
  kanbanNode.height = totalHeight;
 | 
			
		||||
 | 
			
		||||
  kanbanNode.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  kanbanNode.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(kanbanNode, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ import { drawRect } from './drawRect.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function roundedRect<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -48,8 +49,12 @@ export async function labelRect<T extends SVGGraphicsElement>(parent: D3Selectio
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
  // node.width = 1;
 | 
			
		||||
  // node.height = 1;
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -50,6 +51,12 @@ export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selectio
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -49,8 +50,59 @@ export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const dx = h / 2;
 | 
			
		||||
    const z = w - h;
 | 
			
		||||
    // (w = dx+z+dx)
 | 
			
		||||
    const points = [
 | 
			
		||||
      { x: -dx, y: 0 },
 | 
			
		||||
      { x: z, y: 0 },
 | 
			
		||||
      { x: z + dx, y: -h },
 | 
			
		||||
      { x: 0, y: -h },
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
    // if (node.id === 'C') {
 | 
			
		||||
    //   console.log(
 | 
			
		||||
    //     'APA14!',
 | 
			
		||||
    //     bounds.x,
 | 
			
		||||
    //     bounds.x,
 | 
			
		||||
    //     bounds.width,
 | 
			
		||||
    //     '\nw:',
 | 
			
		||||
    //     w,
 | 
			
		||||
    //     points,
 | 
			
		||||
    //     '\nExternal point: ',
 | 
			
		||||
    //     '(',
 | 
			
		||||
    //     point.x,
 | 
			
		||||
    //     point.y,
 | 
			
		||||
    //     ')\nIntersection:',
 | 
			
		||||
    //     res
 | 
			
		||||
    //   );
 | 
			
		||||
    // }
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point: Point) {
 | 
			
		||||
    const res = intersect.polygon(node, points, point);
 | 
			
		||||
    // if (node.id === 'C') {
 | 
			
		||||
    //   console.log(
 | 
			
		||||
    //     'APA14!!',
 | 
			
		||||
    //     node.x,
 | 
			
		||||
    //     node.y,
 | 
			
		||||
    //     '\nw:',
 | 
			
		||||
    //     node.width,
 | 
			
		||||
    //     points,
 | 
			
		||||
    //     '\nExternal point: ',
 | 
			
		||||
    //     '(',
 | 
			
		||||
    //     point.x,
 | 
			
		||||
    //     point.y,
 | 
			
		||||
    //     ')\nIntersection:',
 | 
			
		||||
    //     res
 | 
			
		||||
    //   );
 | 
			
		||||
    // }
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,17 @@ import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import { createPathFromPoints } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
function getPoints(width: number, height: number, gapX: number, gapY: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: width, y: 0 },
 | 
			
		||||
    { x: 0, y: height / 2 + gapY / 2 },
 | 
			
		||||
    { x: width - 4 * gapX, y: height / 2 + gapY / 2 },
 | 
			
		||||
    { x: 0, y: height },
 | 
			
		||||
    { x: width, y: height / 2 - gapY / 2 },
 | 
			
		||||
    { x: 4 * gapX, y: height / 2 - gapY / 2 },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
  node.label = '';
 | 
			
		||||
@@ -55,11 +65,21 @@ export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, lightningBolt);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const { width: w, height: h } = bounds;
 | 
			
		||||
    const gapX = Math.max(5, w * 0.1);
 | 
			
		||||
    const gapY = Math.max(5, h * 0.1);
 | 
			
		||||
    const p = getPoints(w, h, gapX, gapY);
 | 
			
		||||
    const res = intersect.polygon(bounds, p, point);
 | 
			
		||||
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('lightningBolt intersect', node, point);
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    const res = intersect.polygon(node, points, point);
 | 
			
		||||
 | 
			
		||||
    return pos;
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createCylinderPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -110,6 +111,12 @@ export async function linedCylinder<T extends SVGGraphicsElement>(
 | 
			
		||||
    `translate(${-(bbox.width / 2) - (bbox.x - (bbox.left ?? 0))}, ${-(bbox.height / 2) + ry - (bbox.y - (bbox.top ?? 0))})`
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
    const x = pos.x - (node.x ?? 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -74,6 +75,13 @@ export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, waveEdgeRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -74,6 +75,12 @@ export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selectio
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, multiRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, outerPathPoints, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -99,6 +100,12 @@ export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, shape);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, outerPathPoints, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { getConfig } from '../../../config.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function note<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -52,6 +53,12 @@ export async function note<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import { log } from '../../../logger.js';
 | 
			
		||||
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { Node } from '../../types.js';
 | 
			
		||||
@@ -6,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
 | 
			
		||||
  return [
 | 
			
		||||
@@ -59,17 +59,41 @@ export async function question<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const s = bounds.width;
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.debug(
 | 
			
		||||
      'APA12 Intersect called SPLIT\npoint:',
 | 
			
		||||
      point,
 | 
			
		||||
      '\nnode:\n',
 | 
			
		||||
      node,
 | 
			
		||||
      '\nres:',
 | 
			
		||||
      intersect.polygon(node, points, point)
 | 
			
		||||
    );
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
    // console.log(
 | 
			
		||||
    //   'APA10\nbounds width:',
 | 
			
		||||
    //   bounds.width,
 | 
			
		||||
    //   '\nbounds height:',
 | 
			
		||||
    //   bounds.height,
 | 
			
		||||
    //   'point:',
 | 
			
		||||
    //   point.x,
 | 
			
		||||
    //   point.y,
 | 
			
		||||
    //   '\nw:',
 | 
			
		||||
    //   w,
 | 
			
		||||
    //   '\nh',
 | 
			
		||||
    //   h,
 | 
			
		||||
    //   '\ns',
 | 
			
		||||
    //   s
 | 
			
		||||
    // );
 | 
			
		||||
 | 
			
		||||
    // Define polygon points
 | 
			
		||||
    const points = [
 | 
			
		||||
      { x: s / 2, y: 0 },
 | 
			
		||||
      { x: s, y: -s / 2 },
 | 
			
		||||
      { x: s / 2, y: -s },
 | 
			
		||||
      { x: 0, y: -s / 2 },
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Calculate the intersection point
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 }; // Adjusted result
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point: Point) {
 | 
			
		||||
    return this.calcIntersect ? this.calcIntersect(node as Bounds, point) : { x: 0, y: 0 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -60,6 +61,12 @@ export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
 | 
			
		||||
  );
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import { getConfig } from '../../../diagram-api/diagramAPI.js';
 | 
			
		||||
import { createRoundedRectPathD } from './roundedRectPath.js';
 | 
			
		||||
import { log } from '../../../logger.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function rectWithTitle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -150,6 +151,12 @@ export async function rectWithTitle<T extends SVGGraphicsElement>(
 | 
			
		||||
  }
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function shadedProcess<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -63,6 +64,12 @@ export async function shadedProcess<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -54,6 +55,12 @@ export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import rough from 'roughjs';
 | 
			
		||||
import { createRoundedRectPathD } from './roundedRectPath.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createStadiumPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -88,6 +89,12 @@ export async function stadium<T extends SVGGraphicsElement>(parent: D3Selection<
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export function stateEnd<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -54,6 +55,12 @@ export function stateEnd<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, circle);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.circle(node, 7, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import { solidStateFill } from './handDrawnShapeStyles.js';
 | 
			
		||||
import { updateNodeBounds } from './util.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export function stateStart<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -33,6 +34,12 @@ export function stateStart<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, circle);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.circle(node, 7, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createSubroutinePathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -79,6 +80,12 @@ export async function subroutine<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
    updateNodeBounds(node, el);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -60,6 +61,12 @@ export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, taggedRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, rectPoints, point);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -96,6 +97,13 @@ export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, waveEdgeRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ import intersect from '../intersect/index.js';
 | 
			
		||||
import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String } from './handDrawnShapeStyles.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -29,6 +30,12 @@ export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>,
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, rect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.rect(node, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import { handleUndefinedAttr } from '../../../utils.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export const createCylinderPathD = (
 | 
			
		||||
  x: number,
 | 
			
		||||
@@ -113,6 +114,12 @@ export async function tiltedCylinder<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, cylinder);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.rect(node, point);
 | 
			
		||||
    const y = pos.y - (node.y ?? 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,21 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { insertPolygonShape } from './insertPolygonShape.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
// export const createTrapezoidPathD = (
 | 
			
		||||
//   x: number,
 | 
			
		||||
//   y: number,
 | 
			
		||||
//   width: number,
 | 
			
		||||
//   height: number
 | 
			
		||||
// ): string => {
 | 
			
		||||
//   return [
 | 
			
		||||
//     `M${x - (2 * height) / 6},${y}`,
 | 
			
		||||
//     `L${x + width + (2 * height) / 6},${y}`,
 | 
			
		||||
//     `L${x + width - height / 6},${y - height}`,
 | 
			
		||||
//     `L${x + height / 6},${y - height}`,
 | 
			
		||||
//     'Z',
 | 
			
		||||
//   ].join(' ');
 | 
			
		||||
// };
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -65,6 +51,12 @@ export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selectio
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -52,6 +53,12 @@ export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import { createPathFromPoints } from './util.js';
 | 
			
		||||
import { evaluate } from '../../../diagrams/common/common.js';
 | 
			
		||||
import { getConfig } from '../../../diagram-api/diagramAPI.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -59,6 +60,12 @@ export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection
 | 
			
		||||
    `translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))}, ${h / 2 - (bbox.height + (node.padding ?? 0) / (useHtmlLabels ? 2 : 1) - (bbox.y - (bbox.top ?? 0)))})`
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    log.info('Triangle intersect', node, points, point);
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
@@ -74,6 +75,13 @@ export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, waveEdgeRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,16 @@ import type { Node } from '../../types.js';
 | 
			
		||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function getPoints(w: number, finalH: number, waveAmplitude: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: -w / 2, y: finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
 | 
			
		||||
    { x: w / 2, y: -finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
  node: Node
 | 
			
		||||
@@ -52,12 +61,7 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
    options.fillStyle = 'solid';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: -w / 2, y: finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
 | 
			
		||||
    { x: w / 2, y: -finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getPoints(w, finalH, waveAmplitude);
 | 
			
		||||
 | 
			
		||||
  const waveRectPath = createPathFromPoints(points);
 | 
			
		||||
  const waveRectNode = rc.path(waveRectPath, options);
 | 
			
		||||
@@ -75,6 +79,18 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, waveRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
 | 
			
		||||
    const waveAmplitude = Math.min(h * 0.2, h / 4);
 | 
			
		||||
    const finalH = h + waveAmplitude * 2;
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(w, finalH, waveAmplitude);
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, points, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,16 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import intersect from '../intersect/index.js';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function getOutPathPoints(x: number, y: number, w: number, h: number, rectOffset: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: x - rectOffset, y: y - rectOffset },
 | 
			
		||||
    { x: x - rectOffset, y: y + h },
 | 
			
		||||
    { x: x + w, y: y + h },
 | 
			
		||||
    { x: x + w, y: y - rectOffset },
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
 | 
			
		||||
  const { labelStyles, nodeStyles } = styles2String(node);
 | 
			
		||||
@@ -20,12 +30,7 @@ export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
  const rc = rough.svg(shapeSvg);
 | 
			
		||||
  const options = userNodeOverrides(node, {});
 | 
			
		||||
 | 
			
		||||
  const outerPathPoints = [
 | 
			
		||||
    { x: x - rectOffset, y: y - rectOffset },
 | 
			
		||||
    { x: x - rectOffset, y: y + h },
 | 
			
		||||
    { x: x + w, y: y + h },
 | 
			
		||||
    { x: x + w, y: y - rectOffset },
 | 
			
		||||
  ];
 | 
			
		||||
  const outerPathPoints = getOutPathPoints(x, y, w, h, rectOffset);
 | 
			
		||||
 | 
			
		||||
  const path = `M${x - rectOffset},${y - rectOffset} L${x + w},${y - rectOffset} L${x + w},${y + h} L${x - rectOffset},${y + h} L${x - rectOffset},${y - rectOffset}
 | 
			
		||||
                M${x - rectOffset},${y} L${x + w},${y}
 | 
			
		||||
@@ -58,6 +63,17 @@ export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
 | 
			
		||||
  updateNodeBounds(node, windowPane);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const rectOffset = 5;
 | 
			
		||||
    const x = -w / 2;
 | 
			
		||||
    const y = -h / 2;
 | 
			
		||||
 | 
			
		||||
    const outerPathPoints = getOutPathPoints(x, y, w, h, rectOffset);
 | 
			
		||||
    return intersect.polygon(node, outerPathPoints, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    const pos = intersect.polygon(node, outerPathPoints, point);
 | 
			
		||||
    return pos;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ export type MarkdownWordType = 'normal' | 'strong' | 'em';
 | 
			
		||||
import type { MermaidConfig } from '../config.type.js';
 | 
			
		||||
import type { ClusterShapeID } from './rendering-elements/clusters.js';
 | 
			
		||||
import type { ShapeID } from './rendering-elements/shapes.js';
 | 
			
		||||
import type { Bounds, Point } from '../types.js';
 | 
			
		||||
export interface MarkdownWord {
 | 
			
		||||
  content: string;
 | 
			
		||||
  type: MarkdownWordType;
 | 
			
		||||
@@ -43,6 +44,7 @@ interface BaseNode {
 | 
			
		||||
  height?: number;
 | 
			
		||||
  // Specific properties for State Diagram nodes TODO remove and use generic properties
 | 
			
		||||
  intersect?: (point: any) => any;
 | 
			
		||||
  calcIntersect?: (bounds: Bounds, point: Point) => any;
 | 
			
		||||
 | 
			
		||||
  // Non-generic properties
 | 
			
		||||
  rx?: number; // Used for rounded corners in Rect, Ellipse, etc.Maybe it to specialized RectNode, EllipseNode, etc.
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,12 @@ export interface Point {
 | 
			
		||||
  x: number;
 | 
			
		||||
  y: number;
 | 
			
		||||
}
 | 
			
		||||
export interface Bounds {
 | 
			
		||||
  x: number;
 | 
			
		||||
  y: number;
 | 
			
		||||
  width: number;
 | 
			
		||||
  height: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TextDimensionConfig {
 | 
			
		||||
  fontSize?: number;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import type { EdgeData, Point } from '../types.js';
 | 
			
		||||
// We need to draw the lines a bit shorter to avoid drawing
 | 
			
		||||
// under any transparent markers.
 | 
			
		||||
// The offsets are calculated from the markers' dimensions.
 | 
			
		||||
const markerOffsets = {
 | 
			
		||||
export const markerOffsets = {
 | 
			
		||||
  aggregation: 18,
 | 
			
		||||
  extension: 18,
 | 
			
		||||
  composition: 18,
 | 
			
		||||
@@ -104,7 +104,6 @@ export const getLineFunctionsWithOffset = (
 | 
			
		||||
        adjustment *= DIRECTION === 'right' ? -1 : 1;
 | 
			
		||||
        offset += adjustment;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return pointTransformer(d).x + offset;
 | 
			
		||||
    },
 | 
			
		||||
    y: function (
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user