Path

A representation of a two-dimensional path made up of straight and curved segments.

Constructors

Path(anchors,closed,stroke,fill)Path

Constructs a path from an array of anchors.

anchors
[]

An array of anchors

closed
boolean
false

If true, the path will form a loop

stroke
optional

A stroke style to assign

fill
optional

A fill style to assign

Path.fromPoints(points,closed)Path

Connects a series of points with lines to form a path.

points
Vec[]
closed
boolean
false
Path.fromCubicBezierPoints(points,closed)Path

Constructs a path from an array of points interpreted as cubic bezier positions.

In canvas-style drawing terms, the first point is interpreted as a "move to" command. Subsequent groups of 3 points are interpreted as "curve to" commands.

points
Vec[]
closed
boolean
false
Path.fromSegment(segment)Path

Constructs a path from a segment.

Path.fromFragments(fragments)Path

Constructs a path from a sequence of path fragments.

If sequential fragments are connected -- the second fragment starts from the position where the previous fragment ended -- they will be merged together. Otherwise, a line will be drawn in-between.

If the start and end points of the entire sequence are equal, the resulting path will be closed.

fragments
Path.fromBoundingBox(box)Path

Constructs a path from a bounding box.

Returns A clockwise closed path

Path.fromArc(center,radius,startAngle,endAngle)Path

Constructs an arc (circle segment) path.

center
radius
number
startAngle
number

The angle at the start of the arc, specified in degrees

endAngle
number

The angle at the end of the arc, specified in degrees

To construct a clockwise arc, endAngle must be greater than startAngle. If endAngle is less than startAngle, add 360° to draw a clockwise arc. For counter-clockwise, do the opposite.

if (endAngle < startAngle) {
  endAngle += 360;
}
Path.fromSmoothFunction(func,domainStart,domainEnd,tolerance)Path

Constructs a path that plots a smooth function over a given time domain.

It's important that func be a smooth function for this to produce a path. A smooth function must be continuous and should have C1 differentiability (continuous derivative).

See: https://en.wikipedia.org/wiki/Smoothness

func

The function to plot, taking a single argument "time"

domainStart
number

Start of the time domain to evaluate the function over

domainEnd
number

End of the time domain to evaluate the function over

tolerance
number

The resulting path will be considered "close enough" if it is within this distance from the true plot.

Properties

.anchorsAnchor[]

An array of anchors that makes up the path.

.closedboolean

Specifies if the path is closed. If closed, the first and last anchors will be connected by an additional segment.

.strokeStrokeoptional

The stroke style

.fill(Fill | ImageFill)optional

The fill style

Methods

.segments()(LineSegment | CubicSegment)[]

Returns an array of segments for the path.

.segmentPaths()Path[]

Returns an array of paths corresponding to each segment in the path.

.edgePaths()Path[]

A path can be broken into edges by splitting it at every corner. A corner is an anchor with non-tangent handles. This means each edge will be a path that is "smooth", i.e. all of its anchors have tangent handles.

Returns an array of edges for the path.

.length()number

Returns the approximate arc length of the path.

.signedArea()number

Returns the signed area of the path. Clockwise paths will have a positive area and counter-clockwise paths negative. Paths are assumed to be non-intersecting. Paths such as infinity (∞) that cross over themselves will have both positive and negative areas which will cancel out and give an incorrect result.

.area()number

Returns the area of the path. Paths such as infinity (∞) that cross over themselves will have both positive and negative areas which will cancel out and give an incorrect result.

.timeAtDistance(distance)number
distance
number

A positive distance

Returns the approximate time at distance along the path.

If distance is greater than the length of the path, this will return the time of the last anchor.

.distanceAtTime(time)number
time
number

A valid path time

Returns the approximate distance along the path at time.

.normalizedTime(time)number
time
number

A valid path time

Returns the canonical time for time.

If the path is closed, time will loop.

.isSameTime(time1,time2)boolean
time1
number
time2
number

Returns true if time1 and time2 correspond to the same normalized path time.

.firstAnchor()Anchor

Returns the first anchor at the start of the path.

.lastAnchor()Anchor

Returns the last anchor at the end of the path.

.endTime()number

Returns the time that corrensponds to the end of the path. This is different for closed paths to account for the closing segment.

.mixedTime(time1,time2,t)number
time1
number

The time when the mixing factor is 0

time2
number

The time when the mixing factor is 1

t
number

The mixing factor

Returns a time in-between time1 and time2. If the path is closed, return a time in the shorter of the two possible spans.

.isCorner(time)boolean
time
number

A valid path time

Returns true if the point at time is a corner, meaning that there is an anchor at time that does not have tangent handles or is an endpoint.

Note: this currently counts any anchor with zeroed handles as a corner, even if it's a 180 degree anchor.

.isSmooth()boolean

Returns true if all non-endpoint anchors have tangent handles.

