import * as d3 from 'd3'; import { Point } from '../types/Point'; import { Path, transformed } from './Path'; class CubicBezier extends Path { private readonly _start: Point; private readonly _c1: Point; private readonly _c2: Point; private readonly _end: Point; constructor (start: Point, c1: Point, c2: Point, end: Point) { super(); this._start = start; this._c1 = c1; this._c2 = c2; this._end = end; } angleAlong (t: number, x: d3.ScaleLinear, y: d3.ScaleLinear): number { const s = transformed(this._start, x, y); const c1 = transformed(this._c1, x, y); const c2 = transformed(this._c2, x, y); const e = transformed(this._end, x, y); const u = 1 - t; const dx = u * u * (c1.x - s.x) + 2 * t * u * (c2.x - c1.x) + t * t * (e.x - c2.x); const dy = u * u * (c1.y - s.y) + 2 * t * u * (c2.y - c1.y) + t * t * (e.y - c2.y); return Math.atan2(dx, dy) - Math.PI; } apply (context: CanvasRenderingContext2D, x: d3.ScaleLinear, y: d3.ScaleLinear): void { const s = transformed(this._start, x, y); const c1 = transformed(this._c1, x, y); const c2 = transformed(this._c2, x, y); const e = transformed(this._end, x, y); context.moveTo(s.x, s.y); context.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, e.x, e.y); } pointAlong (t: number, x: d3.ScaleLinear, y: d3.ScaleLinear): Point { const s = transformed(this._start, x, y); const c1 = transformed(this._c1, x, y); const c2 = transformed(this._c2, x, y); const e = transformed(this._end, x, y); const u = 1 - t; return { x: u * u * u * s.x + 3 * t * u * u * c1.x + 3 * t * t * u * c2.x + t * t * t * e.x, y: u * u * u * s.y + 3 * t * u * u * c1.y + 3 * t * t * u * c2.y + t * t * t * e.y }; } points (): Point[] { return [this._start, this._c1, this._c2, this._end]; } } export { CubicBezier }