moves svg utils into its own package

This commit is contained in:
Steve Ruiz 2021-10-22 20:03:22 +01:00
parent f8ede2eab2
commit b94c97aafe
22 changed files with 311 additions and 597 deletions

View file

@ -13,9 +13,10 @@
"packages/core", "packages/core",
"packages/tldraw", "packages/tldraw",
"packages/dev", "packages/dev",
"packages/www",
"packages/vec", "packages/vec",
"packages/intersect" "packages/svg",
"packages/intersect",
"packages/www"
], ],
"scripts": { "scripts": {
"test": "jest", "test": "jest",

View file

@ -1 +0,0 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAE3B,eAAe,KAAK,CAAA"}

View file

@ -1,5 +1,4 @@
import { Utils } from './utils' import { Utils } from './utils'
export { Utils } from './utils' export { Utils } from './utils'
export { Svg } from './svg'
export default Utils export default Utils

View file

@ -1 +0,0 @@
//# sourceMappingURL=polyfills.d.ts.map

View file

@ -1 +0,0 @@
{"version":3,"file":"polyfills.d.ts","sourceRoot":"","sources":["polyfills.ts"],"names":[],"mappings":""}

View file

@ -1,15 +0,0 @@
export declare class Svg {
static ellipse: (A: number[], r: number) => string;
static moveTo: (v: number[]) => string;
static lineTo: (v: number[]) => string;
static line: (a: number[], ...pts: number[][]) => string;
static hLineTo: (v: number[]) => string;
static vLineTo: (v: number[]) => string;
static bezierTo: (A: number[], B: number[], C: number[]) => string;
static arcTo: (C: number[], r: number, A: number[], B: number[]) => string;
static closePath: () => string;
static rectTo: (A: number[]) => string;
static getPointAtLength: (path: SVGPathElement, length: number) => number[];
}
export default Svg;
//# sourceMappingURL=svg.d.ts.map

View file

@ -1 +0,0 @@
{"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["svg.ts"],"names":[],"mappings":"AAIA,qBAAa,GAAG;IACd,MAAM,CAAC,OAAO,MAAO,MAAM,EAAE,KAAK,MAAM,KAAG,MAAM,CAIhD;IAED,MAAM,CAAC,MAAM,MAAO,MAAM,EAAE,KAAG,MAAM,CAEpC;IAED,MAAM,CAAC,MAAM,MAAO,MAAM,EAAE,KAAG,MAAM,CAEpC;IAED,MAAM,CAAC,IAAI,MAAO,MAAM,EAAE,UAAU,MAAM,EAAE,EAAE,KAAG,MAAM,CAEtD;IAED,MAAM,CAAC,OAAO,MAAO,MAAM,EAAE,KAAG,MAAM,CAErC;IAED,MAAM,CAAC,OAAO,MAAO,MAAM,EAAE,KAAG,MAAM,CAErC;IAED,MAAM,CAAC,QAAQ,MAAO,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,KAAG,MAAM,CAEhE;IAED,MAAM,CAAC,KAAK,MAAO,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,KAAG,MAAM,CAYxE;IAED,MAAM,CAAC,SAAS,QAAO,MAAM,CAE5B;IAED,MAAM,CAAC,MAAM,MAAO,MAAM,EAAE,KAAG,MAAM,CAEpC;IAED,MAAM,CAAC,gBAAgB,SAAU,cAAc,UAAU,MAAM,KAAG,MAAM,EAAE,CAGzE;CACF;AAED,eAAe,GAAG,CAAA"}

View file

@ -1,64 +0,0 @@
import { Utils } from './utils'
// General
export class Svg {
static ellipse = (A: number[], r: number): string => {
return `M ${A[0] - r},${A[1]}
a ${r},${r} 0 1,0 ${r * 2},0
a ${r},${r} 0 1,0 -${r * 2},0 `
}
static moveTo = (v: number[]): string => {
return `M ${v[0]},${v[1]} `
}
static lineTo = (v: number[]): string => {
return `L ${v[0]},${v[1]} `
}
static line = (a: number[], ...pts: number[][]): string => {
return Svg.moveTo(a) + pts.map((p): string => Svg.lineTo(p)).join()
}
static hLineTo = (v: number[]): string => {
return `H ${v[0]},${v[1]} `
}
static vLineTo = (v: number[]): string => {
return `V ${v[0]},${v[1]} `
}
static bezierTo = (A: number[], B: number[], C: number[]): string => {
return `C ${A[0]},${A[1]} ${B[0]},${B[1]} ${C[0]},${C[1]} `
}
static arcTo = (C: number[], r: number, A: number[], B: number[]): string => {
return [
Svg.moveTo(A),
'A',
r,
r,
0,
0,
Utils.getArcLength(C, r, A, B) > 0 ? '1' : '0',
B[0],
B[1],
].join(' ')
}
static closePath = (): string => {
return 'Z'
}
static rectTo = (A: number[]): string => {
return ['R', A[0], A[1]].join(' ')
}
static getPointAtLength = (path: SVGPathElement, length: number): number[] => {
const point = path.getPointAtLength(length)
return [point.x, point.y]
}
}
export default Svg

View file

@ -1,497 +0,0 @@
import type React from 'react';
import { TLBezierCurveSegment, TLBounds, TLBoundsCorner, TLBoundsEdge } from '../types';
import './polyfills';
import type { TLBoundsWithCenter } from '+index';
export declare class Utils {
static filterObject<T extends object>(obj: T, fn: (entry: Entry<T>, i?: number, arr?: Entry<T>[]) => boolean): Partial<T>;
static deepMerge: <T>(target: T, patch: any) => T;
/**
* 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;
static compress(s: string): string;
static decompress(s: string): string;
/**
* Recursively clone an object or array.
* @param obj
*/
static deepClone<T extends unknown>(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 getRectangleSides(point: number[], size: number[], rotation?: number): [string, number[][]][];
static getBoundsSides(bounds: TLBounds): [string, number[][]][];
static shallowEqual<T extends Record<string, unknown>>(objA: T, objB: T): boolean;
/**
* Get the outer of between a circle and a point.
* @param C The circle's center.
* @param r The circle's radius.
* @param P The point.
* @param side
*/
static getCircleTangentToPoint(C: number[], r: number, P: number[], side: number): number[] | null;
/**
* Get outer tangents of two circles.
* @param x0
* @param y0
* @param r0
* @param x1
* @param y1
* @param r1
* @returns [lx0, ly0, lx1, ly1, rx0, ry0, rx1, ry1]
*/
static getOuterTangentsOfCircles(C0: number[], r0: number, C1: number[], r1: number): number[][] | null;
/**
* Get the closest point on the perimeter of a circle to a given point.
* @param C The circle's center.
* @param r The circle's radius.
* @param P The point.
*/
static getClosestPointOnCircle(C: number[], r: number, P: number[]): 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;
/**
* Rotate a point around a center.
* @param x The x-axis coordinate of the point.
* @param y The y-axis coordinate of the point.
* @param cx The x-axis coordinate of the point to rotate round.
* @param cy The y-axis coordinate of the point to rotate round.
* @param angle The distance (in radians) to rotate.
*/
static rotatePoint(A: number[], B: number[], angle: 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;
/**
* 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 bezier curve segments that pass through an array of points.
* @param points
* @param tension
*/
static getTLBezierCurveSegments(points: number[][], tension?: number): TLBezierCurveSegment[];
/**
* Find a point along a curve segment, via pomax.
* @param t
* @param points [cpx1, cpy1, cpx2, cpy2, px, py][]
*/
static computePointOnCurve(t: number, points: number[][]): number[];
/**
* Evaluate a 2d cubic bezier at a point t on the x axis.
* @param tx
* @param x1
* @param y1
* @param x2
* @param y2
*/
static cubicBezier(tx: number, x1: number, y1: number, x2: number, y2: number): number;
/**
* Get a bezier curve data for a spline that fits an array of points.
* @param points An array of points formatted as [x, y]
* @param k Tension
*/
static getSpline(pts: number[][], k?: number): {
cp1x: number;
cp1y: number;
cp2x: number;
cp2y: number;
px: number;
py: number;
}[];
/**
* Get a bezier curve data for a spline that fits an array of points.
* @param pts
* @param tension
* @param isClosed
* @param numOfSegments
*/
static getCurvePoints(pts: number[][], tension?: number, isClosed?: boolean, numOfSegments?: number): number[][];
/**
* Simplify a line (using Ramer-Douglas-Peucker algorithm).
* @param points An array of points as [x, y, ...][]
* @param tolerance The minimum line distance (also called epsilon).
* @returns Simplified array as [x, y, ...][]
*/
static simplify(points: number[][], tolerance?: 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;
/**
* Expand a bounding box by a delta.
*
* ### Example
*
*```ts
* expandBounds(myBounds, [100, 100])
*```
*/
static expandBounds(bounds: TLBounds, delta: number): TLBounds;
/**
* Get whether a point is inside of a bounds.
* @param A
* @param b
* @returns
*/
static pointInBounds(A: number[], b: TLBounds): boolean;
/**
* 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;
/**
* 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): TLBounds & {
midX: number;
midY: number;
};
static getSnapPoints: (bounds: any, others: TLBoundsWithCenter[], snapDistance: number) => {
offset: number[];
snapLines: number[][][];
};
/**
*
*
* ### Example
*
*```ts
* example
*```
*/
static removeDuplicatePoints(points: number[][]): number[][];
/**
// points =
/**
* 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[];
/**
* Deep compare two arrays.
* @param a
* @param b
*/
static deepCompareArrays<T>(a: T[], b: T[]): boolean;
/**
* Deep compare any values.
* @param a
* @param b
*/
static deepCompare<T>(a: T, b: T): boolean;
/**
* Find whether two arrays intersect.
* @param a
* @param b
* @param fn An optional function to apply to the items of a; will check if b includes the result.
*/
static arrsIntersect<T, K>(a: T[], b: K[], fn?: (item: K) => T): boolean;
static arrsIntersect<T>(a: T[], b: T[]): boolean;
/**
* Get the unique values from an array of strings or numbers.
* @param items
*/
static uniqueArray<T extends string | number>(...items: T[]): T[];
/**
* Convert a set to an array.
* @param set
*/
static setToArray<T>(set: Set<T>): T[];
/**
* Debounce a function.
*/
static debounce<T extends (...args: any[]) => void>(fn: T, ms?: number): (...args: Parameters<T>) => void;
static TRIM_NUMBERS: RegExp;
/**
* Turn an array of points into a path of quadradic curves.
* @param stroke ;
*/
static getSvgPathFromStroke(points: number[][], 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).
*/
static getPerfectDashProps(length: number, strokeWidth: number, style: 'dashed' | 'dotted' | string, snap?: number, outset?: boolean): {
strokeDasharray: string;
strokeDashoffset: string;
};
static isMobileSize(): boolean;
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;
}
export default Utils;
declare type Entry<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T];
//# sourceMappingURL=utils.d.ts.map

File diff suppressed because one or more lines are too long

View file

@ -40,4 +40,4 @@
"typescript": "4.2.3" "typescript": "4.2.3"
}, },
"gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6" "gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
} }

View file

@ -2,7 +2,7 @@
"name": "@tldraw/intersect", "name": "@tldraw/intersect",
"version": "0.0.126", "version": "0.0.126",
"private": false, "private": false,
"description": "A tiny little drawing app (intersect)", "description": "Intersection utilities for tldraw.",
"author": "@steveruizok", "author": "@steveruizok",
"repository": { "repository": {
"type": "git", "type": "git",
@ -21,7 +21,7 @@
"typings": "./dist/types/index.d.ts", "typings": "./dist/types/index.d.ts",
"scripts": { "scripts": {
"start:pre": "node scripts/pre-dev && yarn types:pre", "start:pre": "node scripts/pre-dev && yarn types:pre",
"start": "node scripts/dev & yarn types:dev", "start:utils": "node scripts/dev & yarn types:dev",
"build": "node scripts/build && yarn types:build", "build": "node scripts/build && yarn types:build",
"types:pre": "tsc", "types:pre": "tsc",
"types:dev": "tsc --watch", "types:dev": "tsc --watch",
@ -33,8 +33,6 @@
"docs:watch": "typedoc --watch" "docs:watch": "typedoc --watch"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.15.5",
"@babel/preset-env": "^7.15.4",
"@types/jest": "^27.0.1", "@types/jest": "^27.0.1",
"@types/node": "^16.7.10", "@types/node": "^16.7.10",
"@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/eslint-plugin": "^4.30.0",
@ -42,7 +40,6 @@
"esbuild": "^0.13.8", "esbuild": "^0.13.8",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"lerna": "^4.0.0", "lerna": "^4.0.0",
"ts-node": "^10.2.1",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"typedoc": "^0.22.3", "typedoc": "^0.22.3",
"typescript": "^4.4.2" "typescript": "^4.4.2"
@ -51,4 +48,4 @@
"@tldraw/vec": "^0.0.126" "@tldraw/vec": "^0.0.126"
}, },
"gitHead": "5cb031ddc264846ec6732d7179511cddea8ef034" "gitHead": "5cb031ddc264846ec6732d7179511cddea8ef034"
} }

21
packages/svg/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Stephen Ruiz Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
packages/svg/README.md Normal file
View file

@ -0,0 +1,3 @@
# @tldraw/svg
SVG utilities.

48
packages/svg/package.json Normal file
View file

@ -0,0 +1,48 @@
{
"name": "@tldraw/svg",
"version": "0.0.126",
"private": false,
"description": "SVG utilities for tldraw.",
"author": "@steveruizok",
"repository": {
"type": "git",
"url": "git+https://github.com/tldraw/tldraw.git",
"directory": "packages/vec"
},
"license": "MIT",
"keywords": [],
"files": [
"dist/**/*"
],
"sideEffects": false,
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"types": "./dist/types/index.d.ts",
"typings": "./dist/types/index.d.ts",
"scripts": {
"start:pre": "node scripts/pre-dev && yarn types:pre",
"start:utils": "node scripts/dev & yarn types:dev",
"build": "node scripts/build && yarn types:build",
"types:pre": "tsc",
"types:dev": "tsc --watch",
"types:build": "tsc --project tsconfig.build.json",
"lint": "eslint src/ --ext .ts,.tsx",
"clean": "rm -rf dist",
"ts-node": "ts-node",
"docs": "typedoc",
"docs:watch": "typedoc --watch"
},
"devDependencies": {
"@types/jest": "^27.0.1",
"@types/node": "^16.7.10",
"@typescript-eslint/eslint-plugin": "^4.30.0",
"@typescript-eslint/parser": "^4.30.0",
"esbuild": "^0.13.8",
"eslint": "^7.32.0",
"lerna": "^4.0.0",
"tslib": "^2.3.1",
"typedoc": "^0.22.3",
"typescript": "^4.4.2"
},
"gitHead": "5cb031ddc264846ec6732d7179511cddea8ef034"
}

View file

@ -0,0 +1,65 @@
/* eslint-disable */
const fs = require('fs')
const esbuild = require('esbuild')
const { gzip } = require('zlib')
const name = process.env.npm_package_name || ''
async function main() {
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
try {
esbuild.buildSync({
entryPoints: ['./src/index.ts'],
outdir: 'dist/cjs',
minify: true,
bundle: true,
format: 'cjs',
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.build.json',
external: ['react', 'react-dom'],
})
const esmResult = esbuild.buildSync({
entryPoints: ['./src/index.ts'],
outdir: 'dist/esm',
minify: true,
bundle: true,
format: 'esm',
target: 'es6',
tsconfig: './tsconfig.build.json',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
external: ['react', 'react-dom'],
metafile: true,
})
let esmSize = 0
Object.values(esmResult.metafile.outputs).forEach((output) => {
esmSize += output.bytes
})
fs.readFile('./dist/esm/index.js', (_err, data) => {
gzip(data, (_err, result) => {
console.log(
`${name}: Built package. ${(esmSize / 1000).toFixed(2)}kb (${(
result.length / 1000
).toFixed(2)}kb minified)`
)
})
})
} catch (e) {
console.log(`× ${name}: Build failed due to an error.`)
console.log(e)
}
}
main()

View file

@ -0,0 +1,31 @@
/* eslint-disable */
const esbuild = require('esbuild')
const name = process.env.npm_package_name || ''
async function main() {
esbuild.build({
entryPoints: ['./src/index.ts'],
outdir: 'dist/cjs',
minify: false,
bundle: true,
format: 'cjs',
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.json',
external: ['react', 'react-dom'],
incremental: true,
watch: {
onRebuild(error) {
if (error) {
console.log(`× ${name}: An error in prevented the rebuild.`)
return
}
console.log(`${name}: Rebuilt.`)
},
},
})
}
main()

View file

@ -0,0 +1,28 @@
/* eslint-disable */
const fs = require('fs')
const esbuild = require('esbuild')
async function main() {
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
esbuild.build({
entryPoints: ['./src/index.ts'],
outdir: 'dist/cjs',
minify: false,
bundle: true,
format: 'cjs',
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.json',
external: ['react', 'react-dom'],
})
}
main()

63
packages/svg/src/index.ts Normal file
View file

@ -0,0 +1,63 @@
// General
function angle(A: number[], B: number[]): number {
return Math.atan2(B[1] - A[1], B[0] - A[0])
}
function shortAngleDist(A: number, B: number) {
const max = Math.PI * 2
const da = (B - A) % max
return ((2 * da) % max) - da
}
function getArcLength(C: number[], r: number, A: number[], B: number[]): number {
return r * (2 * Math.PI) * (shortAngleDist(angle(C, A), angle(C, B)) / (2 * Math.PI))
}
export const moveTo = (v: number[]): string => {
return `M ${v} `
}
export const lineTo = (...v: number[][]): string => {
return `L ${v.join(' ')} `
}
export const hLineTo = (v: number[]): string => {
return `H ${v} `
}
export const vLineTo = (v: number[]): string => {
return `V ${v} `
}
export const bezierTo = (A: number[], B: number[], C: number[]): string => {
return `C ${A} ${B} ${C} `
}
export const arcTo = (C: number[], r: number, A: number[], B: number[]): string => {
return [moveTo(A), 'A', r, r, 0, 0, getArcLength(C, r, A, B) > 0 ? '1' : '0', B[0], B[1]].join(
' '
)
}
export const rectTo = (A: number[]): string => {
return `R ${A}`
}
export const ellipse = (A: number[], r: number): string => {
return `M ${A[0] - r},${A[1]}
a ${r},${r} 0 1,0 ${r * 2},0
a ${r},${r} 0 1,0 -${r * 2},0 `
}
export const line = (a: number[], ...pts: number[][]): string => {
return moveTo(a) + lineTo(...pts)
}
export const closePath = (): string => {
return 'Z'
}
export const getPointAtLength = (path: SVGPathElement, length: number): number[] => {
const point = path.getPointAtLength(length)
return [point.x, point.y]
}

View file

@ -0,0 +1,24 @@
{
"extends": "./tsconfig.json",
"exclude": [
"node_modules",
"**/*.test.tsx",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.spec.ts",
"src/test",
"dist",
"docs"
],
"compilerOptions": {
"composite": false,
"incremental": false,
"declarationMap": false,
"sourceMap": false,
"emitDeclarationOnly": true,
"paths": {
"@tldraw/vec": ["../vec"]
}
},
"references": [{ "path": "../vec" }]
}

View file

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": ["node_modules", "dist", "docs"],
"compilerOptions": {
"outDir": "./dist/types",
"rootDir": "src",
"baseUrl": "src",
"paths": {
"@tldraw/vec": ["../vec"]
}
},
"references": [{ "path": "../vec" }],
"typedocOptions": {
"entryPoints": ["src/index.ts"],
"out": "docs"
}
}

