Compare commits

..

15 Commits

Author SHA1 Message Date
Justin Greywolf
4693aa2749 Merge branch 'develop' into 5824-diff-between-markdown-and-strings 2024-12-02 14:45:11 -08:00
Justin Greywolf
468b6a55b6 Update cypress/integration/rendering/flowchart.spec.js
Co-authored-by: Sidharth Vinod <github@sidharth.dev>
2024-12-02 14:43:55 -08:00
Sidharth Vinod
df636c6d0a Merge pull request #6001 from michaelbaudino/patch-1
Fix a configuration example in `gantt.md`
2024-11-28 09:10:56 +05:30
Ashish Jain
64554a6c60 Merge pull request #6092 from mermaid-js/master
Merge back master to develop
2024-11-27 18:24:31 +01:00
Knut Sveidqvist
becadf0a7d Merge pull request #6091 from mermaid-js/changeset-release/master
Version Packages
2024-11-27 18:14:40 +01:00
Sidharth Vinod
54d485f173 Merge branch 'develop' into patch-1 2024-11-27 21:50:42 +05:30
Ashish Jain
b4f5b8ddaf Update CHANGELOG.md 2024-11-27 17:13:25 +01:00
github-actions[bot]
cb5c1ae367 Version Packages 2024-11-27 16:10:54 +00:00
Knut Sveidqvist
b29081d4e8 Merge pull request #6090 from mermaid-js/hotfix/elk-0.1.7
Hotfix/elk 0.1.7
2024-11-27 17:08:48 +01:00
Knut Sveidqvist
654097c438 Added changeset 2024-11-27 17:05:58 +01:00
Knut Sveidqvist
1e672868c4 #6088 Updated offset calculations 2024-11-27 17:05:58 +01:00
Knut Sveidqvist
c7880d7281 Adding changeset 2024-11-27 13:02:36 +01:00
Knut Sveidqvist
f27ca07371 Adding back create label for the cases where you do not want markdown text 2024-11-27 12:38:08 +01:00
autofix-ci[bot]
8cb1c68166 [autofix.ci] apply automated fixes 2024-10-29 13:09:54 +01:00
Michael Baudino
d752240efc Fix a configuration example in gantt.md
According to the [config schema docs](https://mermaid.js.org/config/schema-docs/config-defs-gantt-diagram-config.html#tickinterval-constraints), Gantt's `tickInterval` configuration must match the following regular expression, which does **not** allow any space:

```regexp
/^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/
```
2024-10-29 13:09:54 +01:00
75 changed files with 671 additions and 1161 deletions

View File

@@ -0,0 +1,5 @@
---
'mermaid': patch
---
fix: Proper separation between strings and markdown strings

View File

@@ -1,5 +0,0 @@
---
'@mermaid-js/layout-elk': patch
---
fix: Updated offset calculations for diamond shape when handling intersections

View File

@@ -895,7 +895,7 @@ graph TD
imgSnapshotTest(
`
graph TD
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
hello --> default
`,
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
@@ -917,4 +917,24 @@ graph TD
}
);
});
it('68: should be able to render string and markdown labels (#5824)', () => {
imgSnapshotTest(
`
flowchart TB
mermaid{"What is\nyourmermaid version?"} --> v10["<11"] --"\`<**1**1\`"--> fine["No bug"]
mermaid --> v11[">= v11"] -- ">= v11" --> broken["Affected by https://github.com/mermaid-js/mermaid/issues/5824"]
subgraph subgraph1["\`How to fix **fix**\`"]
broken --> B["B"]
end
githost["Github, Gitlab, BitBucket, etc."]
githost2["\`Github, Gitlab, BitBucket, etc.\`"]
a["1."]
b["- x"]
`,
{
flowchart: { htmlLabels: true },
securityLevel: 'loose',
}
);
});
});

View File

@@ -90,29 +90,6 @@
<body>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
flowchart LR
%% subgraph s1["Untitled subgraph"]
C{"Evaluate"}
%% end
B --> C
</pre>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
flowchart LR
%% A ==> B
%% A2 --> B2
D --> I((I the Circle))
D --> I
</pre>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
@@ -123,9 +100,9 @@ config:
end
D -- Mermaid js --> I(("fa:fa-code Text"))
D -- Mermaid js --> I{"fa:fa-code Text"}
D --> I
D --> I
D --> E --> I
end
</pre>
@@ -167,7 +144,7 @@ config:
D-->I
D-->I
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -208,19 +185,19 @@ flowchart LR
</pre>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
title: https://github.com/mermaid-js/mermaid/issues/5824
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
end
n1 -- One --> n2
%% 6048, 5824
flowchart TB
mermaid{"What is\nyourmermaid version?"} --> v10["<11"] --"`<**1**1`"--> fine["No bug"]
mermaid --> v11[">= v11"] -- ">= v11" --> broken["Affected by https://github.com/mermaid-js/mermaid/issues/5824"]
subgraph subgraph1["`How to fix **fix**`"]
broken --> B["B"]
end
githost["Github, Gitlab, BitBucket, etc."]
githost2["`Github, Gitlab, BitBucket, etc.`"]
a["1."]
b["- x"]
</pre>
<pre id="diagram4" class="mermaid">
---
@@ -261,7 +238,7 @@ flowchart LR
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
kanban:
@@ -280,81 +257,81 @@ kanban
task3[💻 Develop login feature]@{ ticket: 103 }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
kanban
id2[In progress]
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
kanban:

View File

@@ -1,102 +0,0 @@
<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>

View File

