modern-path2d 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +527 -130
- package/dist/index.d.cts +141 -2
- package/dist/index.d.mts +141 -2
- package/dist/index.d.ts +141 -2
- package/dist/index.js +3 -2
- package/dist/index.mjs +523 -131
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -249,6 +249,20 @@ declare class Transform2D {
|
|
|
249
249
|
destroy(): void;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
type BooleanOp = 'union' | 'intersection' | 'difference' | 'xor';
|
|
253
|
+
/**
|
|
254
|
+
* A flat ring: `[x0, y0, x1, y1, …]` (the same layout {@link Curve.getAdaptiveVertices} produces).
|
|
255
|
+
* A path is described as an array of such rings (one per sub-path).
|
|
256
|
+
*/
|
|
257
|
+
type FlatRing = number[];
|
|
258
|
+
/**
|
|
259
|
+
* Boolean operation between two ring soups, returning the result as flat rings (shells wound
|
|
260
|
+
* counter-clockwise, holes clockwise — so a nonzero fill renders them correctly). Powered by the
|
|
261
|
+
* Martinez–Rueda sweep-line clipper (`polygon-clipping`); because the inputs are sampled outlines,
|
|
262
|
+
* the result is a polygonal approximation of curved paths.
|
|
263
|
+
*/
|
|
264
|
+
declare function polygonBoolean(op: BooleanOp, ringsA: FlatRing[], ringsB: FlatRing[]): FlatRing[];
|
|
265
|
+
|
|
252
266
|
declare function catmullRom(t: number, p0: number, p1: number, p2: number, p3: number): number;
|
|
253
267
|
|
|
254
268
|
interface CssFunctionArg {
|
|
@@ -274,6 +288,25 @@ declare function parseCssArg(name: string, value: string, context?: ParseCssFunc
|
|
|
274
288
|
|
|
275
289
|
declare function cubicBezier(t: number, p0: number, p1: number, p2: number, p3: number): number;
|
|
276
290
|
|
|
291
|
+
interface EvenoddFillRuleResult {
|
|
292
|
+
index: number;
|
|
293
|
+
/** Containment depth: 0/2/4… are filled shells, 1/3/5… are holes. */
|
|
294
|
+
depth: number;
|
|
295
|
+
/** Immediate enclosing ring (deepest container), or -1 for a top-level ring. */
|
|
296
|
+
parentIndex: number;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Even-odd nesting of a ring soup: classify each ring by how many other rings contain it.
|
|
300
|
+
* Even depth → a filled shell; odd depth → a hole. Each ring also gets its immediate parent
|
|
301
|
+
* (the deepest container), so a shell can collect exactly the holes one level inside it — and
|
|
302
|
+
* an island inside a hole becomes its own shell again (nested donuts work).
|
|
303
|
+
*
|
|
304
|
+
* Mirrors {@link nonzeroFillRule}'s output shape, but uses containment parity (even-odd) instead
|
|
305
|
+
* of winding. Used by `Path2D.fillTriangulate` for `fillRule: 'evenodd'` so WebGL/triangulated
|
|
306
|
+
* fills get real holes instead of solid overlapping rings.
|
|
307
|
+
*/
|
|
308
|
+
declare function evenoddFillRule(paths: number[][]): EvenoddFillRuleResult[];
|
|
309
|
+
|
|
277
310
|
interface FillTriangulateOptions {
|
|
278
311
|
holes?: number[];
|
|
279
312
|
vertices?: number[];
|
|
@@ -375,6 +408,12 @@ interface LineStyle {
|
|
|
375
408
|
cap: LineCap;
|
|
376
409
|
miterLimit: number;
|
|
377
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Derive a triangulator {@link LineStyle} from a (partial) {@link Path2DStyle}. This is what
|
|
413
|
+
* makes `path.strokeTriangulate()` honor `style.strokeWidth` / `strokeLinejoin` / `strokeLinecap`
|
|
414
|
+
* / `strokeMiterlimit` instead of silently falling back to a 1px miter hairline.
|
|
415
|
+
*/
|
|
416
|
+
declare function resolveLineStyle(style?: Partial<Path2DStyle>): LineStyle;
|
|
378
417
|
declare function strokeTriangulate(points: number[], options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
|
|
379
418
|
|
|
380
419
|
interface IsPointInFillOptions {
|
|
@@ -413,6 +452,13 @@ declare abstract class Curve {
|
|
|
413
452
|
getPointAt(u: number, output?: Vector2): Vector2;
|
|
414
453
|
isClockwise(): boolean;
|
|
415
454
|
getControlPointRefs(): Vector2[];
|
|
455
|
+
/**
|
|
456
|
+
* Reverse the traversal direction in place (start ↔ end, same geometry). The base
|
|
457
|
+
* implementation reverses the order of the control-point *values*, which is correct for
|
|
458
|
+
* line / Bézier / spline primitives whose {@link getControlPointRefs} order matches their
|
|
459
|
+
* parametric order. {@link RoundCurve} (angle-based) and composites (child order) override it.
|
|
460
|
+
*/
|
|
461
|
+
reverse(): this;
|
|
416
462
|
applyTransform(transform: Transform2D | ((point: Vector2) => void)): this;
|
|
417
463
|
getUnevenVertices(count?: number, output?: number[]): number[];
|
|
418
464
|
getSpacedVertices(count?: number, output?: number[]): number[];
|
|
@@ -428,6 +474,16 @@ declare abstract class Curve {
|
|
|
428
474
|
getUToTMapping(u: number, distance?: number): number;
|
|
429
475
|
getTangent(t: number, output?: Vector2): Vector2;
|
|
430
476
|
getTangentAt(u: number, output?: Vector2): Vector2;
|
|
477
|
+
/**
|
|
478
|
+
* PathKit-style sample at an absolute arc-length `distance` along the curve: the point, the unit
|
|
479
|
+
* tangent, and the tangent `angle` in radians. `distance` is clamped to `[0, getLength()]`, so
|
|
480
|
+
* passing `0`/`getLength()` always yields the endpoints. See {@link PathMeasure} for a wrapper.
|
|
481
|
+
*/
|
|
482
|
+
getPosTan(distance: number): {
|
|
483
|
+
position: Vector2;
|
|
484
|
+
tangent: Vector2;
|
|
485
|
+
angle: number;
|
|
486
|
+
};
|
|
431
487
|
getNormal(t: number, output?: Vector2): Vector2;
|
|
432
488
|
getNormalAt(u: number, output?: Vector2): Vector2;
|
|
433
489
|
getTForPoint(target: Vector2Like, epsilon?: number): number;
|
|
@@ -464,6 +520,13 @@ declare abstract class Curve {
|
|
|
464
520
|
contains(x: number, y: number, options?: IsPointInFillOptions): boolean;
|
|
465
521
|
getFillVertices(_options?: FillTriangulateOptions): number[];
|
|
466
522
|
fillTriangulate(options?: FillTriangulateOptions): FillTriangulatedResult;
|
|
523
|
+
/**
|
|
524
|
+
* Whether this curve forms a closed loop (its outline should be stroked without end caps,
|
|
525
|
+
* stitching the last vertex back to the first). The base test is purely geometric — the first
|
|
526
|
+
* sampled vertex coincides with the last. Curves that close without a duplicated endpoint
|
|
527
|
+
* (a full-revolution {@link RoundCurve}, rectangles, polygons) override this.
|
|
528
|
+
*/
|
|
529
|
+
isClosed(): boolean;
|
|
467
530
|
strokeTriangulate(options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
|
|
468
531
|
toCommands(): Path2DCommand[];
|
|
469
532
|
toData(): Path2DData;
|
|
@@ -494,6 +557,13 @@ declare class RoundCurve extends Curve {
|
|
|
494
557
|
set dy(val: number);
|
|
495
558
|
constructor(_center?: Vector2, _radius?: Vector2, _diff?: Vector2, rotate?: number, startAngle?: number, endAngle?: number, clockwise?: boolean);
|
|
496
559
|
isClockwise(): boolean;
|
|
560
|
+
/**
|
|
561
|
+
* A circle/ellipse arc is closed when it sweeps (at least) a full revolution — the sampled
|
|
562
|
+
* outline does not duplicate the start vertex, so the geometric first==last test in the base
|
|
563
|
+
* class would wrongly report a full circle as open and leave a seam gap in the stroke.
|
|
564
|
+
*/
|
|
565
|
+
isClosed(): boolean;
|
|
566
|
+
reverse(): this;
|
|
497
567
|
protected _getDeltaAngle(): number;
|
|
498
568
|
getPoint(t: number, output?: Vector2): Vector2;
|
|
499
569
|
/**
|
|
@@ -541,7 +611,14 @@ declare class CompositeCurve<T extends Curve = Curve> extends Curve {
|
|
|
541
611
|
protected _removeNextPointIfEqualPrevPoint(output: number[], offset: number): number[];
|
|
542
612
|
getSpacedVertices(count?: number, output?: number[]): number[];
|
|
543
613
|
getAdaptiveVertices(output?: number[]): number[];
|
|
614
|
+
/**
|
|
615
|
+
* A composite is closed when its single child is closed (e.g. a lone full-circle arc), or when
|
|
616
|
+
* its assembled outline returns to its start (rectangles, polygons, multi-segment loops).
|
|
617
|
+
*/
|
|
618
|
+
isClosed(): boolean;
|
|
544
619
|
strokeTriangulate(options?: StrokeTriangulateOptions): StrokeTriangulatedResult;
|
|
620
|
+
/** Reverse the sub-curve order and reverse each sub-curve, so the whole outline runs backwards. */
|
|
621
|
+
reverse(): this;
|
|
545
622
|
getFillVertices(options?: FillTriangulateOptions): number[];
|
|
546
623
|
applyTransform(transform: Transform2D | ((point: Vector2) => void)): this;
|
|
547
624
|
getMinMax(min?: Vector2, max?: Vector2): {
|
|
@@ -564,6 +641,7 @@ declare class CubicBezierCurve extends Curve {
|
|
|
564
641
|
getPoint(t: number, output?: Vector2): Vector2;
|
|
565
642
|
getAdaptiveVertices(output?: number[]): number[];
|
|
566
643
|
getControlPointRefs(): Vector2[];
|
|
644
|
+
reverse(): this;
|
|
567
645
|
protected _solveQuadratic(a: number, b: number, c: number): number[];
|
|
568
646
|
getMinMax(min?: Vector2, max?: Vector2): {
|
|
569
647
|
min: Vector2;
|
|
@@ -589,6 +667,7 @@ declare class LineCurve extends Curve {
|
|
|
589
667
|
getTangent(_t: number, output?: Vector2): Vector2;
|
|
590
668
|
getTangentAt(u: number, output?: Vector2): Vector2;
|
|
591
669
|
getControlPointRefs(): Vector2[];
|
|
670
|
+
reverse(): this;
|
|
592
671
|
getAdaptiveVertices(output?: number[]): number[];
|
|
593
672
|
getMinMax(min?: Vector2, max?: Vector2): {
|
|
594
673
|
min: Vector2;
|
|
@@ -621,6 +700,7 @@ declare class QuadraticBezierCurve extends Curve {
|
|
|
621
700
|
constructor(p1?: Vector2, cp?: Vector2, p2?: Vector2);
|
|
622
701
|
getPoint(t: number, output?: Vector2): Vector2;
|
|
623
702
|
getControlPointRefs(): Vector2[];
|
|
703
|
+
reverse(): this;
|
|
624
704
|
getAdaptiveVertices(output?: number[]): number[];
|
|
625
705
|
getMinMax(min?: Vector2, max?: Vector2): {
|
|
626
706
|
min: Vector2;
|
|
@@ -665,6 +745,7 @@ declare class SplineCurve extends Curve {
|
|
|
665
745
|
constructor(points?: Vector2[]);
|
|
666
746
|
getPoint(t: number, output?: Vector2): Vector2;
|
|
667
747
|
getControlPointRefs(): Vector2[];
|
|
748
|
+
reverse(): this;
|
|
668
749
|
copyFrom(source: SplineCurve): this;
|
|
669
750
|
}
|
|
670
751
|
|
|
@@ -676,6 +757,13 @@ declare class CurvePath extends CompositeCurve {
|
|
|
676
757
|
addPoints(points: Vector2[]): this;
|
|
677
758
|
addCommands(commands: Path2DCommand[]): this;
|
|
678
759
|
addData(data: string): this;
|
|
760
|
+
/**
|
|
761
|
+
* A sub-path is closed if it was explicitly closed (`autoClose`, i.e. a `Z`/`closePath`), or if
|
|
762
|
+
* it forms a geometric loop / wraps a single closed primitive (handled by the base class).
|
|
763
|
+
*/
|
|
764
|
+
isClosed(): boolean;
|
|
765
|
+
/** Reverse direction, then refresh the {@link startPoint}/{@link currentPoint} cursors. */
|
|
766
|
+
reverse(): this;
|
|
679
767
|
protected _closeVertices(output: number[]): number[];
|
|
680
768
|
getUnevenVertices(count?: number, output?: number[]): number[];
|
|
681
769
|
getSpacedVertices(count?: number, output?: number[]): number[];
|
|
@@ -760,6 +848,23 @@ declare class Path2D<T = any> extends CompositeCurve<CurvePath> {
|
|
|
760
848
|
/** Per-sub-path sampled rings, cached for repeated hit tests. */
|
|
761
849
|
protected _getRings(): number[][];
|
|
762
850
|
isPointInFill(point: Vector2Like, options?: IsPointInFillOptions): boolean;
|
|
851
|
+
/** Build a `Path2D` from flat rings (`[x0,y0,…]` per sub-path); closed-and-filled as sub-paths. */
|
|
852
|
+
static fromRings(rings: number[][], style?: Partial<Path2DStyle>): Path2D;
|
|
853
|
+
/**
|
|
854
|
+
* Boolean (path) operation against another path, returning a NEW `Path2D` whose outline is the
|
|
855
|
+
* polygonal result. Curves are sampled before clipping, so the result is a polygonal
|
|
856
|
+
* approximation (see {@link polygonBoolean}). The result inherits this path's `style` unless
|
|
857
|
+
* overridden via `style`. Holes are emitted as oppositely-wound sub-paths (nonzero fill).
|
|
858
|
+
*/
|
|
859
|
+
booleanOp(op: BooleanOp, other: Path2D, style?: Partial<Path2DStyle>): Path2D;
|
|
860
|
+
/** `this ∪ other` — the combined filled area. */
|
|
861
|
+
union(other: Path2D, style?: Partial<Path2DStyle>): Path2D;
|
|
862
|
+
/** `this ∩ other` — only the overlapping area. */
|
|
863
|
+
intersection(other: Path2D, style?: Partial<Path2DStyle>): Path2D;
|
|
864
|
+
/** `this − other` — this path with `other` cut away. */
|
|
865
|
+
difference(other: Path2D, style?: Partial<Path2DStyle>): Path2D;
|
|
866
|
+
/** `this ⊕ other` — areas covered by exactly one of the two paths. */
|
|
867
|
+
xor(other: Path2D, style?: Partial<Path2DStyle>): Path2D;
|
|
763
868
|
/**
|
|
764
869
|
* Test whether a point lies on this path's stroke. A hit on any sub-path counts.
|
|
765
870
|
*
|
|
@@ -833,6 +938,40 @@ declare class Path2DSet<T = any> {
|
|
|
833
938
|
}>): HTMLCanvasElement;
|
|
834
939
|
}
|
|
835
940
|
|
|
941
|
+
interface PosTan {
|
|
942
|
+
position: Vector2;
|
|
943
|
+
tangent: Vector2;
|
|
944
|
+
angle: number;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* PathKit/Skia-style arc-length measurement over any {@link Curve} (including `CurvePath` and
|
|
948
|
+
* `Path2D`). Wraps the curve's existing arc-length cache, so repeated queries are cheap.
|
|
949
|
+
*
|
|
950
|
+
* ```ts
|
|
951
|
+
* const measure = new PathMeasure(path)
|
|
952
|
+
* const { position, angle } = measure.getPosTan(measure.getLength() * progress)
|
|
953
|
+
* ```
|
|
954
|
+
*/
|
|
955
|
+
declare class PathMeasure {
|
|
956
|
+
curve: Curve;
|
|
957
|
+
constructor(curve: Curve);
|
|
958
|
+
/** Total arc length of the path. */
|
|
959
|
+
getLength(): number;
|
|
960
|
+
/** Whether the path forms a closed loop (see {@link Curve.isClosed}). */
|
|
961
|
+
isClosed(): boolean;
|
|
962
|
+
/** Point + unit tangent + tangent angle at an absolute arc-length `distance` (clamped). */
|
|
963
|
+
getPosTan(distance: number): PosTan;
|
|
964
|
+
/** Point at an absolute arc-length `distance` (clamped to `[0, getLength()]`). */
|
|
965
|
+
getPosition(distance: number): Vector2;
|
|
966
|
+
/** Point + tangent at a normalized progress `t ∈ [0, 1]` along the path. */
|
|
967
|
+
getPosTanAtProgress(t: number): PosTan;
|
|
968
|
+
/**
|
|
969
|
+
* Evenly sample the path into `count + 1` {@link PosTan} entries (arc-length spaced), e.g. to
|
|
970
|
+
* lay glyphs along a path or drive an `animate(progress)`-style traversal.
|
|
971
|
+
*/
|
|
972
|
+
sample(count?: number): PosTan[];
|
|
973
|
+
}
|
|
974
|
+
|
|
836
975
|
declare class FFDControlGrid {
|
|
837
976
|
rows: number;
|
|
838
977
|
cols: number;
|
|
@@ -875,5 +1014,5 @@ declare function svgToDom(svg: string | SVGElement): SVGElement;
|
|
|
875
1014
|
|
|
876
1015
|
declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
|
|
877
1016
|
|
|
878
|
-
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPolygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PolygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, pointInPolygon, pointInPolygons, pointToPolylineDistance, pointToSegmentDistance, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
|
|
879
|
-
export type { CssFunction, CssFunctionArg, DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, IsPointInFillOptions, IsPointInStrokeOptions, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
|
|
1017
|
+
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPolygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PathMeasure, PolygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, evenoddFillRule, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, pointInPolygon, pointInPolygons, pointToPolylineDistance, pointToSegmentDistance, polygonBoolean, quadraticBezier, resolveLineStyle, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
|
|
1018
|
+
export type { BooleanOp, CssFunction, CssFunctionArg, DrawPointOptions, EvenoddFillRuleResult, FillRule, FillTriangulateOptions, FillTriangulatedResult, FlatRing, IsPointInFillOptions, IsPointInStrokeOptions, LineCap, LineJoin, LineStyle, ParseCssFunctionContext, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, PosTan, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, TransformableObject, TriangulatedResult, Vector2Like };
|