UNPKG

@liammartens/svg-path-properties

Version:

Calculate the length for an SVG path, to use it with node or a Canvas element

102 lines (94 loc) 3.09 kB
import { Properties, Point } from "./types"; import { cubicPoint, getCubicArcLength, cubicDerivative, getQuadraticArcLength, quadraticPoint, quadraticDerivative, t2length } from "./bezier-functions"; export class Bezier implements Properties { private a: Point; private b: Point; private c: Point; private d: Point; private length: number; private getArcLength: (xs: number[], ys: number[], t: number) => number; private getPoint: (xs: number[], ys: number[], t: number) => Point; private getDerivative: (xs: number[], ys: number[], t: number) => Point; constructor( ax: number, ay: number, bx: number, by: number, cx: number, cy: number, dx: number | undefined, dy: number | undefined ) { this.a = { x: ax, y: ay }; this.b = { x: bx, y: by }; this.c = { x: cx, y: cy }; if (dx !== undefined && dy !== undefined) { this.getArcLength = getCubicArcLength; this.getPoint = cubicPoint; this.getDerivative = cubicDerivative; this.d = { x: dx, y: dy }; } else { this.getArcLength = getQuadraticArcLength; this.getPoint = quadraticPoint; this.getDerivative = quadraticDerivative; this.d = { x: 0, y: 0 }; } this.length = this.getArcLength( [this.a.x, this.b.x, this.c.x, this.d.x], [this.a.y, this.b.y, this.c.y, this.d.y], 1 ); } public getTotalLength = () => { return this.length; }; public getPointAtLength = (length: number) => { const xs = [this.a.x, this.b.x, this.c.x, this.d.x]; const xy = [this.a.y, this.b.y, this.c.y, this.d.y]; const t = t2length(length, this.length, i => this.getArcLength(xs, xy, i)); return this.getPoint(xs, xy, t); }; public getTangentAtLength = (length: number) => { const xs = [this.a.x, this.b.x, this.c.x, this.d.x]; const xy = [this.a.y, this.b.y, this.c.y, this.d.y]; const t = t2length(length, this.length, i => this.getArcLength(xs, xy, i)); const derivative = this.getDerivative(xs, xy, t); const mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y); let tangent: Point; if (mdl > 0) { tangent = { x: derivative.x / mdl, y: derivative.y / mdl }; } else { tangent = { x: 0, y: 0 }; } return tangent; }; public getPropertiesAtLength = (length: number) => { const xs = [this.a.x, this.b.x, this.c.x, this.d.x]; const xy = [this.a.y, this.b.y, this.c.y, this.d.y]; const t = t2length(length, this.length, i => this.getArcLength(xs, xy, i)); const derivative = this.getDerivative(xs, xy, t); const mdl = Math.sqrt(derivative.x * derivative.x + derivative.y * derivative.y); let tangent: Point; if (mdl > 0) { tangent = { x: derivative.x / mdl, y: derivative.y / mdl }; } else { tangent = { x: 0, y: 0 }; } const point = this.getPoint(xs, xy, t); return { x: point.x, y: point.y, tangentX: tangent.x, tangentY: tangent.y }; }; public getC = () => { return this.c; }; public getD = () => { return this.d; }; }