1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- 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;
|