@@ -500,7 +500,7 @@ mermaid.ganttConfig = {
sectionFontSize: 24, // Font size for sections
numberSectionStyles: 1, // The number of alternating section styles
axisFormat: '%d/%m', // Date/time format of the axis
tickInterval: '1 week', // Axis ticks
tickInterval: '1week', // Axis ticks
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
displayMode: 'compact', // Turns compact mode on
weekday: 'sunday', // On which day a week-based interval should start

View File

@@ -1,5 +1,11 @@
# @mermaid-js/layout-elk
## 0.1.7
### Patch Changes
- [#6090](https://github.com/mermaid-js/mermaid/pull/6090) [`654097c`](https://github.com/mermaid-js/mermaid/commit/654097c43801b2d606bc3d2bef8c6fbc3301e9e4) Thanks [@knsv](https://github.com/knsv)! - fix: Updated offset calculations for diamond shape when handling intersections
## 0.1.6
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@mermaid-js/layout-elk",
"version": "0.1.6",
"version": "0.1.7",
"description": "ELK layout engine for mermaid",
"module": "dist/mermaid-layout-elk.core.mjs",
"types": "dist/layouts.d.ts",

View File

@@ -4,8 +4,7 @@ import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from '
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
type Node = LayoutData['nodes'][number];
// Used to calculate distances in order to avoid floating number rounding issues when comparing floating numbers
const epsilon = 0.0001;
interface LabelData {
width: number;
height: number;
@@ -18,16 +17,7 @@ interface NodeWithVertex extends Omit<Node, 'domId'> {
labelData?: LabelData;
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
}
interface Point {
x: number;
y: number;
}
function distance(p1?: Point, p2?: Point): number {
if (!p1 || !p2) {
return 0;
}
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
export const render = async (
data4Layout: LayoutData,
svg: SVG,
@@ -70,7 +60,6 @@ export const render = async (
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
const boundingBox = childNodeEl.node()!.getBBox();
child.domId = childNodeEl;
child.calcIntersect = node.calcIntersect;
child.width = boundingBox.width;
child.height = boundingBox.height;
} else {
@@ -470,6 +459,302 @@ 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('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
const points: any[] = [];
let lastPointOutside = _points[0];
let isInside = false;
_points.forEach((point: any) => {
// check if point is inside the boundary rect
if (!outsideNode(bounds, point) && !isInside) {
// First point inside the rect found
// Calc the intersection coord between the point anf the last point outside the rect
let inter;
if (isDiamond) {
const inter2 = diamondIntersection(bounds, lastPointOutside, point);
const distance = Math.sqrt(
(lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2
);
if (distance > 1) {
inter = inter2;
}
}
if (!inter) {
inter = intersection(bounds, lastPointOutside, point);
}
// Check case where the intersection is the same as the last point
let pointPresent = false;
points.forEach((p) => {
pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
});
// if (!pointPresent) {
if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
points.push(inter);
} else {
log.debug('abc88 no intersect', inter, points);
}
// points.push(inter);
isInside = true;
} else {
// Outside
log.debug('abc88 outside', point, lastPointOutside, points);
lastPointOutside = point;
// points.push(point);
if (!isInside) {
points.push(point);
}
}
});
return points;
};
// @ts-ignore - ELK is not typed
const elk = new ELK();
const element = svg.select('g');
@@ -592,10 +877,9 @@ export const render = async (
setIncludeChildrenPolicy(target, ancestorId);
}
});
// const copy = JSON.parse(JSON.stringify({ ...elkGraph }));
// console.log('APA13 layout before', copy);
const g = await elk.layout(elkGraph);
// console.log('APA13 layout', JSON.parse(JSON.stringify(g)));
// debugger;
await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
g.edges?.map(
@@ -682,59 +966,43 @@ export const render = async (
startNode.innerHTML
);
}
if (startNode.calcIntersect) {
// console.log(
// 'APA13 calculating start intersection start node',
// startNode.id,
// startNode.x,
// startNode.y,
// 'w:',
// startNode.width,
// 'h:',
// startNode.height,
// '\nPos',
// edge.points[0]
// );
const intersection = startNode.calcIntersect(
{
x: startNode.offset.posX + startNode.width / 2,
y: startNode.offset.posY + startNode.height / 2,
width: startNode.width,
height: startNode.height,
},
edge.points[0]
);
if (distance(intersection, edge.points[0]) > epsilon) {
edge.points.unshift(intersection);
}
if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
edge.points.unshift({
x: startNode.offset.posX + startNode.width / 2,
y: startNode.offset.posY + startNode.height / 2,
});
}
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);
}
if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
edge.points.push({
x: endNode.offset.posX + endNode.width / 2,
y: endNode.offset.posY + endNode.height / 2,
});
}
edge.points = cutPathAtIntersect(
edge.points.reverse(),
{
x: startNode.offset.posX + startNode.width / 2,
y: startNode.offset.posY + startNode.height / 2,
width: sw,
height: startNode.height,
padding: startNode.padding,
},
startNode.shape === 'diamond' || startNode.shape === 'diam'
).reverse();
edge.points = cutPathAtIntersect(
edge.points,
{
x: endNode.offset.posX + endNode.width / 2,
y: endNode.offset.posY + endNode.height / 2,
width: ew,
height: endNode.height,
padding: endNode.padding,
},
endNode.shape === 'diamond' || endNode.shape === 'diam'
);
const paths = insertEdge(
edgesEl,
edge,
@@ -744,6 +1012,7 @@ export const render = async (
endNode,
data4Layout.diagramId
);
log.info('APA12 edge points after insert', JSON.stringify(edge.points));
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;

View File

@@ -896,6 +896,7 @@ const addNodeFromVertex = (
const baseNode = {
id: vertex.id,
label: vertex.text,
labelType: vertex.labelType,
labelStyle: '',
parentId,
padding: config.flowchart?.padding || 8,
@@ -1002,6 +1003,7 @@ export const getData = () => {
end: rawEdge.end,
type: rawEdge.type ?? 'normal',
label: rawEdge.text,
labelType: rawEdge.labelType,
labelpos: 'c',
thickness: rawEdge.stroke,
minlen: rawEdge.length,

View File

@@ -390,7 +390,7 @@ mermaid.ganttConfig = {
sectionFontSize: 24, // Font size for sections
numberSectionStyles: 1, // The number of alternating section styles
axisFormat: '%d/%m', // Date/time format of the axis
tickInterval: '1 week', // Axis ticks
tickInterval: '1week', // Axis ticks
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
displayMode: 'compact', // Turns compact mode on
weekday: 'sunday', // On which day a week-based interval should start

View File

@@ -5,8 +5,7 @@ import { createText } from '../createText.js';
import utils from '../../utils.js';
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { curveBasis, curveLinear, line, select } from 'd3';
import { curveBasis, line, select } from 'd3';
import rough from 'roughjs';
import createLabel from './createLabel.js';
import { addEdgeMarkers } from './edgeMarker.ts';
@@ -27,12 +26,16 @@ export const getLabelStyles = (styleArray) => {
export const insertEdgeLabel = async (elem, edge) => {
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
const labelElement = await createText(elem, edge.label, {
style: getLabelStyles(edge.labelStyle),
useHtmlLabels,
addSvgBackground: true,
isNode: false,
});
const labelElement =
edge.labelType === 'markdown'
? await createText(elem, edge.label, {
style: getLabelStyles(edge.labelStyle),
useHtmlLabels,
addSvgBackground: true,
isNode: false,
})
: await createLabel(edge.label, getLabelStyles(edge.labelStyle), undefined, false);
log.info('abc82', edge, edge.labelType);
// Create outer g, edgeLabel, this will be positioned after graph layout
@@ -336,40 +339,6 @@ const cutPathAtIntersect = (_points, boundaryNode) => {
return points;
};
const adjustForArrowHeads = function (lineData, size = 5, shouldLog = false) {
const newLineData = [...lineData];
const lastPoint = lineData[lineData.length - 1];
const secondLastPoint = lineData[lineData.length - 2];
const distanceBetweenLastPoints = Math.sqrt(
(lastPoint.x - secondLastPoint.x) ** 2 + (lastPoint.y - secondLastPoint.y) ** 2
);
if (shouldLog) {
log.debug('APA14 distanceBetweenLastPoints', distanceBetweenLastPoints);
}
if (distanceBetweenLastPoints < size) {
// Calculate the direction vector from the last point to the second last point
const directionX = secondLastPoint.x - lastPoint.x;
const directionY = secondLastPoint.y - lastPoint.y;
// Normalize the direction vector
const magnitude = Math.sqrt(directionX ** 2 + directionY ** 2);
const normalizedX = directionX / magnitude;
const normalizedY = directionY / magnitude;
// Calculate the new position for the second last point
const adjustedSecondLastPoint = {
x: lastPoint.x + normalizedX * size,
y: lastPoint.y + normalizedY * size,
};
// Replace the second last point in the new line data
newLineData[newLineData.length - 2] = adjustedSecondLastPoint;
}
return newLineData;
};
function extractCornerPoints(points) {
const cornerPoints = [];
const cornerPointPositions = [];
@@ -457,109 +426,6 @@ const fixCorners = function (lineData) {
return newLineData;
};
export const generateRoundedPath = (points, radius, endPosition) => {
if (points.length < 2) {
return '';
}
// console.trace('here', points);
const path = [];
const startPoint = points[0];
path.push(`M ${startPoint.x},${startPoint.y}`);
for (let i = 1; i < points.length - 1; i++) {
const currPoint = points[i];
const nextPoint = points[i + 1];
const prevPoint = points[i - 1];
// Calculate vectors
const v1 = { x: currPoint.x - prevPoint.x, y: currPoint.y - prevPoint.y };
const v2 = { x: nextPoint.x - currPoint.x, y: nextPoint.y - currPoint.y };
// Normalize vectors
const v1Length = Math.hypot(v1.x, v1.y);
const v2Length = Math.hypot(v2.x, v2.y);
const v1Normalized = { x: v1.x / v1Length, y: v1.y / v1Length };
const v2Normalized = { x: v2.x / v2Length, y: v2.y / v2Length };
// Calculate tangent points
const tangentLength = Math.min(radius, v1Length / 2, v2Length / 2);
const tangent1 = {
x: currPoint.x - v1Normalized.x * tangentLength,
y: currPoint.y - v1Normalized.y * tangentLength,
};
const tangent2 = {
x: currPoint.x + v2Normalized.x * tangentLength,
y: currPoint.y + v2Normalized.y * tangentLength,
};
if (endPosition) {
const { bottomY, leftX, rightX, topY } = endPosition;
if (startPoint.pos === 'b' && tangent1.y > topY) {
tangent1.y = topY;
tangent2.y = topY;
currPoint.y = topY;
}
if (startPoint.pos === 't' && tangent1.y < bottomY) {
tangent1.y = bottomY;
tangent2.y = bottomY;
currPoint.y = bottomY;
}
if (startPoint.pos === 'l' && tangent1.x < rightX) {
tangent1.x = rightX;
tangent2.x = rightX;
currPoint.x = rightX;
}
if (startPoint.pos === 'r' && tangent1.x > leftX) {
tangent1.x = leftX;
tangent2.x = leftX;
currPoint.x = leftX;
}
if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
path.push(
`L ${tangent1.x},${tangent1.y}`,
`Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
);
}
} else {
if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
path.push(
`L ${tangent1.x},${tangent1.y}`,
`Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
);
}
}
}
// Last point
const lastPoint = points[points.length - 1];
if (endPosition) {
if (startPoint.pos === 'b') {
if (endPosition?.topY && points[1].y > endPosition?.topY && points[2].y > endPosition?.topY) {
points[1].y = endPosition?.topY;
points[2].y = endPosition?.topY;
}
path.push(`L ${lastPoint.x},${endPosition.topY}`);
}
if (startPoint.pos === 't') {
if (points[1].y < endPosition.bottomY) {
points[1].y = endPosition.bottomY;
points[2].y = endPosition.bottomY;
}
path.push(`L ${lastPoint.x},${endPosition.bottomY}`);
}
if (startPoint.pos === 'l') {
path.push(`L ${endPosition.rightX},${lastPoint.y}`);
}
if (startPoint.pos === 'r') {
path.push(`L ${endPosition.leftX},${lastPoint.y}`);
}
} else {
path.push(`L ${lastPoint.x},${lastPoint.y}`);
}
return path.join(' ');
};
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
const { handDrawnSeed } = getConfig();
let points = edge.points;
@@ -600,21 +466,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
}
let lineData = points.filter((p) => !Number.isNaN(p.y));
lineData = adjustForArrowHeads(lineData, 4, edge.id === 'L_n4_C_10_0');
lineData = fixCorners(lineData);
// if (edge.id === 'L_n4_C_10_0') {
// console.log('APA14 lineData', lineData);
// }
// lineData = adjustForArrowHeads(lineData);
let curve = curveBasis;
// let curve = curveLinear;
if (edge.curve) {
curve = edge.curve;
}
const { x, y } = getLineFunctionsWithOffset(edge);
const lineFunction = line().x(x).y(y).curve(curve);
// const lineFunction = line().curve(curve);
let strokeClasses;
switch (edge.thickness) {
@@ -645,7 +504,6 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
}
let svgPath;
let linePath = lineFunction(lineData);
// let linePath = generateRoundedPath(lineData, 5);
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
if (edge.look === 'handDrawn') {
const rc = rough.svg(elem);
@@ -677,12 +535,21 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
// DEBUG code, DO NOT REMOVE
// adds a red circle at each edge coordinate
// points.forEach((point) => {
// cornerPoints.forEach((point) => {
// elem
// .append('circle')
// .style('stroke', 'red')
// .style('fill', 'red')
// .attr('r', 1)
// .style('stroke', 'blue')
// .style('fill', 'blue')
// .attr('r', 3)
// .attr('cx', point.x)
// .attr('cy', point.y);
// });
// lineData.forEach((point) => {
// elem
// .append('circle')
// .style('stroke', 'blue')
// .style('fill', 'blue')
// .attr('r', 3)
// .attr('cx', point.x)
// .attr('cy', point.y);
// });

View File

@@ -2,87 +2,64 @@
* Returns the point at which two lines, p and q, intersect or returns undefined if they do not intersect.
*/
function intersectLine(p1, p2, q1, q2) {
{
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
// p7 and p473.
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
// p7 and p473.
// 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;
var a1, a2, b1, b2, c1, c2;
var r1, r2, r3, r4;
var denom, offset, num;
var x, y;
// Compute r3 and r4.
const r3 = a1 * q1.x + b1 * q1.y + c1;
const r4 = a1 * q2.x + b1 * q2.y + c1;
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
// b1 y + c1 = 0.
a1 = p2.y - p1.y;
b1 = p1.x - p2.x;
c1 = p2.x * p1.y - p1.x * p2.y;
const epsilon = 1e-6;
// Compute r3 and r4.
r3 = a1 * q1.x + b1 * q1.y + c1;
r4 = a1 * q2.x + b1 * q2.y + c1;
// Check signs of r3 and r4. If both point 3 and point 4 lie on
// same side of line 1, the line segments do not intersect.
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
return /*DON'T_INTERSECT*/;
}
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
const a2 = q2.y - q1.y;
const b2 = q1.x - q2.x;
const c2 = q2.x * q1.y - q1.x * q2.y;
// Compute r1 and r2
const r1 = a2 * p1.x + b2 * p1.y + c2;
const r2 = a2 * p2.x + b2 * p2.y + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie
// on same side of second line segment, the line segments do
// not intersect.
if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
return /*DON'T_INTERSECT*/;
}
// Line segments intersect: compute intersection point.
const denom = a1 * b2 - a2 * b1;
if (denom === 0) {
return /*COLLINEAR*/;
}
const offset = Math.abs(denom / 2);
// The denom/2 is to get rounding instead of truncating. It
// is added or subtracted to the numerator, depending upon the
// sign of the numerator.
let num = b1 * c2 - b2 * c1;
const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
num = a2 * c1 - a1 * c2;
const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
// console.log(
// 'APA13 intersectLine intersection',
// '\np1: (',
// p1.x,
// p1.y,
// ')',
// '\np2: (',
// p2.x,
// p2.y,
// ')',
// '\nq1: (',
// q1.x,
// q1.y,
// ')',
// '\np1: (',
// q2.x,
// q2.y,
// ')',
// 'offset:',
// offset,
// '\nintersection: (',
// x,
// y,
// ')'
// );
return { x: x, y: y };
// 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
a2 = q2.y - q1.y;
b2 = q1.x - q2.x;
c2 = q2.x * q1.y - q1.x * q2.y;
// Compute r1 and r2
r1 = a2 * p1.x + b2 * p1.y + c2;
r2 = a2 * p2.x + b2 * p2.y + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie
// on same side of second line segment, the line segments do
// not intersect.
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
return /*DON'T_INTERSECT*/;
}
// Line segments intersect: compute intersection point.
denom = a1 * b2 - a2 * b1;
if (denom === 0) {
return /*COLLINEAR*/;
}
offset = Math.abs(denom / 2);
// The denom/2 is to get rounding instead of truncating. It
// is added or subtracted to the numerator, depending upon the
// sign of the numerator.
num = b1 * c2 - b2 * c1;
x = num < 0 ? (num - offset) / denom : (num + offset) / denom;
num = a2 * c1 - a1 * c2;
y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
return { x: x, y: y };
}
function sameSign(r1, r2) {

View File

@@ -7,7 +7,7 @@ import intersectLine from './intersect-line.js';
function intersectPolygon(node, polyPoints, point) {
let x1 = node.x;
let y1 = node.y;
// console.trace('APA14 intersectPolygon', x1, y1, polyPoints, point);
let intersections = [];
let minX = Number.POSITIVE_INFINITY;
@@ -24,7 +24,7 @@ function intersectPolygon(node, polyPoints, point) {
let left = x1 - node.width / 2 - minX;
let top = y1 - node.height / 2 - minY;
// console.log('APA13 intersectPolygon2 ', left, y1);
for (let i = 0; i < polyPoints.length; i++) {
let p1 = polyPoints[i];
let p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
@@ -34,9 +34,7 @@ function intersectPolygon(node, polyPoints, point) {
{ x: left + p1.x, y: top + p1.y },
{ x: left + p2.x, y: top + p2.y }
);
// console.log('APA13 intersectPolygon3 ', intersect);
if (intersect) {
// console.log('APA13 intersectPolygon4 ', intersect);
intersections.push(intersect);
}
}
@@ -44,7 +42,6 @@ function intersectPolygon(node, polyPoints, point) {
if (!intersections.length) {
return node;
}
// console.log('APA12 intersectPolygon5 ');
if (intersections.length > 1) {
// More intersections, find the one nearest to edge end point
@@ -57,8 +54,6 @@ function intersectPolygon(node, polyPoints, point) {
let qdy = q.y - point.y;
let distq = Math.sqrt(qdx * qdx + qdy * qdy);
// console.log('APA12 intersectPolygon6 ');
return distp < distq ? -1 : distp === distq ? 0 : 1;
});
}

View File

@@ -6,7 +6,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { handleUndefinedAttr } from '../../../utils.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles } = styles2String(node);
@@ -38,11 +37,6 @@ export function anchor<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
updateNodeBounds(node, circleElem);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('Circle intersect', node, radius, point);
return intersect.circle(node, radius, point);

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function generateArcPoints(
x1: number,
@@ -71,15 +70,7 @@ function generateArcPoints(
return points;
}
function getPoints(w: number, h: number, rx: number, ry: number) {
return [
{ x: w / 2, y: -h / 2 },
{ x: -w / 2, y: -h / 2 },
...generateArcPoints(-w / 2, -h / 2, -w / 2, h / 2, rx, ry, false),
{ x: w / 2, y: h / 2 },
...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true),
];
}
export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
@@ -93,7 +84,13 @@ export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selecti
// let shape: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
const points = getPoints(w, h, rx, ry);
const points = [
{ x: w / 2, y: -h / 2 },
{ x: -w / 2, y: -h / 2 },
...generateArcPoints(-w / 2, -h / 2, -w / 2, h / 2, rx, ry, false),
{ x: w / 2, y: h / 2 },
...generateArcPoints(w / 2, h / 2, w / 2, -h / 2, rx, ry, true),
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
@@ -121,16 +118,6 @@ export async function bowTieRect<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, bowTieRectShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const ry = h / 2;
const rx = ry / (2.5 + h / 50);
const points = getPoints(w, h, rx, ry);
return intersect.polygon(bounds, points, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -3,25 +3,17 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getPoints(w: number, h: number, padding: number) {
const left = 0;
const right = w;
const top = -h;
const bottom = 0;
return [
{ x: left + padding, y: top },
{ x: right, y: top },
{ x: right, y: bottom },
{ x: left, y: bottom },
{ x: left, y: top + padding },
{ x: left + padding, y: top },
];
}
// const createPathFromPoints = (points: { x: number; y: number }[]): string => {
// const pointStrings = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`);
// pointStrings.push('Z');
// return pointStrings.join(' ');
// };
export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
@@ -30,8 +22,18 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
const h = bbox.height + node.padding;
const padding = 12;
const w = bbox.width + node.padding + padding;
const points = getPoints(w, h, padding);
const left = 0;
const right = w;
const top = -h;
const bottom = 0;
const points = [
{ x: left + padding, y: top },
{ x: right, y: top },
{ x: right, y: bottom },
{ x: left, y: bottom },
{ x: left, y: top + padding },
{ x: left + padding, y: top },
];
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
const { cssStyles } = node;
@@ -60,17 +62,6 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const h = bounds.height;
const padding = 12;
const w = bounds.width;
const points = getPoints(w, h, padding);
const res = intersect.polygon(bounds, points, point);
return { x: res.x - 0.5, y: res.y - 0.5 };
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -4,15 +4,7 @@ import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { createPathFromPoints, getNodeClasses } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getPoints(s: number) {
return [
{ x: 0, y: s / 2 },
{ x: s / 2, y: 0 },
{ x: 0, y: -s / 2 },
{ x: -s / 2, y: 0 },
];
}
export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { nodeStyles } = styles2String(node);
node.label = '';
@@ -24,7 +16,12 @@ export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
const s = Math.max(28, node.width ?? 0);
const points = getPoints(s);
const points = [
{ 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
const rc = rough.svg(shapeSvg);
@@ -50,13 +47,6 @@ export function choice<T extends SVGGraphicsElement>(parent: D3Selection<T>, nod
node.width = 28;
node.height = 28;
node.calcIntersect = function (bounds: Bounds, point: Point) {
const s = Math.max(28, bounds.width ?? 0);
const points = getPoints(s);
return intersect.circle(bounds, points, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -6,7 +6,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -36,10 +35,7 @@ export async function circle<T extends SVGGraphicsElement>(parent: D3Selection<T
}
updateNodeBounds(node, circleElem);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('Circle intersect', node, radius, point);
return intersect.circle(node, radius, point);

View File

@@ -9,7 +9,6 @@ import intersect from '../intersect/index.js';
import { textHelper } from '../../../diagrams/class/shapeUtil.js';
import { evaluate } from '../../../diagrams/common/common.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const config = getConfig();
@@ -200,9 +199,6 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
}
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
return intersect.rect(bounds, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function createLine(r: number) {
const xAxis45 = Math.cos(Math.PI / 4); // cosine of 45 degrees
@@ -58,11 +57,6 @@ export function crossedCircle<T extends SVGGraphicsElement>(parent: D3Selection<
updateNodeBounds(node, crossedCircle);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const radius = Math.max(30, bounds?.width ?? 0);
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('crossedCircle intersect', node, { radius, point });
const pos = intersect.circle(node, radius, point);

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@@ -36,21 +35,6 @@ function generateCirclePoints(
return points;
}
function getRectPoints(w: number, h: number, radius: number) {
return [
{ x: w / 2, y: -h / 2 - radius },
{ x: -w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: -w / 2 - radius, y: -radius },
...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180),
{ x: -w / 2 - radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: -w / 2, y: h / 2 + radius },
{ x: w / 2, y: h / 2 + radius },
];
}
export async function curlyBraceLeft<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
@@ -73,7 +57,18 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
];
const rectPoints = getRectPoints(w, h, radius);
const rectPoints = [
{ x: w / 2, y: -h / 2 - radius },
{ x: -w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: -w / 2 - radius, y: -radius },
...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180),
{ x: -w / 2 - radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: -w / 2, y: h / 2 + radius },
{ x: w / 2, y: h / 2 + radius },
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
@@ -110,15 +105,6 @@ export async function curlyBraceLeft<T extends SVGGraphicsElement>(
updateNodeBounds(node, curlyBraceLeftShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const radius = Math.max(5, h * 0.1);
const rectPoints = getRectPoints(w, h, radius);
return intersect.polygon(bounds, rectPoints, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, rectPoints, point);

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@@ -36,21 +35,6 @@ function generateCirclePoints(
return points;
}
function getRectPoints(w: number, h: number, radius: number) {
return [
{ x: -w / 2, y: -h / 2 - radius },
{ x: w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: w / 2 + radius, y: -radius },
...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
{ x: w / 2 + radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: w / 2, y: h / 2 + radius },
{ x: -w / 2, y: h / 2 + radius },
];
}
export async function curlyBraceRight<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
@@ -73,7 +57,18 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
];
const rectPoints = getRectPoints(w, h, radius);
const rectPoints = [
{ x: -w / 2, y: -h / 2 - radius },
{ x: w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: w / 2 + radius, y: -radius },
...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
{ x: w / 2 + radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: w / 2, y: h / 2 + radius },
{ x: -w / 2, y: h / 2 + radius },
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
@@ -110,15 +105,6 @@ export async function curlyBraceRight<T extends SVGGraphicsElement>(
updateNodeBounds(node, curlyBraceRightShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const radius = Math.max(5, h * 0.1);
const rectPoints = getRectPoints(w, h, radius);
return intersect.polygon(bounds, rectPoints, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, rectPoints, point);

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function generateCirclePoints(
centerX: number,
@@ -36,25 +35,6 @@ function generateCirclePoints(
return points;
}
const getRectPoints = (w: number, h: number, radius: number) => [
{ x: w / 2, y: -h / 2 - radius },
{ x: -w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: -w / 2 - radius, y: -radius },
...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
{ x: -w / 2 - radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: -w / 2, y: h / 2 + radius },
{ x: w / 2 - radius - radius / 2, y: h / 2 + radius },
...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180),
{ x: w / 2 - radius / 2, y: radius },
...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90),
...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0),
{ x: w / 2 - radius / 2, y: -radius },
...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
];
export async function curlyBraces<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
@@ -86,7 +66,24 @@ export async function curlyBraces<T extends SVGGraphicsElement>(
...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
];
const rectPoints = getRectPoints(w, h, radius);
const rectPoints = [
{ x: w / 2, y: -h / 2 - radius },
{ x: -w / 2, y: -h / 2 - radius },
...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0),
{ x: -w / 2 - radius, y: -radius },
...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270),
...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180),
{ x: -w / 2 - radius, y: h / 2 },
...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90),
{ x: -w / 2, y: h / 2 + radius },
{ x: w / 2 - radius - radius / 2, y: h / 2 + radius },
...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180),
{ x: w / 2 - radius / 2, y: radius },
...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90),
...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0),
{ x: w / 2 - radius / 2, y: -radius },
...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270),
];
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
const rc = rough.svg(shapeSvg);
@@ -127,15 +124,6 @@ export async function curlyBraces<T extends SVGGraphicsElement>(
updateNodeBounds(node, curlyBracesShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const radius = Math.max(5, h * 0.1);
const rectPoints = getRectPoints(w, h, radius);
return intersect.polygon(bounds, rectPoints, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, rectPoints, point);

View File

@@ -10,16 +10,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
const getTrapezoidPoints = (rw: number, tw: number, totalHeight: number, radius: number) => [
{ x: rw, y: 0 },
{ x: tw, y: 0 },
{ x: 0, y: totalHeight / 2 },
{ x: tw, y: totalHeight },
{ x: rw, y: totalHeight },
...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90),
];
export async function curvedTrapezoid<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -49,7 +39,14 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
const rw = totalWidth - radius;
const tw = totalHeight / 4;
const points = getTrapezoidPoints(rw, tw, totalHeight, radius);
const points = [
{ x: rw, y: 0 },
{ x: tw, y: 0 },
{ x: 0, y: totalHeight / 2 },
{ x: tw, y: totalHeight },
{ x: rw, y: totalHeight },
...generateCirclePoints(-rw, -totalHeight / 2, radius, 50, 270, 90),
];
const pathData = createPathFromPoints(points);
const shapeNode = rc.path(pathData, options);
@@ -69,20 +66,6 @@ export async function curvedTrapezoid<T extends SVGGraphicsElement>(
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const radius = h / 2;
const totalWidth = w,
totalHeight = h;
const rw = totalWidth - radius;
const tw = totalHeight / 4;
const points = getTrapezoidPoints(rw, tw, totalHeight, radius);
return intersect.polygon(bounds, points, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createCylinderPathD = (
x: number,
@@ -97,24 +96,22 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
`translate(${-(bbox.width / 2) - (bbox.x - (bbox.left ?? 0))}, ${-(bbox.height / 2) + (node.padding ?? 0) / 1.5 - (bbox.y - (bbox.top ?? 0))})`
);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const rx = w / 2;
const ry = rx / (2.5 + w / 50);
const h = bounds.height;
const pos = intersect.rect(bounds, point);
const x = pos.x - (bounds.x ?? 0);
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const x = pos.x - (node.x ?? 0);
if (
rx != 0 &&
(Math.abs(x) < (w ?? 0) / 2 ||
(Math.abs(x) == (w ?? 0) / 2 && Math.abs(pos.y - (bounds.y ?? 0)) > (h ?? 0) / 2 - ry))
(Math.abs(x) < (node.width ?? 0) / 2 ||
(Math.abs(x) == (node.width ?? 0) / 2 &&
Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
) {
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y > 0) {
y = Math.sqrt(y);
}
y = ry - y;
if (point.y - (bounds.y ?? 0) > 0) {
if (point.y - (node.y ?? 0) > 0) {
y = -y;
}
@@ -124,14 +121,5 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
return pos;
};
node.intersect = function (point: Point) {
return this.calcIntersect
? this.calcIntersect(
{ x: node.x ?? 0, y: node.y ?? 0, width: node.width ?? 0, height: node.height ?? 0 },
point
)
: { x: 0, y: 0 };
};
return shapeSvg;
}

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function dividedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -63,10 +62,6 @@ export async function dividedRectangle<T extends SVGGraphicsElement>(
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
return intersect.rect(bounds, point);
};
node.intersect = function (point) {
const pos = intersect.rect(node, point);
return pos;

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createCylinderPathD = (
x: number,
@@ -92,36 +91,29 @@ export async function cylinder<T extends SVGGraphicsElement>(parent: D3Selection
updateNodeBounds(node, cylinder);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const pos = intersect.rect(bounds, point);
const x = pos.x - (bounds.x ?? 0);
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const x = pos.x - (node.x ?? 0);
if (
rx != 0 &&
(Math.abs(x) < (bounds.width ?? 0) / 2 ||
(Math.abs(x) == (bounds.width ?? 0) / 2 &&
Math.abs(pos.y - (bounds.y ?? 0)) > (bounds.height ?? 0) / 2 - ry))
(Math.abs(x) < (node.width ?? 0) / 2 ||
(Math.abs(x) == (node.width ?? 0) / 2 &&
Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
) {
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y != 0) {
y = Math.sqrt(y);
}
y = ry - y;
if (point.y - (bounds.y ?? 0) > 0) {
if (point.y - (node.y ?? 0) > 0) {
y = -y;
}
pos.y += y;
}
};
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 pos;
};
return shapeSvg;

View File

@@ -6,7 +6,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export async function doublecircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -63,11 +62,6 @@ export async function doublecircle<T extends SVGGraphicsElement>(
updateNodeBounds(node, circleGroup);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('DoubleCircle intersect', node, outerRadius, point);
return intersect.circle(node, outerRadius, point);

View File

@@ -6,7 +6,6 @@ import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export async function drawRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -63,10 +62,6 @@ export async function drawRect<T extends SVGGraphicsElement>(
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
return intersect.rect(bounds, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -5,7 +5,6 @@ import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export function filledCircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -47,11 +46,6 @@ export function filledCircle<T extends SVGGraphicsElement>(
updateNodeBounds(node, filledCircle);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('filledCircle intersect', node, { radius, point });
const pos = intersect.circle(node, radius, point);

View File

@@ -6,15 +6,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getPoints(tw: number, h: number) {
return [
{ x: 0, y: -h },
{ x: tw, y: -h },
{ x: tw / 2, y: 0 },
];
}
export async function flippedTriangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -28,7 +19,11 @@ export async function flippedTriangle<T extends SVGGraphicsElement>(
const h = w + bbox.height;
const tw = w + bbox.height;
const points = getPoints(tw, h);
const points = [
{ x: 0, y: -h },
{ x: tw, y: -h },
{ x: tw / 2, y: 0 },
];
const { cssStyles } = node;
@@ -64,16 +59,6 @@ export async function flippedTriangle<T extends SVGGraphicsElement>(
`translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))}, ${-h / 2 + (node.padding ?? 0) / 2 + (bbox.y - (bbox.top ?? 0))})`
);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const w = bounds.width;
const h = bounds.height;
const tw = w + bounds.height;
const points = getPoints(tw, h);
return intersect.polygon(node, points, point);
};
node.intersect = function (point) {
log.info('Triangle intersect', node, points, point);
return intersect.polygon(node, points, point);

View File

@@ -4,7 +4,6 @@ import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export function forkJoin<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -60,10 +59,6 @@ export function forkJoin<T extends SVGGraphicsElement>(
node.width += padding / 2 || 0;
node.height += padding / 2 || 0;
}
node.calcIntersect = function (bounds: Bounds, point: Point) {
return intersect.rect(bounds, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -11,7 +11,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -64,12 +63,6 @@ export async function halfRoundedRectangle<T extends SVGGraphicsElement>(
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('Pill intersect', node, { radius, point });
const pos = intersect.polygon(node, points, point);

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export const createHexagonPathD = (
x: number,
@@ -73,12 +72,6 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -5,7 +5,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -53,18 +52,6 @@ export async function hourglass<T extends SVGGraphicsElement>(parent: D3Selectio
// label.attr('transform', `translate(${-bbox.width / 2}, ${(h/2)})`); // To transform text below hourglass shape
node.calcIntersect = function (bounds: Bounds, point: Point) {
const { width: w, height: h } = bounds;
const points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
{ x: 0, y: h },
{ x: w, y: h },
];
const res = intersect.polygon(bounds, points, point);
return { x: res.x - 0.5, y: res.y - 0.5 };
};
node.intersect = function (point) {
log.info('Pill intersect', node, { points });
const pos = intersect.polygon(node, points, point);

View File

@@ -6,7 +6,6 @@ import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function icon<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -98,12 +97,6 @@ export async function icon<T extends SVGGraphicsElement>(
updateNodeBounds(node, outerShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('iconSquare intersect', node, point);
if (!node.label) {

View File

@@ -6,7 +6,6 @@ import intersect from '../intersect/index.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function iconCircle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -95,12 +94,6 @@ export async function iconCircle<T extends SVGGraphicsElement>(
updateNodeBounds(node, outerShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('iconSquare intersect', node, point);
const pos = intersect.rect(node, point);

View File

@@ -7,7 +7,6 @@ import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShap
import { createRoundedRectPathD } from './roundedRectPath.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function iconRounded<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -105,12 +104,6 @@ export async function iconRounded<T extends SVGGraphicsElement>(
updateNodeBounds(node, outerShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('iconSquare intersect', node, point);
if (!node.label) {

View File

@@ -7,7 +7,6 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function iconSquare<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -105,12 +104,6 @@ export async function iconSquare<T extends SVGGraphicsElement>(
updateNodeBounds(node, outerShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('iconSquare intersect', node, point);
if (!node.label) {

View File

@@ -5,7 +5,6 @@ import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function imageSquare<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -109,12 +108,6 @@ export async function imageSquare<T extends SVGGraphicsElement>(
updateNodeBounds(node, outerShape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('iconSquare intersect', node, point);
if (!node.label) {

View File

@@ -5,7 +5,21 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
// export const 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>(
parent: D3Selection<T>,
@@ -56,12 +70,6 @@ export async function inv_trapezoid<T extends SVGGraphicsElement>(
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -5,7 +5,6 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
const colorFromPriority = (priority: NonNullable<KanbanNode['priority']>) => {
switch (priority) {
@@ -156,12 +155,6 @@ export async function kanbanItem<T extends SVGGraphicsElement>(
updateNodeBounds(kanbanNode, rect);
kanbanNode.height = totalHeight;
kanbanNode.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
kanbanNode.intersect = function (point) {
return intersect.rect(kanbanNode, point);
};

View File

@@ -3,7 +3,6 @@ import { drawRect } from './drawRect.js';
import { labelHelper, updateNodeBounds } from './util.js';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function roundedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -49,12 +48,8 @@ export async function labelRect<T extends SVGGraphicsElement>(parent: D3Selectio
// }
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.width = 1;
// node.height = 1;
node.intersect = function (point) {
return intersect.rect(node, point);

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -51,12 +50,6 @@ export async function lean_left<T extends SVGGraphicsElement>(parent: D3Selectio
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -50,59 +49,8 @@ export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const dx = h / 2;
const z = w - h;
// (w = dx+z+dx)
const points = [
{ x: -dx, y: 0 },
{ x: z, y: 0 },
{ x: z + dx, y: -h },
{ x: 0, y: -h },
];
const res = intersect.polygon(bounds, points, point);
// if (node.id === 'C') {
// console.log(
// 'APA14!',
// bounds.x,
// bounds.x,
// bounds.width,
// '\nw:',
// w,
// points,
// '\nExternal point: ',
// '(',
// point.x,
// point.y,
// ')\nIntersection:',
// res
// );
// }
return { x: res.x - 0.5, y: res.y - 0.5 };
};
node.intersect = function (point: Point) {
const res = intersect.polygon(node, points, point);
// if (node.id === 'C') {
// console.log(
// 'APA14!!',
// node.x,
// node.y,
// '\nw:',
// node.width,
// points,
// '\nExternal point: ',
// '(',
// point.x,
// point.y,
// ')\nIntersection:',
// res
// );
// }
return res;
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
return shapeSvg;

View File

@@ -6,17 +6,7 @@ import rough from 'roughjs';
import intersect from '../intersect/index.js';
import { createPathFromPoints } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getPoints(width: number, height: number, gapX: number, gapY: number) {
return [
{ x: width, y: 0 },
{ x: 0, y: height / 2 + gapY / 2 },
{ x: width - 4 * gapX, y: height / 2 + gapY / 2 },
{ x: 0, y: height },
{ x: width, y: height / 2 - gapY / 2 },
{ x: 4 * gapX, y: height / 2 - gapY / 2 },
];
}
export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
node.label = '';
@@ -65,21 +55,11 @@ export function lightningBolt<T extends SVGGraphicsElement>(parent: D3Selection<
updateNodeBounds(node, lightningBolt);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const { width: w, height: h } = bounds;
const gapX = Math.max(5, w * 0.1);
const gapY = Math.max(5, h * 0.1);
const p = getPoints(w, h, gapX, gapY);
const res = intersect.polygon(bounds, p, point);
return { x: res.x - 0.5, y: res.y - 0.5 };
};
node.intersect = function (point) {
log.info('lightningBolt intersect', node, point);
const res = intersect.polygon(node, points, point);
const pos = intersect.polygon(node, points, point);
return res;
return pos;
};
return shapeSvg;

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createCylinderPathD = (
x: number,
@@ -111,12 +110,6 @@ export async function linedCylinder<T extends SVGGraphicsElement>(
`translate(${-(bbox.width / 2) - (bbox.x - (bbox.left ?? 0))}, ${-(bbox.height / 2) + ry - (bbox.y - (bbox.top ?? 0))})`
);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const x = pos.x - (node.x ?? 0);

View File

@@ -9,7 +9,6 @@ import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -75,13 +74,6 @@ export async function linedWaveEdgedRect<T extends SVGGraphicsElement>(
);
updateNodeBounds(node, waveEdgeRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -4,7 +4,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -75,12 +74,6 @@ export async function multiRect<T extends SVGGraphicsElement>(parent: D3Selectio
updateNodeBounds(node, multiRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, outerPathPoints, point);
return pos;

View File

@@ -10,7 +10,6 @@ import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -100,12 +99,6 @@ export async function multiWaveEdgedRectangle<T extends SVGGraphicsElement>(
updateNodeBounds(node, shape);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, outerPathPoints, point);
return pos;

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import { getConfig } from '../../../config.js';
import type { Bounds, Point } from '../../../types.js';
export async function note<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -53,12 +52,6 @@ export async function note<T extends SVGGraphicsElement>(
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -1,3 +1,4 @@
import { log } from '../../../logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
@@ -5,7 +6,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
return [
@@ -59,41 +59,17 @@ export async function question<T extends SVGGraphicsElement>(parent: D3Selection
}
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const s = bounds.width;
// console.log(
// 'APA10\nbounds width:',
// bounds.width,
// '\nbounds height:',
// bounds.height,
// 'point:',
// point.x,
// point.y,
// '\nw:',
// w,
// '\nh',
// h,
// '\ns',
// s
// );
// Define polygon points
const points = [
{ x: s / 2, y: 0 },
{ x: s, y: -s / 2 },
{ x: s / 2, y: -s },
{ x: 0, y: -s / 2 },
];
// Calculate the intersection point
const res = intersect.polygon(bounds, points, point);
return { x: res.x - 0.5, y: res.y - 0.5 }; // Adjusted result
};
node.intersect = function (point: Point) {
return this.calcIntersect ? this.calcIntersect(node as Bounds, point) : { x: 0, y: 0 };
node.intersect = function (point) {
log.debug(
'APA12 Intersect called SPLIT\npoint:',
point,
'\nnode:\n',
node,
'\nres:',
intersect.polygon(node, points, point)
);
return intersect.polygon(node, points, point);
};
return shapeSvg;

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -61,12 +60,6 @@ export async function rect_left_inv_arrow<T extends SVGGraphicsElement>(
);
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -10,7 +10,6 @@ import { getConfig } from '../../../diagram-api/diagramAPI.js';
import { createRoundedRectPathD } from './roundedRectPath.js';
import { log } from '../../../logger.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function rectWithTitle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -151,12 +150,6 @@ export async function rectWithTitle<T extends SVGGraphicsElement>(
}
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -5,7 +5,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export async function shadedProcess<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -64,12 +63,6 @@ export async function shadedProcess<T extends SVGGraphicsElement>(
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -55,12 +54,6 @@ export async function slopedRect<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -6,7 +6,6 @@ import rough from 'roughjs';
import { createRoundedRectPathD } from './roundedRectPath.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createStadiumPathD = (
x: number,
@@ -89,12 +88,6 @@ export async function stadium<T extends SVGGraphicsElement>(parent: D3Selection<
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -4,7 +4,6 @@ import intersect from '../intersect/index.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import { updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export function stateEnd<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -55,12 +54,6 @@ export function stateEnd<T extends SVGGraphicsElement>(
updateNodeBounds(node, circle);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.circle(node, 7, point);
};

View File

@@ -4,7 +4,6 @@ import intersect from '../intersect/index.js';
import { solidStateFill } from './handDrawnShapeStyles.js';
import { updateNodeBounds } from './util.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export function stateStart<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -34,12 +33,6 @@ export function stateStart<T extends SVGGraphicsElement>(
updateNodeBounds(node, circle);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.circle(node, 7, point);
};

View File

@@ -6,7 +6,6 @@ import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createSubroutinePathD = (
x: number,
@@ -80,12 +79,6 @@ export async function subroutine<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, el);
}
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -4,7 +4,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -61,12 +60,6 @@ export async function taggedRect<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, taggedRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, rectPoints, point);

View File

@@ -10,7 +10,6 @@ import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -97,13 +96,6 @@ export async function taggedWaveEdgedRectangle<T extends SVGGraphicsElement>(
);
updateNodeBounds(node, waveEdgeRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -3,7 +3,6 @@ import intersect from '../intersect/index.js';
import type { Node } from '../../types.js';
import { styles2String } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -30,12 +29,6 @@ export async function text<T extends SVGGraphicsElement>(parent: D3Selection<T>,
updateNodeBounds(node, rect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.rect(node, point);
};

View File

@@ -5,7 +5,6 @@ import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import { handleUndefinedAttr } from '../../../utils.js';
import type { Bounds, Point } from '../../../types.js';
export const createCylinderPathD = (
x: number,
@@ -114,12 +113,6 @@ export async function tiltedCylinder<T extends SVGGraphicsElement>(
updateNodeBounds(node, cylinder);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const y = pos.y - (node.y ?? 0);

View File

@@ -5,7 +5,21 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
// export const 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) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -51,12 +65,6 @@ export async function trapezoid<T extends SVGGraphicsElement>(parent: D3Selectio
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};

View File

@@ -4,7 +4,6 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -53,12 +52,6 @@ export async function trapezoidalPentagon<T extends SVGGraphicsElement>(
updateNodeBounds(node, polygon);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -8,7 +8,6 @@ import { createPathFromPoints } from './util.js';
import { evaluate } from '../../../diagrams/common/common.js';
import { getConfig } from '../../../diagram-api/diagramAPI.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -60,12 +59,6 @@ export async function triangle<T extends SVGGraphicsElement>(parent: D3Selection
`translate(${-bbox.width / 2 - (bbox.x - (bbox.left ?? 0))}, ${h / 2 - (bbox.height + (node.padding ?? 0) / (useHtmlLabels ? 2 : 1) - (bbox.y - (bbox.top ?? 0)))})`
);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
log.info('Triangle intersect', node, points, point);
return intersect.polygon(node, points, point);

View File

@@ -1,3 +1,4 @@
import createLabel from '../createLabel.js';
import { createText } from '../../createText.js';
import type { Node } from '../../types.js';
import { getConfig } from '../../../diagram-api/diagramAPI.js';
@@ -40,14 +41,26 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
label = typeof node.label === 'string' ? node.label : node.label[0];
}
const text = await createText(labelEl, sanitizeText(decodeEntities(label), getConfig()), {
useHtmlLabels,
width: node.width || getConfig().flowchart?.wrappingWidth,
// @ts-expect-error -- This is currently not used. Should this be `classes` instead?
cssClasses: 'markdown-node-label',
style: node.labelStyle,
addSvgBackground: !!node.icon || !!node.img,
});
let text;
if (node.labelType !== 'string') {
text = await createText(labelEl, sanitizeText(decodeEntities(label), getConfig()), {
useHtmlLabels,
width: node.width || getConfig().flowchart?.wrappingWidth,
// @ts-expect-error -- This is currently not used. Should this be `classes` instead?
cssClasses: 'markdown-node-label',
style: node.labelStyle,
addSvgBackground: !!node.icon || !!node.img,
});
} else {
const labelElement = await createLabel(
sanitizeText(decodeEntities(label), getConfig()),
node.labelStyle,
false,
true
);
text = labelEl.node()?.appendChild(labelElement);
}
// Get the size of the label
let bbox = text.getBBox();
const halfPadding = (node?.padding ?? 0) / 2;

View File

@@ -10,7 +10,6 @@ import type { Node } from '../../types.js';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
@@ -75,13 +74,6 @@ export async function waveEdgedRectangle<T extends SVGGraphicsElement>(
);
updateNodeBounds(node, waveEdgeRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
// TODO: Implement intersect for this shape
const radius = bounds.width / 2;
return intersect.circle(bounds, radius, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -10,16 +10,7 @@ import type { Node } from '../../types.js';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getPoints(w: number, finalH: number, waveAmplitude: number) {
return [
{ x: -w / 2, y: finalH / 2 },
...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
{ x: w / 2, y: -finalH / 2 },
...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
];
}
export async function waveRectangle<T extends SVGGraphicsElement>(
parent: D3Selection<T>,
node: Node
@@ -61,7 +52,12 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
options.fillStyle = 'solid';
}
const points = getPoints(w, finalH, waveAmplitude);
const points = [
{ x: -w / 2, y: finalH / 2 },
...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
{ x: w / 2, y: -finalH / 2 },
...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
];
const waveRectPath = createPathFromPoints(points);
const waveRectNode = rc.path(waveRectPath, options);
@@ -79,18 +75,6 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
}
updateNodeBounds(node, waveRect);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const waveAmplitude = Math.min(h * 0.2, h / 4);
const finalH = h + waveAmplitude * 2;
const points = getPoints(w, finalH, waveAmplitude);
return intersect.polygon(node, points, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;

View File

@@ -4,16 +4,6 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
import type { D3Selection } from '../../../types.js';
import type { Bounds, Point } from '../../../types.js';
function getOutPathPoints(x: number, y: number, w: number, h: number, rectOffset: number) {
return [
{ x: x - rectOffset, y: y - rectOffset },
{ x: x - rectOffset, y: y + h },
{ x: x + w, y: y + h },
{ x: x + w, y: y - rectOffset },
];
}
export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
const { labelStyles, nodeStyles } = styles2String(node);
@@ -30,7 +20,12 @@ export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selecti
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const outerPathPoints = getOutPathPoints(x, y, w, h, rectOffset);
const outerPathPoints = [
{ x: x - rectOffset, y: y - rectOffset },
{ x: x - rectOffset, y: y + h },
{ x: x + w, y: y + h },
{ x: x + w, y: y - rectOffset },
];
const 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}
@@ -63,17 +58,6 @@ export async function windowPane<T extends SVGGraphicsElement>(parent: D3Selecti
updateNodeBounds(node, windowPane);
node.calcIntersect = function (bounds: Bounds, point: Point) {
const w = bounds.width;
const h = bounds.height;
const rectOffset = 5;
const x = -w / 2;
const y = -h / 2;
const outerPathPoints = getOutPathPoints(x, y, w, h, rectOffset);
return intersect.polygon(node, outerPathPoints, point);
};
node.intersect = function (point) {
const pos = intersect.polygon(node, outerPathPoints, point);
return pos;

View File

@@ -2,7 +2,6 @@ export type MarkdownWordType = 'normal' | 'strong' | 'em';
import type { MermaidConfig } from '../config.type.js';
import type { ClusterShapeID } from './rendering-elements/clusters.js';
import type { ShapeID } from './rendering-elements/shapes.js';
import type { Bounds, Point } from '../types.js';
export interface MarkdownWord {
content: string;
type: MarkdownWordType;
@@ -44,7 +43,6 @@ interface BaseNode {
height?: number;
// Specific properties for State Diagram nodes TODO remove and use generic properties
intersect?: (point: any) => any;
calcIntersect?: (bounds: Bounds, point: Point) => any;
// Non-generic properties
rx?: number; // Used for rounded corners in Rect, Ellipse, etc.Maybe it to specialized RectNode, EllipseNode, etc.

View File

@@ -18,12 +18,6 @@ export interface Point {
x: number;
y: number;
}
export interface Bounds {
x: number;
y: number;
width: number;
height: number;
}
export interface TextDimensionConfig {
fontSize?: number;

View File

@@ -3,7 +3,7 @@ import type { EdgeData, Point } from '../types.js';
// We need to draw the lines a bit shorter to avoid drawing
// under any transparent markers.
// The offsets are calculated from the markers' dimensions.
export const markerOffsets = {
const markerOffsets = {
aggregation: 18,
extension: 18,
composition: 18,
@@ -104,6 +104,7 @@ export const getLineFunctionsWithOffset = (
adjustment *= DIRECTION === 'right' ? -1 : 1;
offset += adjustment;
}
return pointTransformer(d).x + offset;
},
y: function (