UNPKG

plotboilerplate

Version:

A simple javascript plotting boilerplate for 2d stuff.

575 lines (574 loc) 21.3 kB
/** * @author Ikaros Kappler * @date 2013-08-19 * @modified 2018-08-16 Added closure. Removed the 'IKRS' wrapper. * @modified 2018-11-20 Added circular auto-adjustment. * @modified 2018-11-25 Added the point constants to the BezierPath class itself. * @modified 2018-11-28 Added the locateCurveByStartPoint() function. * @modified 2018-12-04 Added the toSVGString() function. * @modified 2019-03-23 Added JSDoc tags. * @modified 2019-03-23 Changed the fuctions getPoint and getPointAt to match semantics in the Line class. * @modified 2019-11-18 Fixed the clone function: adjustCircular attribute was not cloned. * @modified 2019-12-02 Removed some excessive comments. * @modified 2019-12-04 Fixed the missing obtainHandleLengths behavior in the adjustNeightbourControlPoint function. * @modified 2020-02-06 Added function locateCurveByEndPoint( Vertex ). * @modified 2020-02-11 Added 'return this' to the scale(Vertex,number) and to the translate(Vertex) function. * @modified 2020-03-24 Ported this class from vanilla-JS to Typescript. * @modified 2020-06-03 Made the private helper function _locateUIndex to a private function. * @modified 2020-06-03 Added the getBounds() function. * @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords). * @modified 2020-07-24 Added the getClosestT(Vertex) function. * @modified 2020-12-29 Constructor is now private (no explicit use intended). * @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ). * @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`. * @modified 2022-02-02 Added the `destroy` method. * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead. * @modified 2023-10-06 Adding the `BezierPath.toPathPoints()` method. * @modified 2023-10-07 Adding the `BezierPath.fromCurve(CubicBezierCurve)` static function. * @version 2.6.0 * * @file BezierPath * @public **/ import { Bounds } from "./Bounds"; import { CubicBezierCurve } from "./CubicBezierCurve"; import { Vertex } from "./Vertex"; import { XYCoords, SVGSerializable, UID } from "./interfaces"; /** * @classdesc A BezierPath class. * * This was refactored from an older project. * * @requires Bounds * @requires Vertex * @requires CubicBezierCurve * @requires XYCoords * @requires SVGSerializable * @requires UID * @requires UIDGenerator **/ export declare class BezierPath implements SVGSerializable { /** * Required to generate proper CSS classes and other class related IDs. **/ readonly className: string; /** * The UID of this drawable object. * * @member {UID} * @memberof BezierCurve * @instance * @readonly */ readonly uid: UID; /** * @member {Array<Vertex>} * @memberof BezierPath * @type {Array<Vertex>} * @instance */ pathPoints: Array<Vertex>; /** * @member {number} * @memberof BezierPath * @type {number} * @instance */ totalArcLength: number; /** * Set this flag to true if you want the first point and * last point of the path to be auto adjusted, too. * * @member {number} * @memberof BezierPath * @type {number} * @instance */ adjustCircular: boolean; /** * @member {Array<CubicBezierCurve>} * @memberof BezierPath * @type {Array<CubicBezierCurve>} * @instance */ bezierCurves: Array<CubicBezierCurve>; /** * @member {boolean} * @memberof BezierPath * @type {boolean} * @instance */ isDestroyed: boolean; /** @constant {number} */ static START_POINT: number; /** @constant {number} */ static START_CONTROL_POINT: number; /** @constant {number} */ static END_CONTROL_POINT: number; /** @constant {number} */ static END_POINT: number; /** @constant {number} */ START_POINT: number; /** @constant {number} */ START_CONTROL_POINT: number; /** @constant {number} */ END_CONTROL_POINT: number; /** @constant {number} */ END_POINT: number; /** * The constructor.<br> * <br> * This constructor expects a sequence of path points and will approximate * the location of control points by picking some between the points.<br> * You should consider just constructing empty paths and then add more curves later using * the addCurve() function. * * @constructor * @name BezierPath * @param {Vertex[]} pathPoints - An array of path vertices (no control points). **/ private constructor(); /** * Add a cubic bezier curve to the end of this path. * * @method addCurve * @param {CubicBezierCurve} curve - The curve to be added to the end of the path. * @instance * @memberof BezierPath * @return {void} **/ addCurve(curve: CubicBezierCurve): void; /** * Locate the curve with the given start point (function returns the index). * * @method locateCurveByStartPoint * @param {Vertex} point - The (curve start-) point to look for. * @instance * @memberof BezierPath * @return {number} The curve index or -1 if curve (start-) point not found **/ locateCurveByStartPoint(point: Vertex): number; /** * Locate the curve with the given end point (function returns the index). * * @method locateCurveByEndPoint * @param {Vertex} point - The (curve end-) point to look for. * @instance * @memberof BezierPath * @return {number} The curve index or -1 if curve (end-) point not found **/ locateCurveByEndPoint(point: Vertex): number; /** * Locate the curve with the given start point (function returns the index). * * @method locateCurveByStartControlPoint * @param {Vertex} point - The (curve endt-) point to look for. * @instance * @memberof BezierPath * @return {number} The curve index or -1 if curve (end-) point not found **/ locateCurveByStartControlPoint(point: Vertex): number; locateCurveByEndControlPoint(point: Vertex): number; /** * Get the total length of this path.<br> * <br> * Note that the returned value comes from the curve buffer. Unregistered changes * to the curve points will result in invalid path length values. * * @method getLength * @instance * @memberof BezierPath * @return {number} The (buffered) length of the path. **/ getLength(): number; /** * This function is internally called whenever the curve or path configuration * changed. It updates the attribute that stores the path length information.<br> * <br> * If you perform any unregistered changes to the curve points you should call * this function afterwards to update the curve buffer. Not updating may * result in unexpected behavior. * * @method updateArcLengths * @instance * @memberof BezierPath * @return {void} **/ updateArcLengths(): void; /** * Get the number of curves in this path. * * @method getCurveCount * @instance * @memberof BezierPath * @return {number} The number of curves in this path. **/ getCurveCount(): number; /** * Get the cubic bezier curve at the given index. * * @method getCurveAt * @param {number} index - The curve index from 0 to getCurveCount()-1. * @instance * @memberof BezierPath * @return {CubicBezierCurve} The curve at the specified index. **/ getCurveAt(curveIndex: number): CubicBezierCurve; /** * Move the whole bezier path by the given (x,y)-amount. * * @method translate * @param {Vertex} amount - The amount to be added (amount.x and amount.y) * to each vertex of the curve. * @instance * @memberof BezierPath * @return {BezierPath} this for chaining **/ translate(amount: Vertex): BezierPath; /** * Scale the whole bezier path by the given uniform factor. * * @method scale * @param {Vertex} anchor - The scale origin to scale from. * @param {number} scaleFactor - The scalar to be multiplied with. * @instance * @memberof BezierPath * @return {BezierPath} this for chaining. **/ scale(anchor: Vertex, scaleFactor: number): BezierPath; /** * Scale the whole bezier path by the given (x,y)-factors. * * @method scale * @param {Vertex} anchor - The scale origin to scale from. * @param {number} amount - The scalar to be multiplied with. * @instance * @memberof BezierPath * @return {BezierPath} this for chaining. **/ scaleXY(scaleFactors: XYCoords, anchor?: XYCoords): BezierPath; /** * Rotate the whole bezier path around a point.. * * @method rotate * @param {Vertex} angle - The angle to rotate this path by. * @param {Vertex} center - The rotation center. * @instance * @memberof BezierPath * @return {void} **/ rotate(angle: number, center: Vertex): void; /** * Get the 't' position on this curve with the minimal distance to point p. * * @param {Vertex} p - The point to find the closest curve point for. * @return {number} A value t with 0.0 <= t <= 1.0. **/ getClosestT(p: Vertex): number; /** * Get the point on the bézier path at the given relative path location. * * @method getPoint * @param {number} u - The relative path position: <pre>0 <= u <= this.getLength()</pre> * @instance * @memberof BezierPath * @return {Vertex} The point at the relative path position. **/ getPoint(u: number): Vertex; /** * Get the point on the bézier path at the given path fraction. * * @method getPointAt * @param {number} t - The absolute path position: <pre>0.0 <= t <= 1.0</pre> * @instance * @memberof BezierPath * @return {Vertex} The point at the absolute path position. **/ getPointAt(t: number): Vertex; /** * Get the tangent of the bézier path at the given path fraction.<br> * <br> * Note that the returned vector is not normalized. * * @method getTangentAt * @param {number} t - The absolute path position: <pre>0.0 <= t <= 1.0</pre> * @instance * @memberof BezierPath * @return {Vertex} The tangent vector at the absolute path position. **/ getTangentAt(t: number): Vertex; /** * Get the tangent of the bézier path at the given path location.<br> * <br> * Note that the returned vector is not normalized. * * @method getTangent * @param {number} u - The relative path position: <pre>0 <= u <= getLength()</pre> * @instance * @memberof BezierPath * @return {Vertex} The tangent vector at the relative path position. **/ getTangent(u: number): Vertex; /** * Get the perpendicular of the bézier path at the given absolute path location (fraction).<br> * <br> * Note that the returned vector is not normalized. * * @method getPerpendicularAt * @param {number} t - The absolute path position: <pre>0.0 <= t <= 1.0</pre> * @instance * @memberof BezierPath * @return {Vertex} The perpendicluar vector at the absolute path position. **/ getPerpendicularAt(t: number): Vertex; /** * Get the perpendicular of the bézier path at the given relative path location.<br> * <br> * Note that the returned vector is not normalized. * * @method getPerpendicular * @param {number} u - The relative path position: <pre>0 <= u <= getLength()</pre> * @instance * @memberof BezierPath * @return {Vertex} The perpendicluar vector at the relative path position. **/ getPerpendicular(u: number): Vertex; /** * This is a helper function to locate the curve index for a given * absolute path position u. * * I decided to put this into privat scope as it is really specific. Maybe * put this into a utils wrapper. * * Returns: * - {number} i - the index of the containing curve. * - {number} uPart - the absolute curve length sum (length from the beginning to u, should equal u itself). * - {number} uBefore - the absolute curve length for all segments _before_ the matched curve (usually uBefore <= uPart). **/ private static _locateUIndex; /** * Get a specific sub path from this path. The start and end position are specified by * ratio number in [0..1]. * * 0.0 is at the beginning of the path. * 1.0 is at the end of the path. * * Values below 0 or beyond 1 are cropped down to the [0..1] interval. * * startT > endT is allowed, the returned sub path will have inverse direction then. * * @method getSubPathAt * @param {number} startT - The start position of the sub path. * @param {number} endT - The end position of the sub path. * @instance * @memberof BezierPath * @return {BezierPath} The desired sub path in the bounds [startT..endT]. **/ getSubPathAt(startT: number, endT: number): BezierPath; /** * This function moves the addressed curve point (or control point) with * keeping up the path's curve integrity.<br> * <br> * Thus is done by moving neighbour- and control- points as needed. * * @method moveCurvePoint * @param {number} curveIndex - The curve index to move a point from. * @param {number} pointID - One of the curve's four point IDs (START_POINT, * START_CONTROL_POINT, END_CONTRO_POINT or END_POINT). * @param {XYCoords} moveAmount - The amount to move the addressed vertex by. * @instance * @memberof BezierPath * @return {void} **/ moveCurvePoint(curveIndex: number, pointID: number, moveAmount: XYCoords): void; /** * This helper function adjusts the given point's predecessor's control point. * * @method adjustPredecessorControlPoint * @param {number} curveIndex - The curve index to move a point from. * @param {boolean} obtainHandleLength - Moves the point with keeping the original handle length. * @param {boolean} updateArcLength - The amount to move the addressed vertex by. * @instance * @private * @memberof BezierPath * @return {void} **/ adjustPredecessorControlPoint(curveIndex: number, obtainHandleLength: boolean, updateArcLengths: boolean): void; /** * This helper function adjusts the given point's successor's control point. * * @method adjustSuccessorControlPoint * @param {number} curveIndex - The curve index to move a point from. * @param {boolean} obtainHandleLength - Moves the point with keeping the original handle length. * @param {boolean} updateArcLength - The amount to move the addressed vertex by. * @instance * @private * @memberof BezierPath * @return {void} **/ adjustSuccessorControlPoint(curveIndex: number, obtainHandleLength: boolean, updateArcLengths: boolean): void; /** * This helper function adjusts the given point's successor's control point. * * @method adjustNeighbourControlPoint * @param {CubicBezierCurve} mainCurve * @param {CubicBezierCurve} neighbourCurve * @param {Vertex} mainPoint * @param {Vertex} mainControlPoint * @param {Vertex} neighbourPoint * @param {Vertex} neighbourControlPoint * @param {boolean} obtainHandleLengths * @param {boolean} updateArcLengths * @instance * @private * @memberof BezierPath * @return {void} **/ private static adjustNeighbourControlPoint; /** * Get the bounds of this Bézier path. * * Note the the curves' underlyung segment buffers are used to determine the bounds. The more * elements the segment buffers have, the more precise the returned bounds will be. * * @return {Bounds} The bounds of this Bézier path. **/ getBounds(): Bounds; /** * Get n 'equally' distributed vertices along this Bézier path. * * As the changing curvature of the B slines makes prediction of distances difficult, the * returned vertices' distances are only relatively equal: * - the distance grows where curvature is large. * - the distance shrinks where curvature is small. * * Only the distance mean of all consecutive is 1/n-th of the total arc length. * * Usually this approximation is good enough for most use cases. * * @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included). * @return {Array<Vertex>} */ getEvenDistributionVertices(pointCount: number): Array<Vertex>; /** * Clone this BezierPath (deep clone). * * @method clone * @instance * @memberof BezierPath * @return {BezierPath} **/ clone(): BezierPath; /** * Compare this and the passed Bézier path. * * @method equals * @param {BezierPath} path - The pass to compare with. * @instance * @memberof BezierPath * @return {boolean} **/ equals(path: BezierPath): boolean; /** * This function should invalidate any installed listeners and invalidate this object. * After calling this function the object might not hold valid data any more and * should not be used. * * @method destroy * @instance * @memberof BezierPath */ destroy(): void; /** * Convert this path to an array of path points that can be drawn by the default DrawLib * implementations. * * @method toPathPoints * @instance * @memberof BezierPath * @return {Array<XYCoords>} */ toPathPoints(): Array<XYCoords>; /** * Create a JSON string representation of this bézier curve. * * @method toJSON * @param {boolean} prettyFormat - If true then the function will add line breaks. * @instance * @memberof BezierPath * @return {string} The JSON string. **/ toJSON(prettyFormat: boolean): string; /** * Parse a BezierPath from the given JSON string. * * @method fromJSON * @param {string} jsonString - The string with the JSON data. * @throw An error if the string is not JSON or does not contain a bezier path object. * @static * @memberof BezierPath * @return {BezierPath} The parsed bezier path instance. **/ static fromJSON(jsonString: string): BezierPath; /** * Construct a new path with a single curve. Adding more curves is always possible. * * @method fromCurve * @param {CubicBezierCurve} curve - The curve to construct a new path from. * @static * @memberof BezierPath * @return {BezierPath} The constructed bezier path instance. */ static fromCurve(curve: CubicBezierCurve): BezierPath; /** * Create a BezierPath instance from the given array. * * @method fromArray * @param {Vertex[][]} arr - A two-dimensional array containing the bezier path vertices. * @throw An error if the array does not contain proper bezier path data. * @static * @memberof BezierPath * @return {BezierPath} The bezier path instance retrieved from the array data. **/ static fromArray(obj: any): BezierPath; /** * This function converts the bezier path into a string containing * integer values only. * The points' float values are rounded to 1 digit after the comma. * * The returned string represents a JSON array (with leading '[' and * trailing ']', the separator is ','). * * @method toReducedListRepresentation * @param {number} digits - The number of digits to be used after the comma '.'. * @instance * @memberof BezierPath * @return {string} The reduced list representation of this path. **/ toReducedListRepresentation(digits: number): string; /** * Parse a BezierPath instance from the reduced list representation.<br> * <br> * The passed string must represent a JSON array containing numbers only. * * @method fromReducedListRepresentation * @param {string} listJSON - The number of digits to be used after the floating point. * @throw An error if the string is malformed. * @instance * @memberof BezierPath * @return {BezierPath} The bezier path instance retrieved from the string. **/ static fromReducedListRepresentation(listJSON: string, adjustCircular?: boolean): BezierPath; /** * Convert a reduced list representation (array of numeric coordinates) to a BezierPath instance. * * The array's length must be 6*n + 2: * - [sx, sy, scx, scy, ecx, ecy, ... , ex, ey ] * | | | | * +--- sequence of curves --------+ +-end-+ * * @param {number[]} pointArray * @returns BezierPath */ static fromReducedList(pointArray: Array<number>, adjustCircular?: boolean): BezierPath; }