mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-22 17:56:43 +02:00
Compare commits
9 Commits
@mermaid-j
...
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}
|
n7@{ shape: rect}
|
||||||
n8@{ 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 } }
|
{ flowchart: { titleTopMargin: 0 } }
|
||||||
);
|
);
|
||||||
|
@@ -88,33 +88,84 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
---
|
---
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph s1["Untitled subgraph"]
|
%% subgraph s1["Untitled subgraph"]
|
||||||
n1["Evaluate"]
|
C{"Evaluate"}
|
||||||
n2["Option 1"]
|
%% end
|
||||||
n3["Option 2"]
|
|
||||||
n4["fa:fa-car Option 3"]
|
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
|
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"]
|
|
||||||
|
|
||||||
|
|
||||||
|
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>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
@@ -155,7 +206,7 @@ flowchart LR
|
|||||||
n8@{ shape: rect}
|
n8@{ shape: rect}
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -171,7 +222,7 @@ flowchart LR
|
|||||||
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -180,7 +231,19 @@ flowchart LR
|
|||||||
A{A} --> B & C
|
A{A} --> B & C
|
||||||
</pre
|
</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:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -198,7 +261,7 @@ flowchart LR
|
|||||||
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
kanban:
|
kanban:
|
||||||
@@ -217,81 +280,81 @@ kanban
|
|||||||
task3[💻 Develop login feature]@{ ticket: 103 }
|
task3[💻 Develop login feature]@{ ticket: 103 }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
kanban
|
kanban
|
||||||
id2[In progress]
|
id2[In progress]
|
||||||
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
kanban:
|
kanban:
|
||||||
|
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';
|
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
||||||
|
|
||||||
type Node = LayoutData['nodes'][number];
|
type Node = LayoutData['nodes'][number];
|
||||||
|
// Used to calculate distances in order to avoid floating number rounding issues when comparing floating numbers
|
||||||
|
const epsilon = 0.0001;
|
||||||
interface LabelData {
|
interface LabelData {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@@ -17,7 +18,16 @@ interface NodeWithVertex extends Omit<Node, 'domId'> {
|
|||||||
labelData?: LabelData;
|
labelData?: LabelData;
|
||||||
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
|
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 (
|
export const render = async (
|
||||||
data4Layout: LayoutData,
|
data4Layout: LayoutData,
|
||||||
svg: SVG,
|
svg: SVG,
|
||||||
@@ -60,6 +70,7 @@ export const render = async (
|
|||||||
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
||||||
const boundingBox = childNodeEl.node()!.getBBox();
|
const boundingBox = childNodeEl.node()!.getBBox();
|
||||||
child.domId = childNodeEl;
|
child.domId = childNodeEl;
|
||||||
|
child.calcIntersect = node.calcIntersect;
|
||||||
child.width = boundingBox.width;
|
child.width = boundingBox.width;
|
||||||
child.height = boundingBox.height;
|
child.height = boundingBox.height;
|
||||||
} else {
|
} else {
|
||||||
@@ -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
|
// @ts-ignore - ELK is not typed
|
||||||
const elk = new ELK();
|
const elk = new ELK();
|
||||||
const element = svg.select('g');
|
const element = svg.select('g');
|
||||||
@@ -880,9 +592,10 @@ export const render = async (
|
|||||||
setIncludeChildrenPolicy(target, ancestorId);
|
setIncludeChildrenPolicy(target, ancestorId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// const copy = JSON.parse(JSON.stringify({ ...elkGraph }));
|
||||||
|
// console.log('APA13 layout before', copy);
|
||||||
const g = await elk.layout(elkGraph);
|
const g = await elk.layout(elkGraph);
|
||||||
|
// console.log('APA13 layout', JSON.parse(JSON.stringify(g)));
|
||||||
// debugger;
|
// debugger;
|
||||||
await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
|
||||||
g.edges?.map(
|
g.edges?.map(
|
||||||
@@ -906,7 +619,7 @@ export const render = async (
|
|||||||
|
|
||||||
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
||||||
log.debug(
|
log.debug(
|
||||||
'offset',
|
'APA18 offset',
|
||||||
offset,
|
offset,
|
||||||
sourceId,
|
sourceId,
|
||||||
' ==> ',
|
' ==> ',
|
||||||
@@ -969,50 +682,59 @@ export const render = async (
|
|||||||
startNode.innerHTML
|
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
edge.points = cutPathAtIntersect(
|
if (startNode.calcIntersect) {
|
||||||
edge.points.reverse(),
|
// 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.x + startNode.width / 2 + offset.x,
|
x: startNode.offset.posX + startNode.width / 2,
|
||||||
y: startNode.y + startNode.height / 2 + offset.y,
|
y: startNode.offset.posY + startNode.height / 2,
|
||||||
width: sw,
|
width: startNode.width,
|
||||||
height: startNode.height,
|
height: startNode.height,
|
||||||
padding: startNode.padding,
|
|
||||||
},
|
},
|
||||||
startNode.shape === 'diamond' || startNode.shape === 'diam'
|
edge.points[0]
|
||||||
).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[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])
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
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(
|
const paths = insertEdge(
|
||||||
edgesEl,
|
edgesEl,
|
||||||
edge,
|
edge,
|
||||||
@@ -1022,7 +744,6 @@ export const render = async (
|
|||||||
endNode,
|
endNode,
|
||||||
data4Layout.diagramId
|
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.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
||||||
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||||
|
@@ -5,7 +5,8 @@ import { createText } from '../createText.js';
|
|||||||
import utils from '../../utils.js';
|
import utils from '../../utils.js';
|
||||||
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
|
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
|
||||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.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 rough from 'roughjs';
|
||||||
import createLabel from './createLabel.js';
|
import createLabel from './createLabel.js';
|
||||||
import { addEdgeMarkers } from './edgeMarker.ts';
|
import { addEdgeMarkers } from './edgeMarker.ts';
|
||||||
@@ -335,6 +336,40 @@ const cutPathAtIntersect = (_points, boundaryNode) => {
|
|||||||
return points;
|
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) {
|
function extractCornerPoints(points) {
|
||||||
const cornerPoints = [];
|
const cornerPoints = [];
|
||||||
const cornerPointPositions = [];
|
const cornerPointPositions = [];
|
||||||
@@ -422,6 +457,109 @@ const fixCorners = function (lineData) {
|
|||||||
return newLineData;
|
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) {
|
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
|
||||||
const { handDrawnSeed } = getConfig();
|
const { handDrawnSeed } = getConfig();
|
||||||
let points = edge.points;
|
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));
|
let lineData = points.filter((p) => !Number.isNaN(p.y));
|
||||||
|
lineData = adjustForArrowHeads(lineData, 4, edge.id === 'L_n4_C_10_0');
|
||||||
lineData = fixCorners(lineData);
|
lineData = fixCorners(lineData);
|
||||||
|
// if (edge.id === 'L_n4_C_10_0') {
|
||||||
|
// console.log('APA14 lineData', lineData);
|
||||||
|
// }
|
||||||
|
// lineData = adjustForArrowHeads(lineData);
|
||||||
let curve = curveBasis;
|
let curve = curveBasis;
|
||||||
|
// let curve = curveLinear;
|
||||||
if (edge.curve) {
|
if (edge.curve) {
|
||||||
curve = edge.curve;
|
curve = edge.curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { x, y } = getLineFunctionsWithOffset(edge);
|
const { x, y } = getLineFunctionsWithOffset(edge);
|
||||||
const lineFunction = line().x(x).y(y).curve(curve);
|
const lineFunction = line().x(x).y(y).curve(curve);
|
||||||
|
// const lineFunction = line().curve(curve);
|
||||||
|
|
||||||
let strokeClasses;
|
let strokeClasses;
|
||||||
switch (edge.thickness) {
|
switch (edge.thickness) {
|
||||||
@@ -500,6 +645,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
}
|
}
|
||||||
let svgPath;
|
let svgPath;
|
||||||
let linePath = lineFunction(lineData);
|
let linePath = lineFunction(lineData);
|
||||||
|
// let linePath = generateRoundedPath(lineData, 5);
|
||||||
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
|
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
|
||||||
if (edge.look === 'handDrawn') {
|
if (edge.look === 'handDrawn') {
|
||||||
const rc = rough.svg(elem);
|
const rc = rough.svg(elem);
|
||||||
@@ -531,21 +677,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
|
|
||||||
// DEBUG code, DO NOT REMOVE
|
// DEBUG code, DO NOT REMOVE
|
||||||
// adds a red circle at each edge coordinate
|
// adds a red circle at each edge coordinate
|
||||||
// cornerPoints.forEach((point) => {
|
// points.forEach((point) => {
|
||||||
// elem
|
// elem
|
||||||
// .append('circle')
|
// .append('circle')
|
||||||
// .style('stroke', 'blue')
|
// .style('stroke', 'red')
|
||||||
// .style('fill', 'blue')
|
// .style('fill', 'red')
|
||||||
// .attr('r', 3)
|
// .attr('r', 1)
|
||||||
// .attr('cx', point.x)
|
|
||||||
// .attr('cy', point.y);
|
|
||||||
// });
|
|
||||||
// lineData.forEach((point) => {
|
|
||||||
// elem
|
|
||||||
// .append('circle')
|
|
||||||
// .style('stroke', 'blue')
|
|
||||||
// .style('fill', 'blue')
|
|
||||||
// .attr('r', 3)
|
|
||||||
// .attr('cx', point.x)
|
// .attr('cx', point.x)
|
||||||
// .attr('cy', point.y);
|
// .attr('cy', point.y);
|
||||||
// });
|
// });
|
||||||
|
@@ -2,23 +2,21 @@
|
|||||||
* Returns the point at which two lines, p and q, intersect or returns undefined if they do not intersect.
|
* 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) {
|
function intersectLine(p1, p2, q1, q2) {
|
||||||
|
{
|
||||||
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
|
||||||
// p7 and p473.
|
// 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 +
|
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
|
||||||
// b1 y + c1 = 0.
|
// b1 y + c1 = 0.
|
||||||
a1 = p2.y - p1.y;
|
const a1 = p2.y - p1.y;
|
||||||
b1 = p1.x - p2.x;
|
const b1 = p1.x - p2.x;
|
||||||
c1 = p2.x * p1.y - p1.x * p2.y;
|
const c1 = p2.x * p1.y - p1.x * p2.y;
|
||||||
|
|
||||||
// Compute r3 and r4.
|
// Compute r3 and r4.
|
||||||
r3 = a1 * q1.x + b1 * q1.y + c1;
|
const r3 = a1 * q1.x + b1 * q1.y + c1;
|
||||||
r4 = a1 * q2.x + b1 * q2.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
|
// 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.
|
// same side of line 1, the line segments do not intersect.
|
||||||
@@ -27,39 +25,64 @@ function intersectLine(p1, p2, q1, q2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
|
// 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;
|
const a2 = q2.y - q1.y;
|
||||||
b2 = q1.x - q2.x;
|
const b2 = q1.x - q2.x;
|
||||||
c2 = q2.x * q1.y - q1.x * q2.y;
|
const c2 = q2.x * q1.y - q1.x * q2.y;
|
||||||
|
|
||||||
// Compute r1 and r2
|
// Compute r1 and r2
|
||||||
r1 = a2 * p1.x + b2 * p1.y + c2;
|
const r1 = a2 * p1.x + b2 * p1.y + c2;
|
||||||
r2 = a2 * p2.x + b2 * p2.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
|
// 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
|
// on same side of second line segment, the line segments do
|
||||||
// not intersect.
|
// not intersect.
|
||||||
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
|
||||||
return /*DON'T_INTERSECT*/;
|
return /*DON'T_INTERSECT*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line segments intersect: compute intersection point.
|
// Line segments intersect: compute intersection point.
|
||||||
denom = a1 * b2 - a2 * b1;
|
const denom = a1 * b2 - a2 * b1;
|
||||||
if (denom === 0) {
|
if (denom === 0) {
|
||||||
return /*COLLINEAR*/;
|
return /*COLLINEAR*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = Math.abs(denom / 2);
|
const offset = Math.abs(denom / 2);
|
||||||
|
|
||||||
// The denom/2 is to get rounding instead of truncating. It
|
// The denom/2 is to get rounding instead of truncating. It
|
||||||
// is added or subtracted to the numerator, depending upon the
|
// is added or subtracted to the numerator, depending upon the
|
||||||
// sign of the numerator.
|
// sign of the numerator.
|
||||||
num = b1 * c2 - b2 * c1;
|
let num = b1 * c2 - b2 * c1;
|
||||||
x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
||||||
|
|
||||||
num = a2 * c1 - a1 * c2;
|
num = a2 * c1 - a1 * c2;
|
||||||
y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
|
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 };
|
return { x: x, y: y };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sameSign(r1, r2) {
|
function sameSign(r1, r2) {
|
||||||
|
@@ -7,7 +7,7 @@ import intersectLine from './intersect-line.js';
|
|||||||
function intersectPolygon(node, polyPoints, point) {
|
function intersectPolygon(node, polyPoints, point) {
|
||||||
let x1 = node.x;
|
let x1 = node.x;
|
||||||
let y1 = node.y;
|
let y1 = node.y;
|
||||||
|
// console.trace('APA14 intersectPolygon', x1, y1, polyPoints, point);
|
||||||
let intersections = [];
|
let intersections = [];
|
||||||
|
|
||||||
let minX = Number.POSITIVE_INFINITY;
|
let minX = Number.POSITIVE_INFINITY;
|
||||||
@@ -24,7 +24,7 @@ function intersectPolygon(node, polyPoints, point) {
|
|||||||
|
|
||||||
let left = x1 - node.width / 2 - minX;
|
let left = x1 - node.width / 2 - minX;
|
||||||
let top = y1 - node.height / 2 - minY;
|
let top = y1 - node.height / 2 - minY;
|
||||||
|
// console.log('APA13 intersectPolygon2 ', left, y1);
|
||||||
for (let i = 0; i < polyPoints.length; i++) {
|
for (let i = 0; i < polyPoints.length; i++) {
|
||||||
let p1 = polyPoints[i];
|
let p1 = polyPoints[i];
|
||||||
let p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
|
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 + p1.x, y: top + p1.y },
|
||||||
{ x: left + p2.x, y: top + p2.y }
|
{ x: left + p2.x, y: top + p2.y }
|
||||||
);
|
);
|
||||||
|
// console.log('APA13 intersectPolygon3 ', intersect);
|
||||||
if (intersect) {
|
if (intersect) {
|
||||||
|
// console.log('APA13 intersectPolygon4 ', intersect);
|
||||||
intersections.push(intersect);
|
intersections.push(intersect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +44,7 @@ function intersectPolygon(node, polyPoints, point) {
|
|||||||
if (!intersections.length) {
|
if (!intersections.length) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
// console.log('APA12 intersectPolygon5 ');
|
||||||
|
|
||||||
if (intersections.length > 1) {
|
if (intersections.length > 1) {
|
||||||
// More intersections, find the one nearest to edge end point
|
// 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 qdy = q.y - point.y;
|
||||||
let distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
let distq = Math.sqrt(qdx * qdx + qdy * qdy);
|
||||||
|
|
||||||
|
// console.log('APA12 intersectPolygon6 ');
|
||||||
|
|
||||||
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
return distp < distq ? -1 : distp === distq ? 0 : 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles } = styles2String(node);
|
const { labelStyles } = styles2String(node);
|
||||||
@@ -37,6 +38,11 @@ export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
|
|||||||
|
|
||||||
updateNodeBounds(node, circleElem);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('Circle intersect', node, radius, point);
|
log.info('Circle intersect', node, radius, point);
|
||||||
return intersect.circle(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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
function generateArcPoints(
|
function generateArcPoints(
|
||||||
x1: number,
|
x1: number,
|
||||||
@@ -70,7 +71,15 @@ function generateArcPoints(
|
|||||||
|
|
||||||
return points;
|
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) {
|
export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
node.labelStyle = labelStyles;
|
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>;
|
// let shape: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
|
||||||
const { cssStyles } = node;
|
const { cssStyles } = node;
|
||||||
|
|
||||||
const points = [
|
const points = getPoints(w, h, rx, ry);
|
||||||
{ 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),
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
@@ -118,6 +121,16 @@ export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
|
|
||||||
updateNodeBounds(node, bowTieRectShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -3,17 +3,25 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '../../types.js';
|
import type { Node } from '../../types.js';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
|
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import { createPathFromPoints } from './util.js';
|
import { createPathFromPoints } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
// const createPathFromPoints = (points: { x: number; y: number }[]): string => {
|
function getPoints(w: number, h: number, padding: number) {
|
||||||
// const pointStrings = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`);
|
const left = 0;
|
||||||
// pointStrings.push('Z');
|
const right = w;
|
||||||
// return pointStrings.join(' ');
|
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) {
|
export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
node.labelStyle = labelStyles;
|
node.labelStyle = labelStyles;
|
||||||
@@ -22,18 +30,8 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
|
|||||||
const h = bbox.height + node.padding;
|
const h = bbox.height + node.padding;
|
||||||
const padding = 12;
|
const padding = 12;
|
||||||
const w = bbox.width + node.padding + padding;
|
const w = bbox.width + node.padding + padding;
|
||||||
const left = 0;
|
|
||||||
const right = w;
|
const points = getPoints(w, h, padding);
|
||||||
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 },
|
|
||||||
];
|
|
||||||
|
|
||||||
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
|
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
|
||||||
const { cssStyles } = node;
|
const { cssStyles } = node;
|
||||||
@@ -62,6 +60,17 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,15 @@ import rough from 'roughjs';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { createPathFromPoints, getNodeClasses } from './util.js';
|
import { createPathFromPoints, getNodeClasses } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { nodeStyles } = styles2String(node);
|
const { nodeStyles } = styles2String(node);
|
||||||
node.label = '';
|
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 s = Math.max(28, node.width ?? 0);
|
||||||
|
|
||||||
const points = [
|
const points = getPoints(s);
|
||||||
{ x: 0, y: s / 2 },
|
|
||||||
{ x: s / 2, y: 0 },
|
|
||||||
{ x: 0, y: -s / 2 },
|
|
||||||
{ x: -s / 2, y: 0 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
@@ -47,6 +50,13 @@ export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
|
|||||||
node.width = 28;
|
node.width = 28;
|
||||||
node.height = 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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.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) {
|
export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -35,7 +36,10 @@ export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNodeBounds(node, circleElem);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('Circle intersect', node, radius, point);
|
log.info('Circle intersect', node, radius, point);
|
||||||
return intersect.circle(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 { textHelper } from '../../../diagrams/class/shapeUtil.js';
|
||||||
import { evaluate } from '../../../diagrams/common/common.js';
|
import { evaluate } from '../../../diagrams/common/common.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
@@ -199,6 +200,9 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNodeBounds(node, rect);
|
updateNodeBounds(node, rect);
|
||||||
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
|
return intersect.rect(bounds, point);
|
||||||
|
};
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
function createLine(r: number) {
|
function createLine(r: number) {
|
||||||
const xAxis45 = Math.cos(Math.PI / 4); // cosine of 45 degrees
|
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);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('crossedCircle intersect', node, { radius, point });
|
log.info('crossedCircle intersect', node, { radius, point });
|
||||||
const pos = intersect.circle(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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
function generateCirclePoints(
|
function generateCirclePoints(
|
||||||
centerX: number,
|
centerX: number,
|
||||||
@@ -35,6 +36,21 @@ function generateCirclePoints(
|
|||||||
return points;
|
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>(
|
export async function curlyBraceLeft<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
node: Node
|
node: Node
|
||||||
@@ -57,18 +73,7 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
|
|||||||
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
|
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
|
||||||
];
|
];
|
||||||
|
|
||||||
const rectPoints = [
|
const rectPoints = getRectPoints(w, h, radius);
|
||||||
{ 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 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
@@ -105,6 +110,15 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, curlyBraceLeftShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, rectPoints, 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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
function generateCirclePoints(
|
function generateCirclePoints(
|
||||||
centerX: number,
|
centerX: number,
|
||||||
@@ -35,6 +36,21 @@ function generateCirclePoints(
|
|||||||
return points;
|
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>(
|
export async function curlyBraceRight<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
node: Node
|
node: Node
|
||||||
@@ -57,18 +73,7 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
|
|||||||
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
|
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
|
||||||
];
|
];
|
||||||
|
|
||||||
const rectPoints = [
|
const rectPoints = getRectPoints(w, h, radius);
|
||||||
{ 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 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
@@ -105,6 +110,15 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, curlyBraceRightShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, rectPoints, 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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
function generateCirclePoints(
|
function generateCirclePoints(
|
||||||
centerX: number,
|
centerX: number,
|
||||||
@@ -35,6 +36,25 @@ function generateCirclePoints(
|
|||||||
return points;
|
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>(
|
export async function curlyBraces<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
node: Node
|
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),
|
...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
|
||||||
];
|
];
|
||||||
|
|
||||||
const rectPoints = [
|
const rectPoints = getRectPoints(w, h, radius);
|
||||||
{ 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),
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
@@ -124,6 +127,15 @@ export async function curlyBraces<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, curlyBracesShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, rectPoints, 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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
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>(
|
export async function curvedTrapezoid<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -39,14 +49,7 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
|
|||||||
const rw = totalWidth - radius;
|
const rw = totalWidth - radius;
|
||||||
const tw = totalHeight / 4;
|
const tw = totalHeight / 4;
|
||||||
|
|
||||||
const points = [
|
const points = getTrapezoidPoints(rw, tw, totalHeight, radius);
|
||||||
{ 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 pathData = createPathFromPoints(points);
|
const pathData = createPathFromPoints(points);
|
||||||
const shapeNode = rc.path(pathData, options);
|
const shapeNode = rc.path(pathData, options);
|
||||||
@@ -66,6 +69,20 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createCylinderPathD = (
|
export const createCylinderPathD = (
|
||||||
x: number,
|
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))})`
|
`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) {
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
const pos = intersect.rect(node, point);
|
const w = bounds.width;
|
||||||
const x = pos.x - (node.x ?? 0);
|
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 (
|
if (
|
||||||
rx != 0 &&
|
rx != 0 &&
|
||||||
(Math.abs(x) < (node.width ?? 0) / 2 ||
|
(Math.abs(x) < (w ?? 0) / 2 ||
|
||||||
(Math.abs(x) == (node.width ?? 0) / 2 &&
|
(Math.abs(x) == (w ?? 0) / 2 && Math.abs(pos.y - (bounds.y ?? 0)) > (h ?? 0) / 2 - ry))
|
||||||
Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
|
|
||||||
) {
|
) {
|
||||||
let y = ry * ry * (1 - (x * x) / (rx * rx));
|
let y = ry * ry * (1 - (x * x) / (rx * rx));
|
||||||
if (y > 0) {
|
if (y > 0) {
|
||||||
y = Math.sqrt(y);
|
y = Math.sqrt(y);
|
||||||
}
|
}
|
||||||
y = ry - y;
|
y = ry - y;
|
||||||
if (point.y - (node.y ?? 0) > 0) {
|
if (point.y - (bounds.y ?? 0) > 0) {
|
||||||
y = -y;
|
y = -y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,5 +124,14 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
|
|||||||
return pos;
|
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;
|
return shapeSvg;
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function dividedRectangle<T extends SVGGraphicsElement>(
|
export async function dividedRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -62,6 +63,10 @@ export async function dividedRectangle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
|
return intersect.rect(bounds, point);
|
||||||
|
};
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.rect(node, point);
|
const pos = intersect.rect(node, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createCylinderPathD = (
|
export const createCylinderPathD = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -91,29 +92,36 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
|
|||||||
|
|
||||||
updateNodeBounds(node, cylinder);
|
updateNodeBounds(node, cylinder);
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
const pos = intersect.rect(node, point);
|
const pos = intersect.rect(bounds, point);
|
||||||
const x = pos.x - (node.x ?? 0);
|
const x = pos.x - (bounds.x ?? 0);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
rx != 0 &&
|
rx != 0 &&
|
||||||
(Math.abs(x) < (node.width ?? 0) / 2 ||
|
(Math.abs(x) < (bounds.width ?? 0) / 2 ||
|
||||||
(Math.abs(x) == (node.width ?? 0) / 2 &&
|
(Math.abs(x) == (bounds.width ?? 0) / 2 &&
|
||||||
Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
|
Math.abs(pos.y - (bounds.y ?? 0)) > (bounds.height ?? 0) / 2 - ry))
|
||||||
) {
|
) {
|
||||||
let y = ry * ry * (1 - (x * x) / (rx * rx));
|
let y = ry * ry * (1 - (x * x) / (rx * rx));
|
||||||
if (y != 0) {
|
if (y != 0) {
|
||||||
y = Math.sqrt(y);
|
y = Math.sqrt(y);
|
||||||
}
|
}
|
||||||
y = ry - y;
|
y = ry - y;
|
||||||
if (point.y - (node.y ?? 0) > 0) {
|
if (point.y - (bounds.y ?? 0) > 0) {
|
||||||
y = -y;
|
y = -y;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos.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;
|
return shapeSvg;
|
||||||
|
@@ -6,6 +6,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function doublecircle<T extends SVGGraphicsElement>(
|
export async function doublecircle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -62,6 +63,11 @@ export async function doublecircle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, circleGroup);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('DoubleCircle intersect', node, outerRadius, point);
|
log.info('DoubleCircle intersect', node, outerRadius, point);
|
||||||
return intersect.circle(node, outerRadius, point);
|
return intersect.circle(node, outerRadius, point);
|
||||||
|
@@ -6,6 +6,7 @@ import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function drawRect<T extends SVGGraphicsElement>(
|
export async function drawRect<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -62,6 +63,10 @@ export async function drawRect<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, rect);
|
updateNodeBounds(node, rect);
|
||||||
|
|
||||||
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
|
return intersect.rect(bounds, point);
|
||||||
|
};
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { getNodeClasses, updateNodeBounds } from './util.js';
|
import { getNodeClasses, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export function filledCircle<T extends SVGGraphicsElement>(
|
export function filledCircle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -46,6 +47,11 @@ export function filledCircle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, filledCircle);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('filledCircle intersect', node, { radius, point });
|
log.info('filledCircle intersect', node, { radius, point });
|
||||||
const pos = intersect.circle(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 rough from 'roughjs';
|
||||||
import { createPathFromPoints } from './util.js';
|
import { createPathFromPoints } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.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>(
|
export async function flippedTriangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -19,11 +28,7 @@ export async function flippedTriangle<T extends SVGGraphicsElement>(
|
|||||||
const h = w + bbox.height;
|
const h = w + bbox.height;
|
||||||
|
|
||||||
const tw = w + bbox.height;
|
const tw = w + bbox.height;
|
||||||
const points = [
|
const points = getPoints(tw, h);
|
||||||
{ x: 0, y: -h },
|
|
||||||
{ x: tw, y: -h },
|
|
||||||
{ x: tw / 2, y: 0 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const { cssStyles } = node;
|
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))})`
|
`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) {
|
node.intersect = function (point) {
|
||||||
log.info('Triangle intersect', node, points, point);
|
log.info('Triangle intersect', node, points, point);
|
||||||
return intersect.polygon(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 { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { getNodeClasses, updateNodeBounds } from './util.js';
|
import { getNodeClasses, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export function forkJoin<T extends SVGGraphicsElement>(
|
export function forkJoin<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -59,6 +60,10 @@ export function forkJoin<T extends SVGGraphicsElement>(
|
|||||||
node.width += padding / 2 || 0;
|
node.width += padding / 2 || 0;
|
||||||
node.height += padding / 2 || 0;
|
node.height += padding / 2 || 0;
|
||||||
}
|
}
|
||||||
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
|
return intersect.rect(bounds, point);
|
||||||
|
};
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -11,6 +11,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
|
export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -63,6 +64,12 @@ export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('Pill intersect', node, { radius, point });
|
log.info('Pill intersect', node, { radius, point });
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createHexagonPathD = (
|
export const createHexagonPathD = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -72,6 +73,12 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
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) {
|
export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(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
|
// 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) {
|
node.intersect = function (point) {
|
||||||
log.info('Pill intersect', node, { points });
|
log.info('Pill intersect', node, { points });
|
||||||
const pos = intersect.polygon(node, points, point);
|
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 { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function icon<T extends SVGGraphicsElement>(
|
export async function icon<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -97,6 +98,12 @@ export async function icon<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, outerShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('iconSquare intersect', node, point);
|
log.info('iconSquare intersect', node, point);
|
||||||
if (!node.label) {
|
if (!node.label) {
|
||||||
|
@@ -6,6 +6,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function iconCircle<T extends SVGGraphicsElement>(
|
export async function iconCircle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -94,6 +95,12 @@ export async function iconCircle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, outerShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('iconSquare intersect', node, point);
|
log.info('iconSquare intersect', node, point);
|
||||||
const pos = intersect.rect(node, point);
|
const pos = intersect.rect(node, point);
|
||||||
|
@@ -7,6 +7,7 @@ import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShap
|
|||||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function iconRounded<T extends SVGGraphicsElement>(
|
export async function iconRounded<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -104,6 +105,12 @@ export async function iconRounded<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, outerShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('iconSquare intersect', node, point);
|
log.info('iconSquare intersect', node, point);
|
||||||
if (!node.label) {
|
if (!node.label) {
|
||||||
|
@@ -7,6 +7,7 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
|
|||||||
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function iconSquare<T extends SVGGraphicsElement>(
|
export async function iconSquare<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -104,6 +105,12 @@ export async function iconSquare<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, outerShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('iconSquare intersect', node, point);
|
log.info('iconSquare intersect', node, point);
|
||||||
if (!node.label) {
|
if (!node.label) {
|
||||||
|
@@ -5,6 +5,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function imageSquare<T extends SVGGraphicsElement>(
|
export async function imageSquare<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -108,6 +109,12 @@ export async function imageSquare<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, outerShape);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('iconSquare intersect', node, point);
|
log.info('iconSquare intersect', node, point);
|
||||||
if (!node.label) {
|
if (!node.label) {
|
||||||
|
@@ -5,21 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } 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(' ');
|
|
||||||
// };
|
|
||||||
|
|
||||||
export async function inv_trapezoid<T extends SVGGraphicsElement>(
|
export async function inv_trapezoid<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -70,6 +56,12 @@ export async function inv_trapezoid<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
|
|||||||
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
|
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
const colorFromPriority = (priority: NonNullable<KanbanNode['priority']>) => {
|
const colorFromPriority = (priority: NonNullable<KanbanNode['priority']>) => {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
@@ -155,6 +156,12 @@ export async function kanbanItem<T extends SVGGraphicsElement>(
|
|||||||
updateNodeBounds(kanbanNode, rect);
|
updateNodeBounds(kanbanNode, rect);
|
||||||
kanbanNode.height = totalHeight;
|
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) {
|
kanbanNode.intersect = function (point) {
|
||||||
return intersect.rect(kanbanNode, point);
|
return intersect.rect(kanbanNode, point);
|
||||||
};
|
};
|
||||||
|
@@ -3,6 +3,7 @@ import { drawRect } from './drawRect.js';
|
|||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function roundedRect<T extends SVGGraphicsElement>(
|
export async function roundedRect<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -48,8 +49,12 @@ export async function labelRect<T extends SVGGraphicsElement>(parent: D3Selectio
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -50,6 +51,12 @@ export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selectio
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -49,8 +50,59 @@ export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
return intersect.polygon(node, points, 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;
|
return shapeSvg;
|
||||||
|
@@ -6,7 +6,17 @@ import rough from 'roughjs';
|
|||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import { createPathFromPoints } from './util.js';
|
import { createPathFromPoints } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
node.label = '';
|
node.label = '';
|
||||||
@@ -55,11 +65,21 @@ export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<
|
|||||||
|
|
||||||
updateNodeBounds(node, lightningBolt);
|
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) {
|
node.intersect = function (point) {
|
||||||
log.info('lightningBolt intersect', node, 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;
|
return shapeSvg;
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createCylinderPathD = (
|
export const createCylinderPathD = (
|
||||||
x: number,
|
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))})`
|
`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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.rect(node, point);
|
const pos = intersect.rect(node, point);
|
||||||
const x = pos.x - (node.x ?? 0);
|
const x = pos.x - (node.x ?? 0);
|
||||||
|
@@ -9,6 +9,7 @@ import type { Node } from '../../types.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
|
export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -74,6 +75,13 @@ export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateNodeBounds(node, waveEdgeRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -4,6 +4,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -74,6 +75,12 @@ export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selectio
|
|||||||
|
|
||||||
updateNodeBounds(node, multiRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, outerPathPoints, point);
|
const pos = intersect.polygon(node, outerPathPoints, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -99,6 +100,12 @@ export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, shape);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, outerPathPoints, point);
|
const pos = intersect.polygon(node, outerPathPoints, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { getConfig } from '../../../config.js';
|
import { getConfig } from '../../../config.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function note<T extends SVGGraphicsElement>(
|
export async function note<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -52,6 +53,12 @@ export async function note<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { log } from '../../../logger.js';
|
|
||||||
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { Node } from '../../types.js';
|
import type { Node } from '../../types.js';
|
||||||
@@ -6,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
|
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
|
||||||
return [
|
return [
|
||||||
@@ -59,17 +59,41 @@ export async function question<T extends SVGGraphicsElement>(parent: D3Selection
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
updateNodeBounds(node, polygon);
|
||||||
|
node.calcIntersect = function (bounds: Bounds, point: Point) {
|
||||||
|
const s = bounds.width;
|
||||||
|
|
||||||
node.intersect = function (point) {
|
// console.log(
|
||||||
log.debug(
|
// 'APA10\nbounds width:',
|
||||||
'APA12 Intersect called SPLIT\npoint:',
|
// bounds.width,
|
||||||
point,
|
// '\nbounds height:',
|
||||||
'\nnode:\n',
|
// bounds.height,
|
||||||
node,
|
// 'point:',
|
||||||
'\nres:',
|
// point.x,
|
||||||
intersect.polygon(node, points, point)
|
// point.y,
|
||||||
);
|
// '\nw:',
|
||||||
return intersect.polygon(node, points, point);
|
// 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;
|
return shapeSvg;
|
||||||
|
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
|
export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -60,6 +61,12 @@ export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
|
|||||||
);
|
);
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -10,6 +10,7 @@ import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
|||||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
import { log } from '../../../logger.js';
|
import { log } from '../../../logger.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function rectWithTitle<T extends SVGGraphicsElement>(
|
export async function rectWithTitle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -150,6 +151,12 @@ export async function rectWithTitle<T extends SVGGraphicsElement>(
|
|||||||
}
|
}
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function shadedProcess<T extends SVGGraphicsElement>(
|
export async function shadedProcess<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -63,6 +64,12 @@ export async function shadedProcess<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
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) {
|
export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -54,6 +55,12 @@ export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -6,6 +6,7 @@ import rough from 'roughjs';
|
|||||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createStadiumPathD = (
|
export const createStadiumPathD = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -88,6 +89,12 @@ export async function stadium<T extends SVGGraphicsElement>(parent: D3Selection<
|
|||||||
|
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import { updateNodeBounds } from './util.js';
|
import { updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export function stateEnd<T extends SVGGraphicsElement>(
|
export function stateEnd<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -54,6 +55,12 @@ export function stateEnd<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, circle);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.circle(node, 7, point);
|
return intersect.circle(node, 7, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import { solidStateFill } from './handDrawnShapeStyles.js';
|
import { solidStateFill } from './handDrawnShapeStyles.js';
|
||||||
import { updateNodeBounds } from './util.js';
|
import { updateNodeBounds } from './util.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export function stateStart<T extends SVGGraphicsElement>(
|
export function stateStart<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -33,6 +34,12 @@ export function stateStart<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, circle);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.circle(node, 7, point);
|
return intersect.circle(node, 7, point);
|
||||||
};
|
};
|
||||||
|
@@ -6,6 +6,7 @@ import rough from 'roughjs';
|
|||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createSubroutinePathD = (
|
export const createSubroutinePathD = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -79,6 +80,12 @@ export async function subroutine<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
updateNodeBounds(node, el);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -60,6 +61,12 @@ export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
|
|
||||||
updateNodeBounds(node, taggedRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, rectPoints, point);
|
const pos = intersect.polygon(node, rectPoints, point);
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -96,6 +97,13 @@ export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateNodeBounds(node, waveEdgeRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -3,6 +3,7 @@ import intersect from '../intersect/index.js';
|
|||||||
import type { Node } from '../../types.js';
|
import type { Node } from '../../types.js';
|
||||||
import { styles2String } from './handDrawnShapeStyles.js';
|
import { styles2String } from './handDrawnShapeStyles.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -29,6 +30,12 @@ export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>,
|
|||||||
|
|
||||||
updateNodeBounds(node, rect);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.rect(node, point);
|
return intersect.rect(node, point);
|
||||||
};
|
};
|
||||||
|
@@ -5,6 +5,7 @@ import rough from 'roughjs';
|
|||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
import { handleUndefinedAttr } from '../../../utils.js';
|
import { handleUndefinedAttr } from '../../../utils.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export const createCylinderPathD = (
|
export const createCylinderPathD = (
|
||||||
x: number,
|
x: number,
|
||||||
@@ -113,6 +114,12 @@ export async function tiltedCylinder<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, cylinder);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.rect(node, point);
|
const pos = intersect.rect(node, point);
|
||||||
const y = pos.y - (node.y ?? 0);
|
const y = pos.y - (node.y ?? 0);
|
||||||
|
@@ -5,21 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } 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(' ');
|
|
||||||
// };
|
|
||||||
|
|
||||||
export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
@@ -65,6 +51,12 @@ export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selectio
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,7 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
|
export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -52,6 +53,12 @@ export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
|
|||||||
|
|
||||||
updateNodeBounds(node, polygon);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -8,6 +8,7 @@ import { createPathFromPoints } from './util.js';
|
|||||||
import { evaluate } from '../../../diagrams/common/common.js';
|
import { evaluate } from '../../../diagrams/common/common.js';
|
||||||
import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(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)))})`
|
`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) {
|
node.intersect = function (point) {
|
||||||
log.info('Triangle intersect', node, points, point);
|
log.info('Triangle intersect', node, points, point);
|
||||||
return intersect.polygon(node, points, point);
|
return intersect.polygon(node, points, point);
|
||||||
|
@@ -10,6 +10,7 @@ import type { Node } from '../../types.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import type { D3Selection } from '../../../types.js';
|
import type { D3Selection } from '../../../types.js';
|
||||||
|
import type { Bounds, Point } from '../../../types.js';
|
||||||
|
|
||||||
export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
|
export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
@@ -74,6 +75,13 @@ export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateNodeBounds(node, waveEdgeRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -10,7 +10,16 @@ import type { Node } from '../../types.js';
|
|||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import type { D3Selection } from '../../../types.js';
|
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>(
|
export async function waveRectangle<T extends SVGGraphicsElement>(
|
||||||
parent: D3Selection<T>,
|
parent: D3Selection<T>,
|
||||||
node: Node
|
node: Node
|
||||||
@@ -52,12 +61,7 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
|
|||||||
options.fillStyle = 'solid';
|
options.fillStyle = 'solid';
|
||||||
}
|
}
|
||||||
|
|
||||||
const points = [
|
const points = getPoints(w, finalH, waveAmplitude);
|
||||||
{ 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 waveRectPath = createPathFromPoints(points);
|
const waveRectPath = createPathFromPoints(points);
|
||||||
const waveRectNode = rc.path(waveRectPath, options);
|
const waveRectNode = rc.path(waveRectPath, options);
|
||||||
@@ -75,6 +79,18 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNodeBounds(node, waveRect);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, points, point);
|
const pos = intersect.polygon(node, points, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -4,6 +4,16 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { D3Selection } from '../../../types.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) {
|
export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||||
const { labelStyles, nodeStyles } = styles2String(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 rc = rough.svg(shapeSvg);
|
||||||
const options = userNodeOverrides(node, {});
|
const options = userNodeOverrides(node, {});
|
||||||
|
|
||||||
const outerPathPoints = [
|
const outerPathPoints = getOutPathPoints(x, y, w, h, rectOffset);
|
||||||
{ 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 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}
|
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}
|
M${x - rectOffset},${y} L${x + w},${y}
|
||||||
@@ -58,6 +63,17 @@ export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selecti
|
|||||||
|
|
||||||
updateNodeBounds(node, windowPane);
|
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) {
|
node.intersect = function (point) {
|
||||||
const pos = intersect.polygon(node, outerPathPoints, point);
|
const pos = intersect.polygon(node, outerPathPoints, point);
|
||||||
return pos;
|
return pos;
|
||||||
|
@@ -2,6 +2,7 @@ export type MarkdownWordType = 'normal' | 'strong' | 'em';
|
|||||||
import type { MermaidConfig } from '../config.type.js';
|
import type { MermaidConfig } from '../config.type.js';
|
||||||
import type { ClusterShapeID } from './rendering-elements/clusters.js';
|
import type { ClusterShapeID } from './rendering-elements/clusters.js';
|
||||||
import type { ShapeID } from './rendering-elements/shapes.js';
|
import type { ShapeID } from './rendering-elements/shapes.js';
|
||||||
|
import type { Bounds, Point } from '../types.js';
|
||||||
export interface MarkdownWord {
|
export interface MarkdownWord {
|
||||||
content: string;
|
content: string;
|
||||||
type: MarkdownWordType;
|
type: MarkdownWordType;
|
||||||
@@ -43,6 +44,7 @@ interface BaseNode {
|
|||||||
height?: number;
|
height?: number;
|
||||||
// Specific properties for State Diagram nodes TODO remove and use generic properties
|
// Specific properties for State Diagram nodes TODO remove and use generic properties
|
||||||
intersect?: (point: any) => any;
|
intersect?: (point: any) => any;
|
||||||
|
calcIntersect?: (bounds: Bounds, point: Point) => any;
|
||||||
|
|
||||||
// Non-generic properties
|
// Non-generic properties
|
||||||
rx?: number; // Used for rounded corners in Rect, Ellipse, etc.Maybe it to specialized RectNode, EllipseNode, etc.
|
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;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
export interface Bounds {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TextDimensionConfig {
|
export interface TextDimensionConfig {
|
||||||
fontSize?: number;
|
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
|
// We need to draw the lines a bit shorter to avoid drawing
|
||||||
// under any transparent markers.
|
// under any transparent markers.
|
||||||
// The offsets are calculated from the markers' dimensions.
|
// The offsets are calculated from the markers' dimensions.
|
||||||
const markerOffsets = {
|
export const markerOffsets = {
|
||||||
aggregation: 18,
|
aggregation: 18,
|
||||||
extension: 18,
|
extension: 18,
|
||||||
composition: 18,
|
composition: 18,
|
||||||
@@ -104,7 +104,6 @@ export const getLineFunctionsWithOffset = (
|
|||||||
adjustment *= DIRECTION === 'right' ? -1 : 1;
|
adjustment *= DIRECTION === 'right' ? -1 : 1;
|
||||||
offset += adjustment;
|
offset += adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointTransformer(d).x + offset;
|
return pointTransformer(d).x + offset;
|
||||||
},
|
},
|
||||||
y: function (
|
y: function (
|
||||||
|
Reference in New Issue
Block a user