.isEndpoint(time)boolean
time
number

A valid path time

Returns true if the point at time is an endpoint of the path.

Note that this will always return false for closed paths since they have no endpoints.

.anchorAtTime(time)Anchor
time
number

Returns the anchor at or before time.

.segmentAtTime(time)(LineSegment | CubicSegment)
time
number

A valid path time

Returns the segment that contains the point at time.

When called on open paths with time at its maximum, the last segment will be returned.

.positionAtTime(time)Vec
time
number

A valid path time

Returns the position on the path at time.

.derivativeAtTime(time)Vec
time
number

A valid path time

Returns the first derivative of the path at time.

.secondDerivativeAtTime(time)Vec
time
number

A valid path time

Returns the second derivative of the path at time.

The second derivative can also be thought of as the "acceleration", or change in velocity of a point moving along the curve.

.curvatureAtTime(time)number
time
number

A valid path time

Returns the curvature of the path at time.

Curvature describes how "bent" a path is at a given point. It can be thought of as the reciprocal of the radius of a circle with the same curvature. To find the radius, one can use the formula 1 / curvature.

.tangentAtTime(time)Vec
time
number

A valid path time

Returns a unit-length vector tangent to the path at time.

.normalAtTime(time)Vec
time
number

A valid path time

Returns a unit-length vector perpendicular to the path at time.

.angleAtTime(time)number
time
number

A valid path time

Returns the angle of of the tangent to the path at time.

.insertAnchorAtTime(time)(Anchor | undefined)

Attempts to insert an anchor into the path at time.

time
number

A valid path time

Returns the inserted anchor, or undefined if there already was an anchor at time

.splitAtAnchor(anchor)([Path] | [Path, Path])

Splits the path at a specific anchor.

anchor

An anchor contained within the path

Returns Two open paths if the path is already open, or one open path if the path is closed

Note: Paths returned from this method will share references to anchors in the original path.

.splitAtTime(time)([Path] | [Path, Path])

Splits the path at a specific time.

time
number

A valid path time

Returns two open paths if the path is already open, or one open path if the path is closed.

Note: Paths returned from this method will share references to anchors in the original path.

.splitAtTimes(times)Path[]

Splits the path in one or more places.

The first path will always be the one before the first split point.

times
number[]

An array of path times

Returns One or more paths, depending on the number of split times.

.roundCorners(radius)Pathchainable

Replaces sharp corners in the path with circular arcs of radius.

radius
(number | number[])

A positive number

.roundCornerAtAnchor(anchor,radius)Pathchainable

Replaces a sharp corner with a circular arc of radius at a specific anchor.

anchor

The anchor to replace

radius
number

A positive number

.slice(startTime,endTime)Path
startTime
number

A valid path time

endTime
number

A valid path time greater than startTime

Returns A new path that is the subset of the path between startTime and endTime.

.splice(orderedSplices)Pathchainable

Cuts the path and inserts each splice path between time1 and time2.

Splices are assumed to be non-overlapping and ordered such that time2 is greater than time1 and time values increase monotonically when forward-iterating through the array. Splice paths are assumed to connect at their first and last anchors sequentially.

orderedSplices
[]
.smooth()Pathchainable

Makes all anchor handles tangent, ensuring the path is fully smooth.

  • If both handles exist, their angles are averaged.
  • If one handle is zero, it mirrors the other.
  • If both handles are zero, the tangent is set perpendicular to the angle bisector of the neighboring anchors, with handle lengths set to 1/3 the distance to each neighbor.
  • Handles at the endpoints of open paths are not modified.
.warpCoordinates(mappingFunc,tolerance)Pathchainable

Warps this path using a mapping function.

mappingFunc

A function that maps a point in the original space to a point in the warped space

tolerance
number

The maximum distance between the original and warped paths, which determines how closely the warped path should follow the original path.

.mergeAnchors(mergeDistance)Pathchainable

Merges contiguous anchors of this path that are less than some distance apart from each other.

mergeDistance
number
DEFAULT_TOLERANCE

A small threshold distance. Anchors closer than this will be merged together.

Methods inherited from Geometry

.transform(transform)thischainable

Transforms this geometry.

A transform can optionally specify any of position, rotation, scale, skew and origin.

origin defines the center (in pre-transform coordinates) of the transformation for rotation, scale and skew.

// Simple translation
geometry.translate({
  position: Vec(1, 0),
});

// Rotation and scale
geometry.transform({
  rotation: 45,
  scale: 2,
});

