@tldraw/core
Version:
The tldraw core renderer and utilities.
393 lines • 14.5 kB
TypeScript
import { StrokePoint } from 'perfect-freehand';
import type React from 'react';
import type { Patch, TLBoundsWithCenter } from '../index';
import { TLBounds, TLBoundsCorner, TLBoundsEdge } from '../types';
import './polyfills';
export declare class Utils {
/**
* Linear interpolation betwen two numbers.
* @param y1
* @param y2
* @param mu
*/
static lerp(y1: number, y2: number, mu: number): number;
/**
* Linear interpolation between two colors.
*
* ### Example
*
*```ts
* lerpColor("#000000", "#0099FF", .25)
*```
*/
static lerpColor(color1: string, color2: string, factor?: number): string;
/**
* Modulate a value between two ranges.
* @param value
* @param rangeA from [low, high]
* @param rangeB to [low, high]
* @param clamp
*/
static modulate(value: number, rangeA: number[], rangeB: number[], clamp?: boolean): number;
/**
* Clamp a value into a range.
* @param n
* @param min
*/
static clamp(n: number, min: number): number;
static clamp(n: number, min: number, max: number): number;
/**
* Recursively clone an object or array.
* @param obj
*/
static deepClone<T>(obj: T): T;
/**
* Seeded random number generator, using [xorshift](https://en.wikipedia.org/wiki/Xorshift).
* The result will always be betweeen -1 and 1.
*
* Adapted from [seedrandom](https://github.com/davidbau/seedrandom).
*/
static rng(seed?: string): () => number;
static pointsToLineSegments(points: number[][], closed?: boolean): number[][][];
static getRectangleSides(point: number[], size: number[], rotation?: number): [string, number[][]][];
/**
* Get a circle from three points.
* @param A
* @param B
* @param C
* @returns [x, y, r]
*/
static circleFromThreePoints(A: number[], B: number[], C: number[]): number[];
/**
* Find the approximate perimeter of an ellipse.
* @param rx
* @param ry
*/
static perimeterOfEllipse(rx: number, ry: number): number;
/**
* Get the short angle distance between two angles.
* @param a0
* @param a1
*/
static shortAngleDist(a0: number, a1: number): number;
/**
* Get the long angle distance between two angles.
* @param a0
* @param a1
*/
static longAngleDist(a0: number, a1: number): number;
/**
* Interpolate an angle between two angles.
* @param a0
* @param a1
* @param t
*/
static lerpAngles(a0: number, a1: number, t: number): number;
/**
* Get the short distance between two angles.
* @param a0
* @param a1
*/
static angleDelta(a0: number, a1: number): number;
/**
* Get the "sweep" or short distance between two points on a circle's perimeter.
* @param C
* @param A
* @param B
*/
static getSweep(C: number[], A: number[], B: number[]): number;
/**
* Clamp radians within 0 and 2PI
* @param r
*/
static clampRadians(r: number): number;
/**
* Clamp rotation to even segments.
* @param r
* @param segments
*/
static snapAngleToSegments(r: number, segments: number): number;
/**
* Is angle c between angles a and b?
* @param a
* @param b
* @param c
*/
static isAngleBetween(a: number, b: number, c: number): boolean;
/**
* Convert degrees to radians.
* @param d
*/
static degreesToRadians(d: number): number;
/**
* Convert radians to degrees.
* @param r
*/
static radiansToDegrees(r: number): number;
/**
* Get the length of an arc between two points on a circle's perimeter.
* @param C
* @param r
* @param A
* @param B
*/
static getArcLength(C: number[], r: number, A: number[], B: number[]): number;
static getSweepFlag(A: number[], B: number[], C: number[]): 0 | 1;
static getLargeArcFlag(A: number[], C: number[], P: number[]): 0 | 1;
/**
* Get a dash offset for an arc, based on its length.
* @param C
* @param r
* @param A
* @param B
* @param step
*/
static getArcDashOffset(C: number[], r: number, A: number[], B: number[], step: number): number;
/**
* Get a dash offset for an ellipse, based on its length.
* @param A
* @param step
*/
static getEllipseDashOffset(A: number[], step: number): number;
/**
* Get whether a point is inside of a circle.
* @param A
* @param b
* @returns
*/
static pointInCircle(A: number[], C: number[], r: number): boolean;
/**
* Get whether a point is inside of an ellipse.
* @param point
* @param center
* @param rx
* @param ry
* @param rotation
* @returns
*/
static pointInEllipse(A: number[], C: number[], rx: number, ry: number, rotation?: number): boolean;
/**
* Get whether a point is inside of a rectangle.
* @param point
* @param size
*/
static pointInRect(point: number[], size: number[]): boolean;
static pointInPolygon(p: number[], points: number[][]): boolean;
/**
* Get whether a point is inside of a bounds.
* @param A The point to check.
* @param b The bounds to check.
* @returns
*/
static pointInBounds(A: number[], b: TLBounds): boolean;
/**
* Hit test a point and a polyline using a minimum distance.
* @param A The point to check.
* @param points The points that make up the polyline.
* @param distance (optional) The mininum distance that qualifies a hit.
*/
static pointInPolyline(A: number[], points: number[][], distance?: number): boolean;
static getBoundsSides(bounds: TLBounds): [string, number[][]][];
/**
* Expand a bounding box by a delta.
*
* ### Example
*
*```ts
* expandBounds(myBounds, [100, 100])
*```
*/
static expandBounds(bounds: TLBounds, delta: number): TLBounds;
/**
* Get whether two bounds collide.
* @param a Bounds
* @param b Bounds
* @returns
*/
static boundsCollide(a: TLBounds, b: TLBounds): boolean;
/**
* Get whether the bounds of A contain the bounds of B. A perfect match will return true.
* @param a Bounds
* @param b Bounds
* @returns
*/
static boundsContain(a: TLBounds, b: TLBounds): boolean;
/**
* Get whether the bounds of A are contained by the bounds of B.
* @param a Bounds
* @param b Bounds
* @returns
*/
static boundsContained(a: TLBounds, b: TLBounds): boolean;
/**
* Get whether two bounds are identical.
* @param a Bounds
* @param b Bounds
* @returns
*/
static boundsAreEqual(a: TLBounds, b: TLBounds): boolean;
/**
* Find a bounding box from an array of points.
* @param points
* @param rotation (optional) The bounding box's rotation.
*/
static getBoundsFromPoints(points: number[][], rotation?: number): TLBounds;
/**
* Center a bounding box around a given point.
* @param bounds
* @param center
*/
static centerBounds(bounds: TLBounds, point: number[]): TLBounds;
/**
* Snap a bounding box to a grid size.
* @param bounds
* @param gridSize
*/
static snapBoundsToGrid(bounds: TLBounds, gridSize: number): TLBounds;
/**
* Move a bounding box without recalculating it.
* @param bounds
* @param delta
* @returns
*/
static translateBounds(bounds: TLBounds, delta: number[]): TLBounds;
/**
* Rotate a bounding box.
* @param bounds
* @param center
* @param rotation
*/
static rotateBounds(bounds: TLBounds, center: number[], rotation: number): TLBounds;
/**
* Get the rotated bounds of an ellipse.
* @param x
* @param y
* @param rx
* @param ry
* @param rotation
*/
static getRotatedEllipseBounds(x: number, y: number, rx: number, ry: number, rotation?: number): TLBounds;
/**
* Get a bounding box that includes two bounding boxes.
* @param a Bounding box
* @param b Bounding box
* @returns
*/
static getExpandedBounds(a: TLBounds, b: TLBounds): TLBounds;
/**
* Get the common bounds of a group of bounds.
* @returns
*/
static getCommonBounds(bounds: TLBounds[]): TLBounds;
static getRotatedCorners(b: TLBounds, rotation?: number): number[][];
static getTransformedBoundingBox(bounds: TLBounds, handle: TLBoundsCorner | TLBoundsEdge | 'center', delta: number[], rotation?: number, isAspectRatioLocked?: boolean): TLBounds & {
scaleX: number;
scaleY: number;
};
static getTransformAnchor(type: TLBoundsEdge | TLBoundsCorner, isFlippedX: boolean, isFlippedY: boolean): TLBoundsCorner | TLBoundsEdge;
/**
* Get the relative bounds (usually a child) within a transformed bounding box.
* @param bounds
* @param initialBounds
* @param initialShapeBounds
* @param isFlippedX
* @param isFlippedY
*/
static getRelativeTransformedBoundingBox(bounds: TLBounds, initialBounds: TLBounds, initialShapeBounds: TLBounds, isFlippedX: boolean, isFlippedY: boolean): TLBounds;
/**
* Get the size of a rotated box.
* @param size : ;
* @param rotation
*/
static getRotatedSize(size: number[], rotation: number): number[];
/**
* Get the center of a bounding box.
* @param bounds
*/
static getBoundsCenter(bounds: TLBounds): number[];
/**
* Get a bounding box with a midX and midY.
* @param bounds
*/
static getBoundsWithCenter(bounds: TLBounds): TLBoundsWithCenter;
/**
* Given a set of points, get their common [minX, minY].
* @param points
*/
static getCommonTopLeft(points: number[][]): number[];
static getSnapPoints: (bounds: TLBoundsWithCenter, others: TLBoundsWithCenter[], snapDistance: number) => {
offset: number[];
snapLines: number[][][];
};
static deepMerge: <T>(target: T, patch: Partial<{ [P in keyof T]: T | Partial<T> | Partial<T[P] extends infer T_1 ? { [P_1 in keyof T_1]: T[P] | Partial<T[P]> | Partial<T[P][P_1] extends infer T_2 ? { [P_2 in keyof T_2]: T[P][P_1] | Partial<T[P][P_1]> | Partial<T[P][P_1][P_2] extends infer T_3 ? { [P_3 in keyof T_3]: T[P][P_1][P_2] | Partial<T[P][P_1][P_2]> | Partial<T[P][P_1][P_2][P_3] extends infer T_4 ? { [P_4 in keyof T_4]: T[P][P_1][P_2][P_3] | Partial<T[P][P_1][P_2][P_3]> | Partial<T[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { [P_5 in keyof T_5]: T[P][P_1][P_2][P_3][P_4] | Partial<T[P][P_1][P_2][P_3][P_4]> | Partial<T[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { [P_6 in keyof T_6]: T[P][P_1][P_2][P_3][P_4][P_5] | Partial<T[P][P_1][P_2][P_3][P_4][P_5]> | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { [P_7 in keyof T_7]: T[P][P_1][P_2][P_3][P_4][P_5][P_6] | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6]> | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { [P_8 in keyof T_8]: T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7]> | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { [P_9 in keyof T_9]: T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8]> | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { [P_10 in keyof T_10]: T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] | Partial<T[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9]> | Partial<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; }>) => T;
/**
* Get a value from a cache (a WeakMap), filling the value if it is not present.
*
* ### Example
*
*```ts
* getFromCache(boundsCache, shape, (cache) => cache.set(shape, "value"))
*```
*/
static getFromCache<V, I extends object>(cache: WeakMap<I, V>, item: I, getNext: () => V): V;
/**
* Get a unique string id.
*/
static uniqueId(a?: string): string;
/**
* Shuffle the contents of an array.
* @param arr
* @param offset
*/
static rotateArray<T>(arr: T[], offset: number): T[];
/**
* Debounce a function.
*/
static debounce<T extends (...args: any[]) => void>(fn: T, ms?: number): (...args: Parameters<T>) => void;
/**
* Turn an array of points into a path of quadradic curves.
*
* @param points The points returned from perfect-freehand
* @param closed Whether the stroke is closed
*/
static getSvgPathFromStroke(points: number[][], closed?: boolean): string;
/**
* Turn an array of stroke points into a path of quadradic curves.
* @param points - the stroke points returned from perfect-freehand
*/
static getSvgPathFromStrokePoints(points: StrokePoint[], closed?: boolean): string;
/**
* Get balanced dash-strokearray and dash-strokeoffset properties for a path of a given length.
* @param length The length of the path.
* @param strokeWidth The shape's stroke-width property.
* @param style The stroke's style: "dashed" or "dotted" (default "dashed").
* @param snap An interval for dashes (e.g. 4 will produce arrays with 4, 8, 16, etc dashes).
* @param outset Whether to outset the stroke (default false).
* @param lengthRatio The ratio to apply to dashed lines (default 2).
*/
static getPerfectDashProps(length: number, strokeWidth: number, style: 'dashed' | 'dotted' | string, snap?: number, outset?: boolean, lengthRatio?: number): {
strokeDasharray: string;
strokeDashoffset: string;
};
static isMobileSafari(): boolean;
static throttle<T extends (...args: any) => any>(func: T, limit: number): (...args: Parameters<T>) => ReturnType<T>;
/**
* Find whether the current display is a touch display.
*/
/**
* Find whether the current device is a Mac / iOS / iPadOS.
*/
static isDarwin(): boolean;
/**
* Get whether an event is command (mac) or control (pc).
* @param e
*/
static metaKey(e: KeyboardEvent | React.KeyboardEvent): boolean;
/**
* Reversable psuedo hash.
* @param str string
*/
static lns(str: string): string;
}
export default Utils;
//# sourceMappingURL=utils.d.ts.map