效果图
代码实操
import React from 'react';
import PropTypes from 'prop-types';
import { iconMaker, triangleMaker } from '../utils';
const Connection = ({ startPoint, radius, height, width, color }) => {
const [sx, sy] = startPoint;
// 上下右左, 矩形的四个点
const point1 = [sx, sy];
const point2 = [sx, sy + height];
const point3 = [sx + width, sy + height];
const point4 = [sx + width, sy];
// 左边圆角的点坐标
const cPoint1 = [sx, point2[1] - radius];
const cPoint2 = point2;
const cPoint3 = [sx + radius, point2[1]];
// 右边圆角的点坐标
const cPoint4 = [point3[0] - radius, point3[1]];
const cPoint5 = point3;
const cPoint6 = [point3[0], point3[1] - radius];
const centerPoint = [
point2[0] + width / 2,
point2[1],
point2[0] + width / 2,
point2[1] + 20
];
return (
<g className="pane-node" style={{ stroke: '#4D9DED', strokeWidth: 2 }}>
<path
d={`M${cPoint1[0]} ${cPoint1[1]} C ${cPoint1[0]} ${cPoint1[1]}, ${cPoint2[0]} ${cPoint2[1]}, ${cPoint3[0]} ${cPoint3[1]} L ${cPoint4[0]} ${cPoint4[1]}`}
fill="transparent"
/>
<circle cx={point1[0]} cy={point1[1]} r="4" fill="#4D9DED" />
<path d={`${triangleMaker(point4, 12)}`} fill="#4D9DED" />
<path
d={`M${cPoint4[0]} ${cPoint4[1]} C ${cPoint4[0]} ${cPoint4[1]}, ${cPoint5[0]} ${cPoint5[1]}, ${cPoint6[0]} ${cPoint6[1]}`}
fill="transparent"
/>
<line
x1={point1[0]}
y1={point1[1]}
x2={cPoint1[0]}
y2={cPoint1[1]}
/>
<line
x1={cPoint6[0]}
y1={cPoint6[1]}
x2={point4[0]}
y2={point4[1]}
/>
<line
x1={centerPoint[0]}
y1={centerPoint[1]}
x2={centerPoint[2]}
y2={centerPoint[3]}
/>
{iconMaker([centerPoint[2], centerPoint[3]], 9)}
</g>
);
};
Connection.defaultProps = {
startPoint: [130, 110],
radius: 4,
height: 20,
width: 283,
color: '#4D9DED'
};
Connection.propTypes = {
height: PropTypes.number,
radius: PropTypes.number,
startPoint: PropTypes.array,
width: PropTypes.number,
color: PropTypes.string
};
export default Connection;
export function triangleMaker(startPoint, len) {
const [x, y] = startPoint;
return `M${x},${y} L${x - len / 2},${y + len / 2} L${x + len / 2},${
y + len / 2
} L${x},${y}`;
}
export function iconMaker(centerPoint, r, stopColor = ['#0073E6', '#66ABF0']) {
const [x, y] = centerPoint;
const textLen = Math.floor(r / 3);
return (
<g style={{ stroke: '#FFFFFF', strokeWidth: 1 }}>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop
offset="0%"
style={{ stopColor: stopColor[0], stopOpacity: 1 }}
/>
<stop
offset="100%"
style={{ stopColor: stopColor[1], stopOpacity: 1 }}
/>
</linearGradient>
</defs>
<circle cx={x} cy={y} r={r} fill="url(#grad1)" />
<line
x1={x - textLen}
y1={y - textLen}
x2={x + textLen}
y2={y + textLen}
/>
<line
x1={x + textLen}
y1={y - textLen}
x2={x - textLen}
y2={y + textLen}
/>
</g>
);
}
原理解析
c1、c2、c3是p2的贝塞尔曲线控制点
c4、c5、c6是p3的贝塞尔控制点
r为曲线半径