123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- type PointType = { x: number; y: number };
- type LineFunc = (
- pointA: PointType,
- pointB: PointType
- ) => { length: number; angle: number };
- type ControlPointClosure = (
- current: PointType,
- previous: PointType,
- next: PointType,
- reverse?: boolean
- ) => number[];
- type ControlPointFunc = (
- lineCale: LineFunc,
- smooth: number
- ) => ControlPointClosure;
- type BezierCommandClosure = (
- point: PointType,
- i: number,
- a: PointType[]
- ) => string;
- type BezierCommandFunc = (
- controlPoint: ControlPointClosure
- ) => BezierCommandClosure;
- type SvgPathFunc = (
- points: PointType[],
- command: BezierCommandClosure
- ) => string;
- export const line: LineFunc = (pointA, pointB) => {
- const lengthX = pointB.x - pointA.x;
- const lengthY = pointB.y - pointA.y;
- return {
- length: Math.sqrt(lengthX ** 2 + lengthY ** 2),
- angle: Math.atan2(lengthY, lengthX),
- };
- };
- export const controlPoint: ControlPointFunc = (lineCale, smooth) => (
- current,
- previous,
- next,
- reverse
- ): number[] => {
- // When 'current' is the first or last point of the array
- // 'previous' or 'next' don't exist.
- // Replace with 'current'
- const p = previous || current;
- const n = next || current;
- // Properties of the opposed-line
- const o = lineCale(p, n);
- // If is end-control-point, add PI to the angle to go backward
- const angle = o.angle + (reverse ? Math.PI : 0);
- const length = o.length * smooth;
- // The control point position is relative to the current point
- const x = current.x + Math.cos(angle) * length;
- const y = current.y + Math.sin(angle) * length;
- return [x, y];
- };
- export const bezierCommand: BezierCommandFunc = controlPointCalc => (
- point,
- i,
- a
- ): string => {
- // start control point
- const [cpsX, cpsY] = controlPointCalc(a[i - 1], a[i - 2], point);
- // end control point
- const [cpeX, cpeY] = controlPointCalc(point, a[i - 1], a[i + 1], true);
- return `C ${cpsX},${cpsY} ${cpeX},${cpeY} ${point.x},${point.y}`;
- };
- export const svgPath: SvgPathFunc = (points, command) => {
- const d = points.reduce(
- (acc, point, i, a) =>
- i === 0 ? `M ${point.x},${point.y}` : `${acc} ${command(point, i, a)}`,
- ''
- );
- return d;
- };
- export default line;
|