Skip to content

Commit 79203f1

Browse files
wumailboyongjiong
authored andcommitted
refactor(extension): optimize curved-edge(#1377)
1 parent 045e80b commit 79203f1

File tree

2 files changed

+161
-84
lines changed

2 files changed

+161
-84
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,185 @@
1-
import { PolylineEdge, PolylineEdgeModel, h } from '@logicflow/core';
2-
import searchMiddleIndex from './searchMiddleIndex';
1+
import {
2+
PointTuple,
3+
PolylineEdge,
4+
PolylineEdgeModel,
5+
h,
6+
} from '@logicflow/core';
37

4-
class CurvedEdge extends PolylineEdge {
5-
pointFilter(points) {
6-
const allPoints = points;
7-
let i = 1;
8-
while (i < allPoints.length - 1) {
9-
const [x, y] = allPoints[i - 1];
10-
const [x1, y1] = allPoints[i];
11-
const [x2, y2] = allPoints[i + 1];
12-
if ((x === x1 && x1 === x2)
13-
|| (y === y1 && y1 === y2)) {
14-
allPoints.splice(i, 1);
15-
} else {
16-
i++;
17-
}
8+
type DirectionType = 't' | 'b' | 'l' | 'r' | '';
9+
type ArcPositionType = 'tl' | 'tr' | 'bl' | 'br' | '-';
10+
11+
const directionMap: any = {
12+
tr: 'tl',
13+
lb: 'tl',
14+
tl: 'tr',
15+
rb: 'tr',
16+
br: 'bl',
17+
lt: 'bl',
18+
bl: 'br',
19+
rt: 'br',
20+
};
21+
22+
function pointFilter(points: number[][]) {
23+
const all = points;
24+
let i = 1;
25+
while (i < all.length - 1) {
26+
const [x, y] = all[i - 1];
27+
const [x1, y1] = all[i];
28+
const [x2, y2] = all[i + 1];
29+
if ((x === x1 && x1 === x2) || (y === y1 && y1 === y2)) {
30+
all.splice(i, 1);
31+
} else {
32+
i++;
1833
}
19-
return allPoints;
2034
}
21-
getEdge() {
22-
const { model } = this.props;
23-
const { points, isAnimation, arrowConfig, radius = 5 } = model;
24-
const style = model.getEdgeStyle();
25-
const animationStyle = model.getEdgeAnimationStyle();
26-
const points2 = this.pointFilter(points.split(' ').map((p) => p.split(',').map(a => Number(a))));
27-
const res = searchMiddleIndex(points2);
28-
if (res) {
29-
const [first, last] = res;
30-
const firstPoint = points2[first];
31-
const lastPoint = points2[last];
32-
const flag = firstPoint.some((num, index) => num === lastPoint[index]);
33-
if (!flag) {
34-
const diff = (lastPoint[1] - firstPoint[1]) / 2;
35-
const firstNextPoint = [lastPoint[0], lastPoint[1] - diff];
36-
const lastPrePoint = [firstPoint[0], firstPoint[1] + diff];
37-
points2.splice(first + 1, 0, lastPrePoint, firstNextPoint);
35+
return all;
36+
}
37+
38+
function getMidPoints(
39+
cur: PointTuple,
40+
key: string,
41+
orientation: ArcPositionType,
42+
radius: number,
43+
) {
44+
const mid1 = [cur[0], cur[1]];
45+
const mid2 = [cur[0], cur[1]];
46+
switch (orientation) {
47+
case 'tl': {
48+
if (key === 'tr') {
49+
mid1[1] += radius;
50+
mid2[0] += radius;
51+
} else if (key === 'lb') {
52+
mid1[0] += radius;
53+
mid2[1] += radius;
3854
}
55+
return [mid1, mid2];
3956
}
40-
const [startX, startY] = points2[0];
41-
let d = `M${startX} ${startY}`;
42-
// 1) 如果一个点不为开始和结束,则在这个点的前后增加弧度开始和结束点。
43-
// 2) 判断这个点与前一个点的坐标
44-
// 如果x相同则前一个点的x也不变,
45-
// y为(这个点的y 大于前一个点的y, 则 为 这个点的y - 5;小于前一个点的y, 则为这个点的y+5)
46-
// 同理,判断这个点与后一个点的x,y是否相同,如果x相同,则y进行加减,如果y相同,则x进行加减
47-
for (let i = 1; i < points2.length - 1; i++) {
48-
const [preX, preY] = points2[i - 1];
49-
const [currentX, currentY] = points2[i];
50-
const [nextX, nextY] = points2[i + 1];
51-
if (currentX === preX && currentY !== preY) {
52-
const y = currentY > preY ? currentY - radius : currentY + radius;
53-
d = `${d} L ${currentX} ${y}`;
57+
case 'tr': {
58+
if (key === 'tl') {
59+
mid1[1] += radius;
60+
mid2[0] -= radius;
61+
} else if (key === 'rb') {
62+
mid1[0] -= radius;
63+
mid2[1] += radius;
5464
}
55-
if (currentY === preY && currentX !== preX) {
56-
const x = currentX > preX ? currentX - radius : currentX + radius;
57-
d = `${d} L ${x} ${currentY}`;
65+
return [mid1, mid2];
66+
}
67+
case 'bl': {
68+
if (key === 'br') {
69+
mid1[1] -= radius;
70+
mid2[0] += radius;
71+
} else if (key === 'lt') {
72+
mid1[0] += radius;
73+
mid2[1] -= radius;
5874
}
59-
d = `${d} Q ${currentX} ${currentY}`;
60-
if (currentX === nextX && currentY !== nextY) {
61-
const y = currentY > nextY ? currentY - radius : currentY + radius;
62-
d = `${d} ${currentX} ${y}`;
75+
return [mid1, mid2];
76+
}
77+
case 'br': {
78+
if (key === 'bl') {
79+
mid1[1] -= radius;
80+
mid2[0] -= radius;
81+
} else if (key === 'rt') {
82+
mid1[0] -= radius;
83+
mid2[1] -= radius;
6384
}
64-
if (currentY === nextY && currentX !== nextX) {
65-
const x = currentX > nextX ? currentX - radius : currentX + radius;
66-
d = `${d} ${x} ${currentY}`;
85+
return [mid1, mid2];
86+
}
87+
default:
88+
return null;
89+
}
90+
}
91+
92+
function getPath(
93+
prev: PointTuple,
94+
cur: PointTuple,
95+
next: PointTuple,
96+
radius: number,
97+
): string {
98+
let dir1: DirectionType = '';
99+
let dir2: DirectionType = '';
100+
let realRadius = radius;
101+
102+
if (prev[0] === cur[0]) {
103+
dir1 = prev[1] > cur[1] ? 't' : 'b';
104+
realRadius = Math.min(Math.abs(prev[0] - cur[0]), radius);
105+
} else if (prev[1] === cur[1]) {
106+
dir1 = prev[0] > cur[0] ? 'l' : 'r';
107+
realRadius = Math.min(Math.abs(prev[1] - cur[1]), radius);
108+
}
109+
if (cur[0] === next[0]) {
110+
dir2 = cur[1] > next[1] ? 't' : 'b';
111+
realRadius = Math.min(Math.abs(prev[0] - cur[0]), radius);
112+
} else if (cur[1] === next[1]) {
113+
dir2 = cur[0] > next[0] ? 'l' : 'r';
114+
realRadius = Math.min(Math.abs(prev[1] - cur[1]), radius);
115+
}
116+
117+
const key = `${dir1}${dir2}`;
118+
const orientation: ArcPositionType = directionMap[key] || '-';
119+
let path = `L ${prev[0]} ${prev[1]}`;
120+
if (orientation === '-') {
121+
path += `L ${cur[0]} ${cur[1]} L ${next[0]} ${next[1]}`;
122+
} else {
123+
const [mid1, mid2] = getMidPoints(cur, key, orientation, (realRadius)) || [];
124+
if (mid1 && mid2) {
125+
path += `L ${mid1[0]} ${mid1[1]} Q ${cur[0]} ${cur[1]} ${mid2[0]} ${mid2[1]}`;
126+
[cur[0], cur[1]] = mid2;
127+
}
128+
}
129+
return path;
130+
}
131+
132+
class CurvedEdge extends PolylineEdge {
133+
getEdge() {
134+
const { model } = this.props;
135+
const { points: pointsStr, isAnimation, arrowConfig, radius = 5 } = model;
136+
const style = model.getEdgeStyle();
137+
const animationStyle = model.getEdgeAnimationStyle();
138+
const points = pointFilter(
139+
pointsStr.split(' ').map((p) => p.split(',').map((a) => +a)),
140+
);
141+
let i = 0;
142+
let d = '';
143+
if (points.length === 2) {
144+
d += `M${points[i][0]} ${points[i++][1]} L ${points[i][0]} ${
145+
points[i][1]
146+
}`;
147+
} else {
148+
d += `M${points[i][0]} ${points[i++][1]}`;
149+
for (; i + 1 < points.length;) {
150+
const prev = points[i - 1] as PointTuple;
151+
const cur = points[i] as PointTuple;
152+
const next = points[i++ + 1] as PointTuple;
153+
d += getPath(prev, cur, next, radius as number);
67154
}
155+
d += `L ${points[i][0]} ${points[i][1]}`;
68156
}
69-
const [endX, endY] = points2[points2.length - 1];
70-
d = `${d} L ${endX} ${endY}`;
157+
71158
const attrs = {
72-
d,
73159
style: isAnimation ? animationStyle : {},
74160
...style,
75161
...arrowConfig,
76162
fill: 'none',
77163
};
78-
return h(
79-
'path',
80-
{
81-
d,
82-
...attrs,
83-
},
84-
);
164+
console.log(d);
165+
return h('path', {
166+
d,
167+
...attrs,
168+
});
85169
}
86170
}
87171

88-
class CurvedEdgeModel extends PolylineEdgeModel {
89-
}
172+
class CurvedEdgeModel extends PolylineEdgeModel {}
173+
174+
const defaultCurvedEdge = {
175+
type: 'curved-edge',
176+
view: CurvedEdge,
177+
model: CurvedEdgeModel,
178+
};
179+
180+
export default defaultCurvedEdge;
90181

91182
export {
92183
CurvedEdge,
93-
// CurvedEdgeView,
94184
CurvedEdgeModel,
95185
};

packages/extension/src/materials/curved-edge/searchMiddleIndex.ts

-13
This file was deleted.

0 commit comments

Comments
 (0)