Skip to content

Commit 3a647e4

Browse files
committed
feat: arrow label can be aligned left and middle
1 parent 8b7ab12 commit 3a647e4

File tree

10 files changed

+184
-134
lines changed

10 files changed

+184
-134
lines changed

demo/Fragmentation.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ const props = {
1616
nodeRenderer: moleculeRenderer,
1717
arrowRendererOptions: {
1818
getLabel: (node) => {
19-
return node?.reaction?.label;
19+
return `Hello\n${node?.reaction?.label}\nWorld`;
2020
},
21+
verticalPosition: 'top',
2122
getID: () => {
2223
return Math.random().toString();
2324
},
24-
labelPosition: 'center',
25+
horizontalPosition: 'left',
2526
},
2627
nodeRendererOptions: {
2728
getID: () => {

src/__tests__/__snapshots__/molecule.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,5 +685,5 @@ exports[`render: Molecule 1`] = `
685685
<circle id="mol13:Atom:11" class="event" cx="39.96" cy="51" r="8" opacity="0"></circle>
686686
<circle id="mol13:Atom:12" class="event" cx="60.75" cy="87" r="8" opacity="0"></circle>
687687
<circle id="mol13:Atom:13" class="event" cx="19.18" cy="63" r="8" opacity="0"></circle>
688-
</svg></g></g></g></g><g><path d="M 227 418 C 302 418 302 154 357 154 Q 357 154 377 154 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,286)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,286)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 432 357 432 Q 357 432 377 432 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,425)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,425)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 640 357 640 Q 357 640 377 640 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,529)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,529)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 773 357 773 Q 357 773 377 773 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,595.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,595.5)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 563 154 C 638 154 638 77 693 77 Q 693 77 713 77 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,115.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,115.5)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 563 154 C 638 154 638 224 693 224 Q 693 224 713 224 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,189)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,189)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 899 77 C 974 77 974 77 1029 77 Q 1029 77 1049 77 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(974,77)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(974,77)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 563 432 C 638 432 638 371 693 371 Q 693 371 713 371 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,401.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,401.5)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 563 432 C 638 432 638 502 693 502 Q 693 502 713 502 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,467)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,467)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 899 371 C 974 371 974 369 1029 369 Q 1029 369 1049 369 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(974,370)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(974,370)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g><g><path d="M 557 640 C 632 640 632 633 687 633 Q 687 633 707 633 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(632,636.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" alignment-baseline="middle" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(632,636.5)" stroke="none" alignment-baseline="middle" font-size="14" fill="black"></text></g></svg>"
688+
</svg></g></g></g></g><g><path d="M 227 418 C 302 418 302 154 357 154 Q 357 154 377 154 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,286)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,286)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 432 357 432 Q 357 432 377 432 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,425)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,425)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 640 357 640 Q 357 640 377 640 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,529)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,529)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 227 418 C 302 418 302 773 357 773 Q 357 773 377 773 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(302,595.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(302,595.5)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 563 154 C 638 154 638 77 693 77 Q 693 77 713 77 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,115.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,115.5)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 563 154 C 638 154 638 224 693 224 Q 693 224 713 224 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,189)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,189)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 899 77 C 974 77 974 77 1029 77 Q 1029 77 1049 77 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(974,77)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(974,77)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 563 432 C 638 432 638 371 693 371 Q 693 371 713 371 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,401.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,401.5)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 563 432 C 638 432 638 502 693 502 Q 693 502 713 502 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(638,467)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(638,467)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 899 371 C 974 371 974 369 1029 369 Q 1029 369 1049 369 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(974,370)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(974,370)" stroke="none" font-size="14" fill="black"></text></g><g><path d="M 557 640 C 632 640 632 633 687 633 Q 687 633 707 633 " style="fill: none; stroke-width: 2; stroke: black; marker-end: url(#arrowhead);"></path><text text-anchor="middle" transform="translate(632,636.5)" stroke="rgba(255,255,255,0.5)" stroke-width="0.5em" fill="none" font-size="14"></text><text text-anchor="middle" transform="translate(632,636.5)" stroke="none" font-size="14" fill="black"></text></g></svg>"
689689
`;

src/__tests__/molecule.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ test('render: Molecule', () => {
2929
getLabel: (node) => {
3030
return node.transformation;
3131
},
32-
labelPosition: 'center',
32+
horizontalPosition: 'center',
3333
},
3434
positionOptions: {
3535
spacingHorizontal: 150,

src/components/Arrow.tsx

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { Point } from '../types/Point';
22

3-
import { CenteredText } from './CenteredText';
43
import { refX } from './MarkerDef.utils';
5-
import { RightText } from './RightText';
4+
import { Text } from './Text';
65
/**
76
* Creates a simple arrow between 2 points. The arrow has one inflection point, which is the middle of the line.
87
* The SVG must define a marker with id="arrowhead" for this to work.
@@ -15,9 +14,17 @@ export function Arrow(props: {
1514
from: Point;
1615
to: Point;
1716
label: string;
18-
labelPosition: 'center' | 'right';
17+
horizontalPosition: 'left' | 'center' | 'right';
18+
verticalPosition?: 'top' | 'bottom' | 'center';
1919
}) {
20-
const { id, from, to, label, labelPosition = 'center' } = props;
20+
const {
21+
id,
22+
from,
23+
to,
24+
label,
25+
horizontalPosition = 'center',
26+
verticalPosition = 'center',
27+
} = props;
2128
const middle = { x: (from.x + to.x) / 2, y: (from.y + to.y) / 2 };
2229

2330
const headInflectionPoint = {
@@ -37,11 +44,32 @@ export function Arrow(props: {
3744
markerEnd: 'url(#arrowhead)',
3845
}}
3946
/>
40-
{labelPosition === 'center' && (
41-
<CenteredText x={middle.x} y={middle.y} label={label} />
47+
{horizontalPosition === 'center' && (
48+
<Text
49+
x={middle.x}
50+
y={middle.y}
51+
label={label}
52+
horizontalPosition={horizontalPosition}
53+
verticalPosition={verticalPosition}
54+
/>
4255
)}
43-
{labelPosition === 'right' && (
44-
<RightText x={to.x - 12} y={to.y - 8} label={label} />
56+
{horizontalPosition === 'right' && (
57+
<Text
58+
x={to.x - 12}
59+
y={to.y - 8}
60+
label={label}
61+
horizontalPosition="right"
62+
verticalPosition={verticalPosition}
63+
/>
64+
)}
65+
{horizontalPosition === 'left' && (
66+
<Text
67+
x={from.x + 12}
68+
y={from.y + 8}
69+
label={label}
70+
horizontalPosition="left"
71+
verticalPosition={verticalPosition}
72+
/>
4573
)}
4674
</g>
4775
);

src/components/CenteredText.tsx

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/components/MultilineText.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export function MultilineText(props: {
2+
label: string;
3+
verticalPosition: 'top' | 'center' | 'bottom';
4+
}) {
5+
const { label, verticalPosition } = props;
6+
if (!label) return;
7+
const lines = label.split(/\r?\n/);
8+
const firstDX =
9+
verticalPosition === 'top'
10+
? 1
11+
: verticalPosition === 'center'
12+
? -lines.length / 2 + 0.5
13+
: -lines.length;
14+
return (
15+
<>
16+
{lines.map((line, index) => (
17+
<tspan key={index} x="0" dy={index === 0 ? `${firstDX}em` : '1em'}>
18+
{line}
19+
</tspan>
20+
))}
21+
</>
22+
);
23+
}

src/components/RightText.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/components/Text.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { MultilineText } from './MultilineText';
2+
3+
export function Text(props: {
4+
x: number;
5+
y: number;
6+
label: string;
7+
horizontalPosition: 'left' | 'center' | 'right';
8+
verticalPosition: 'top' | 'center' | 'bottom';
9+
}) {
10+
const { x, y, label, verticalPosition, horizontalPosition } = props;
11+
const transform = `translate(${x},${y})`;
12+
13+
let textAnchor;
14+
switch (horizontalPosition) {
15+
case 'left':
16+
textAnchor = 'start';
17+
break;
18+
case 'center':
19+
textAnchor = 'middle';
20+
break;
21+
case 'right':
22+
textAnchor = 'end';
23+
break;
24+
default:
25+
textAnchor = 'middle';
26+
}
27+
28+
return (
29+
<>
30+
<text
31+
textAnchor={textAnchor}
32+
transform={transform}
33+
stroke="rgba(255,255,255,0.5)"
34+
strokeWidth="0.5em"
35+
fill="none"
36+
fontSize="14"
37+
>
38+
<MultilineText label={label} verticalPosition={verticalPosition} />
39+
</text>
40+
<text
41+
textAnchor={textAnchor}
42+
transform={transform}
43+
stroke="none"
44+
fontSize="14"
45+
fill="black"
46+
>
47+
<MultilineText label={label} verticalPosition={verticalPosition} />
48+
</text>
49+
</>
50+
);
51+
}

src/data/getArrows.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function getArrows(nodes, options = {}) {
88
}
99

1010
function getArrowsSS(nodes, arrows, status, options: any = {}) {
11-
const { getLabel, labelPosition, getID } = options;
11+
const { getLabel, horizontalPosition, getID, verticalPosition } = options;
1212

1313
for (const node of nodes) {
1414
if (node.children) {
@@ -20,7 +20,8 @@ function getArrowsSS(nodes, arrows, status, options: any = {}) {
2020
from={node.anchor.right}
2121
to={child.anchor.left}
2222
label={getLabel?.(child)}
23-
labelPosition={labelPosition}
23+
horizontalPosition={horizontalPosition}
24+
verticalPosition={verticalPosition}
2425
/>,
2526
);
2627
}

0 commit comments

Comments
 (0)