View file

@ -2,7 +2,7 @@
"name": "@tldraw/vec", "name": "@tldraw/vec",
"version": "0.0.126", "version": "0.0.126",
"private": false, "private": false,
"description": "A tiny little drawing app (vec)", "description": "Vector utilities for tldraw.",
"author": "@steveruizok", "author": "@steveruizok",
"repository": { "repository": {
"type": "git", "type": "git",
@ -21,7 +21,7 @@
"typings": "./dist/types/index.d.ts", "typings": "./dist/types/index.d.ts",
"scripts": { "scripts": {
"start:pre": "node scripts/pre-dev && yarn types:pre", "start:pre": "node scripts/pre-dev && yarn types:pre",
"start": "node scripts/dev & yarn types:dev", "start:utils": "node scripts/dev & yarn types:dev",
"build": "node scripts/build && yarn types:build", "build": "node scripts/build && yarn types:build",
"types:pre": "tsc", "types:pre": "tsc",
"types:dev": "tsc --watch", "types:dev": "tsc --watch",
@ -33,8 +33,6 @@
"docs:watch": "typedoc --watch" "docs:watch": "typedoc --watch"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.15.5",
"@babel/preset-env": "^7.15.4",
"@types/jest": "^27.0.1", "@types/jest": "^27.0.1",
"@types/node": "^16.7.10", "@types/node": "^16.7.10",
"@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/eslint-plugin": "^4.30.0",
@ -42,10 +40,9 @@
"esbuild": "^0.13.8", "esbuild": "^0.13.8",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"lerna": "^4.0.0", "lerna": "^4.0.0",
"ts-node": "^10.2.1",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"typedoc": "^0.22.3", "typedoc": "^0.22.3",
"typescript": "^4.4.2" "typescript": "^4.4.2"
}, },
"gitHead": "5cb031ddc264846ec6732d7179511cddea8ef034" "gitHead": "5cb031ddc264846ec6732d7179511cddea8ef034"
} }