// Complicated transform
geometry.transform({
  position: Vec(1, 1),
  rotation: 180,
  scale: Vec(2, 1),
  skew: 45,
  origin: Vec(-0.5, 0.5),
};
transform
.intersectionsWith(geometries,areaOfInterest)IntersectionResult[]
geometries

An array of geometries to intersect with.

areaOfInterest
optional

If supplied, only intersection results inside this bounding box will be returned. This can save a lot of computation if you only need to find intersections within a small area.

Returns An array of intersections between this geometry and geometries

.overlapsWith(geometries,areaOfInterest,tolerance)OverlapResult[]
geometries

An array of geometries to find overlaps with.

areaOfInterest
optional

If supplied, input geometry will be filtered so that only parts that intersect this bounding box will be tested. This can save a lot of time if only need to find overlaps within a small area.

tolerance
number
optional

The maximum distance apart two segments can be to be considered overlapping.

Returns An array of overlaps between this geometry and geometries

.distanceToIntersect(targetGeometry,direction,options)(number | undefined)
targetGeometry

The geometry to move toward.

direction

The direction to move in. This should point towards the target geometry, otherwise no intersection may be found.

options
optional

Returns approximately the smallest distance to move until this geometry intersects the target geometry.

If minOverlap is specified, the distance to move until the geometry overlaps by some minimum width will be returned instead.

Returns undefined if no intersection is found.

.clone()Path

Clone is useful when you need to make a change to geometry without changing the original.

const transformedPath = path.clone().transform({ rotation: 45 });

Returns A deep copy of this geometry

.isValid()boolean

Returns true if this geometry is valid, or false otherwise.

.affineTransform(affineMatrix)Pathchainable

Spatially transforms this geometry by an affine transformation matrix.

Affine matrices can represent any 2-dimensional transformation that keeps lines parallel.

affineMatrix
.affineTransformWithoutTranslation(affineMatrix)Pathchainable

Spatially transforms this geometry by an affine transformation matrix, excluding translation. Only rotation, scale, and skew transformations will be applied.

affineMatrix
.looseBoundingBox()(BoundingBox | undefined)

The loose bounding box may not be the smallest possible, but it's usually cheaper to compute. Use this when the exact bounding box isn't required.

Returns an axis-aligned bounding box that contains this geometry.

.boundingBox()(BoundingBox | undefined)

Returns the smallest axis-aligned bounding box that contains this geometry.

.isContainedByBoundingBox(box)boolean

Geometry is contained by a bounding box if no part of it lies beyond it's minimum and maximum.

.isIntersectedByBoundingBox(box)boolean

Geometry intersects a bounding box if part of the geometry crosses the boundary between the inside and outside of the box.

.isOverlappedByBoundingBox(box)boolean

Geometry is overlapped by a bounding box if a point can be chosen that is indside both the geometry and the box.

Geometry is overlapped by a bounding box if it's contained inside, or intersected by it.

.reverse()Pathchainable

Reverses this geometry.

.closestPoint(point,areaOfInterest)(ClosestPointResultWithTime | undefined)
point

The target point

areaOfInterest
optional

If supplied, only results inside this bounding box will be returned. This can save a lot of computation if you only need to find closest points within a small area. Typically areaOfInterest is centered on point, but this isn't required.

Returns The closest point to point that lies on this geometry, or undefined if no point is found.

.isValid(a)
a
unknown

Returns true if graphic is a valid graphic

Methods inherited from Graphic

.allCompoundPaths()CompoundPath[]

Returns all compound paths contained within this graphic, recursively.

.allPathsByColor()Path[][]

Returns all paths grouped by their stroke and fill colors.

Paths must have identical stroke and fill colors to be grouped together.

.allPaths()Path[]

Returns all paths contained within this graphic, recursively.

.allAnchors()Anchor[]

Returns all anchors contained within this graphic, recursively.

.allPathsAndCompoundPaths()Path[]

Returns all paths and compound paths contained within this graphic, recursively.

.hasStyle()boolean

Returns true if this graphic has either a stroke or a fill.

.assignFill(fill)Pathchainable

Assigns a fill to this graphic.

fill
.removeFill()Pathchainable

Removes a fill style from this graphic.

.assignStroke(stroke)Pathchainable

Assigns a stroke style to this graphic.

stroke
.removeStroke()Pathchainable

Removes a stroke style from this graphic.

.assignStyle(fill,stroke)Pathchainable

Assigns both a stroke and fill style to this graphic.

fill
stroke
.copyStyle(graphic)Pathchainable

Copies the stroke and fill from graphic.

graphic
.scaleStroke(scaleFactor)Pathchainable

Scales the stroke width of this graphic by scaleFactor.

scaleFactor
number

The amount to scale existing strokes by

.firstStyled()(Path | undefined)

Returns The first styled graphic (Path or CompoundPath) in a group, or the styled path itself. A path must have either a stroke or fill to be considered styled.

.containsPoint(point)boolean

Returns true if this graphic contains point.

point

The point to test

.styleContainsPoint(point)boolean

Returns true if this graphic's style contains point.

This method differs from containsPoint() in that it takes the stroke and fill styling into account.

point

The point to test1