@joemaddalone/path
Version:
a simple svg path generation utility
648 lines (646 loc) • 29 kB
TypeScript
/**
* Path Class - A comprehensive SVG path builder
*
* This class provides a fluent interface for building SVG path data strings.
* It supports all standard SVG path commands (move, line, curve, arc) as well as
* convenient shape methods (circle, rectangle, polygon, etc.).
*
* The class maintains internal state for path data, allowing
* for method chaining and easy manipulation of SVG paths.
*
* @example
* const path = new Path()
* .M(10, 10) // Move to absolute position
* .l(50, 0) // Draw line relative to current position
* .l(0, 50) // Draw line relative to current position
* .close() // Close the path
*/
declare class Path {
/** Array to store SVG path command strings */
private pathData;
/**
* Constructor - Initializes a new Path instance
*
* Creates an empty path with no commands or attributes.
* Returns the instance for method chaining.
*
* @returns {Path} The initialized Path instance
*/
constructor();
/** Convert angle from degrees to radians */
static angleInRadians: (angle: number) => number;
/** Convert polar coordinates (radius, angle) to Cartesian coordinates (x, y) */
static polarToCartesian: (cx: number, cy: number, radius: number, angle: number) => {
x: number;
y: number;
};
/** Calculate point position clockwise from center at given angle and radius */
static clockwisePoint: (cx: number, cy: number, radius: number, angle: number) => {
x: number;
y: number;
};
/** Generate array of points in a circle at given radius and center */
static radialPoints: (radius: number, cx: number, cy: number, numOfPoints: number, offsetAngle?: number, vertexSkip?: number) => Array<[number, number]>;
/** Position elements in a grid based on array configuration */
static positionByArray: (size: number, shape: any[], sx: number, sy: number) => Array<{
size: number;
cx: number;
cy: number;
ri: number;
ci: number;
value: any;
}>;
/**
* Macro system - Dynamically add methods to Path prototype
*
* This allows for runtime extension of the Path class with custom methods.
* Useful for adding domain-specific path building functionality.
*
* @param {string} name - The name of the method to add
* @param {Function} fn - The function to add as a method
* @returns {Function} The added function
*
* @example
* Path.macro('zigzag', function(width, height) {
* return this.M(0, 0).l(width/2, height).l(width/2, -height);
* });
*/
static macro: (name: string, fn: (...args: any[]) => any) => Function;
/** Move to position (x, y) - relative coordinates */
m: (x: number, y: number) => Path;
/** Move to position (x, y) - absolute coordinates */
M: (x: number, y: number) => Path;
/** Draw line to position (x, y) - relative coordinates */
l: (x: number, y: number) => Path;
/** Draw line to position (x, y) - absolute coordinates */
L: (x: number, y: number) => Path;
/** Draw horizontal line to x - absolute coordinates */
H: (x: number) => Path;
/** Draw horizontal line to x - relative coordinates */
h: (x: number) => Path;
/** Draw vertical line to y - absolute coordinates */
V: (y: number) => Path;
/** Draw vertical line to y - relative coordinates */
v: (y: number) => Path;
/** Draw quadratic curve - absolute coordinates */
Q: (cx: number, cy: number, ex: number, ey: number) => Path;
/** Draw quadratic curve - relative coordinates */
q: (cx: number, cy: number, ex: number, ey: number) => Path;
/** Draw smooth quadratic curve - absolute coordinates */
T: (ex: number, ey: number) => Path;
/** Draw smooth quadratic curve - relative coordinates */
t: (ex: number, ey: number) => Path;
/** Draw cubic curve - absolute coordinates */
C: (cx1: number, cy1: number, cx2: number, cy2: number, ex: number, ey: number) => Path;
/** Draw cubic curve - relative coordinates */
c: (cx1: number, cy1: number, cx2: number, cy2: number, ex: number, ey: number) => Path;
/** Draw smooth cubic curve - absolute coordinates */
S: (cx: number, cy: number, ex: number, ey: number) => Path;
/** Draw smooth cubic curve - relative coordinates */
s: (cx: number, cy: number, ex: number, ey: number) => Path;
/** Draw arc - absolute coordinates */
A: (rx: number, ry: number, rotation: number, arc: 1 | 0, sweep: 1 | 0, ex: number, ey: number) => Path;
/** Draw arc - relative coordinates */
a: (rx: number, ry: number, rotation: number, arc: 1 | 0, sweep: 1 | 0, ex: number, ey: number) => Path;
/** Close path - absolute coordinates */
Z: () => Path;
/** Close path - relative coordinates */
z: () => Path;
/**
* Move SVG cursor to position (x, y)
*
* This is the foundation command that sets the starting point for subsequent
* drawing operations. If relative is true, coordinates are relative to the
* current cursor position.
*
* @param {number} x - X coordinate
* @param {number} y - Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
moveTo: (x: number, y: number, relative?: boolean) => Path;
/**
* Draw a straight line to position (x, y)
*
* Creates a line segment from the current cursor position to the specified
* coordinates. If relative is true, coordinates are relative to current position.
*
* @param {number} x - X coordinate
* @param {number} y - Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
lineTo: (x: number, y: number, relative?: boolean) => Path;
/**
* Draw a horizontal line to x coordinate
*
* Creates a horizontal line segment from the current cursor position.
* Only the x coordinate changes; y remains the same.
*
* @param {number} x - X coordinate
* @param {boolean} relative - Whether x is relative to current position (default: false)
* @returns {Path} The Path instance for chaining
*/
horizontalTo: (x: number, relative?: boolean) => Path;
/**
* Draw a vertical line to y coordinate
*
* Creates a vertical line segment from the current cursor position.
* Only the y coordinate changes; x remains the same.
*
* @param {number} x - Y coordinate (parameter name is x for consistency)
* @param {boolean} relative - Whether y is relative to current position (default: false)
* @returns {Path} The Path instance for chaining
*/
verticalTo: (x: number, relative?: boolean) => Path;
/**
* Draw a quadratic Bézier curve
*
* Creates a quadratic curve using a single control point (cx, cy) to define
* the curve shape, ending at (ex, ey). The curve will pass through the
* control point's influence area.
*
* @param {number} cx - Control point X coordinate
* @param {number} cy - Control point Y coordinate
* @param {number} ex - End point X coordinate
* @param {number} ey - End point Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
qCurve: (cx: number, cy: number, ex: number, ey: number, relative?: boolean) => Path;
/**
* Draw a smooth quadratic Bézier curve
*
* Creates a quadratic curve that smoothly continues from the previous curve.
* The control point is automatically calculated based on the previous curve's
* end point, creating a smooth transition.
*
* @param {number} ex - End point X coordinate
* @param {number} ey - End point Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
tCurveTo: (ex: number, ey: number, relative?: boolean) => Path;
/**
* Draw a cubic Bézier curve
*
* Creates a cubic curve using two control points (cx1, cy1) and (cx2, cy2)
* to define the curve shape, ending at (ex, ey). This provides more control
* over the curve than quadratic curves.
*
* @param {number} cx1 - First control point X coordinate
* @param {number} cy1 - First control point Y coordinate
* @param {number} cx2 - Second control point X coordinate
* @param {number} cy2 - Second control point Y coordinate
* @param {number} ex - End point X coordinate
* @param {number} ey - End point Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
cCurve: (cx1: number, cy1: number, cx2: number, cy2: number, ex: number, ey: number, relative?: boolean) => Path;
/**
* Draw a smooth cubic Bézier curve
*
* Creates a cubic curve that smoothly continues from the previous curve.
* The first control point is automatically calculated, while the second
* control point (cx, cy) is explicitly specified.
*
* @param {number} cx - Second control point X coordinate
* @param {number} cy - Second control point Y coordinate
* @param {number} ex - End point X coordinate
* @param {number} ey - End point Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
sCurveTo: (cx: number, cy: number, ex: number, ey: number, relative?: boolean) => Path;
/**
* Draw an elliptical arc
*
* Creates an arc segment of an ellipse. The arc is defined by:
* - rx, ry: x and y radius of the ellipse
* - rotation: rotation of the ellipse in degrees
* - arc: large arc flag (0 = small arc, 1 = large arc)
* - sweep: sweep flag (0 = counterclockwise, 1 = clockwise)
* - ex, ey: end point coordinates
*
* @param {number} rx - X radius of the ellipse
* @param {number} ry - Y radius of the ellipse
* @param {number} rotation - Rotation of the ellipse in degrees
* @param {1|0} arc - Large arc flag (0 = small, 1 = large)
* @param {1|0} sweep - Sweep flag (0 = counterclockwise, 1 = clockwise)
* @param {number} ex - End point X coordinate
* @param {number} ey - End point Y coordinate
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
arc: (rx: number, ry: number, rotation: number, arc: 1 | 0, sweep: 1 | 0, ex: number, ey: number, relative?: boolean) => Path;
/**
* Close the current path
*
* Draws a straight line from the current position back to the starting point
* of the current subpath, effectively closing the shape.
*
* @returns {Path} The Path instance for chaining
*/
close: () => Path;
/** Move down by specified pixels (positive y direction) */
down: (px: number) => Path;
/** Move up by specified pixels (negative y direction) */
up: (px: number) => Path;
/** Move right by specified pixels (positive x direction) */
right: (px: number) => Path;
/** Move left by specified pixels (negative x direction) */
left: (px: number) => Path;
/**
* Get the path data as an array of command strings
*
* Returns the internal pathData array containing all SVG path commands
* that have been added to this path instance.
*
* @returns {string[]} Array of SVG path command strings
*/
toArray: () => string[];
/**
* Convert the path to an SVG path data string
*
* Joins all path commands into a single string suitable for use
* as the 'd' attribute of an SVG path element.
*
* @returns {string} SVG path data string
*/
toString: () => string;
/**
* Convert path commands to structured array format
*
* Parses the path data into an array where each element contains:
* - First element: the command letter (M, L, Q, etc.)
* - Subsequent elements: the numeric parameters for that command
*
* @returns {Array<(string|number)[]>} Array of command arrays
*
* @example
* // For path "M10 10 L20 20"
* // Returns: [["M", 10, 10], ["L", 20, 20]]
*/
toCommands: () => Array<(string | number)[]>;
/**
* Convert path commands to annotated format with named parameters
*
* Uses the docs mapping to convert numeric parameters to named parameters
* based on the command type. This makes the path data more readable
* and self-documenting.
*
* @returns {Array<{fn: string, args?: Record<string, number>}>} Array of annotated commands
*
* @example
* // For path "M10 10 L20 20"
* // Returns: [{fn: "M", args: {x: 10, y: 10}}, {fn: "L", args: {x: 20, y: 20}}]
*/
toAnnotatedCommands: () => Array<{
fn: string;
args?: Record<string, number>;
}>;
/**
* Create an SVG path element from the current path
*
* Generates a DOM SVG path element with all the accumulated path data
* and attributes. This is useful for programmatically creating SVG elements
* that can be inserted into the DOM.
*
* @param {Record<string, any>} attributes - Additional attributes to apply to the element
* @returns {SVGPathElement} SVG path element
*/
toElement: (attributes?: {}) => SVGPathElement;
/**
* Create a circle
*
* Draws a perfect circle using two arc commands. The circle is centered
* at (cx, cy) with the specified size as diameter.
*
* @param {number} size - Diameter of the circle
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
circle: (size: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create an ellipse
*
* Draws an ellipse using two arc commands. The ellipse is centered
* at (cx, cy) with the specified width and height as dimensions.
*
* @param {number} width - Width of the ellipse
* @param {number} height - Height of the ellipse
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
ellipse: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a kite shape
*
* Draws a kite (diamond-like shape) with adjustable height offset.
* The kite has four points: top, left, bottom, and right.
*
* @param {number} width - Width of the kite
* @param {number} height - Height of the kite
* @param {number} dh - Height offset for left/right points (defaults to height * 0.33)
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
kite: (width: number, height: number, dh: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a polygon from an array of points
*
* Draws a closed polygon by connecting the provided points in sequence.
* The polygon automatically closes by drawing a line back to the first point.
*
* @param {number[][]} points - Array of [x, y] coordinate pairs
* @returns {Path} The Path instance for chaining
*/
polygon: (points: number[][]) => Path;
/**
* Create a polygram (star-like polygon)
*
* Draws a polygram by connecting vertices with a specified skip pattern.
* For example, with vertexSkip=2, it connects every other vertex, creating
* a star pattern.
*
* @param {number} size - Size of the polygram
* @param {number} points - Number of vertices
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {number} vertexSkip - How many vertices to skip when connecting (default: 2)
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
polygram: (size: number, points: number, cx: number, cy: number, vertexSkip?: number, centerEnd?: boolean) => Path;
/**
* Create a polyline from an array of points
*
* Draws a series of connected line segments through the provided points.
* Unlike polygon, this does not automatically close the shape.
*
* @param {number[][]} points - Array of [x, y] coordinate pairs
* @param {boolean} relative - Whether coordinates are relative (default: false)
* @returns {Path} The Path instance for chaining
*/
polyline: (points: number[][], relative?: boolean) => Path;
/**
* Create a rectangle
*
* Draws a rectangle centered at (cx, cy) with the specified width and height.
* Uses the convenience directional methods for clean, readable code.
*
* @param {number} width - Width of the rectangle
* @param {number} height - Height of the rectangle
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
rect: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a regular polygon
*
* Draws a regular polygon with equal sides and angles. The polygon is
* centered at (cx, cy) and inscribed in a circle of the specified size.
*
* @param {number} size - Diameter of the circumscribed circle
* @param {number} sides - Number of sides in the polygon
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
regPolygon: (size: number, sides: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a rounded rectangle
*
* Draws a rectangle with rounded corners. The radius is automatically
* adjusted if it exceeds half the width or height of the rectangle.
*
* @param {number} width - Width of the rectangle
* @param {number} height - Height of the rectangle
* @param {number} radius - Corner radius
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
roundedRect: (width: number, height: number, radius: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a rounded square
*
* Convenience method for creating a square with rounded corners.
*
* @param {number} size - Size of the square
* @param {number} radius - Corner radius
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
roundedSquare: (size: number, radius: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a square
*
* Convenience method for creating a square (equal width and height).
*
* @param {number} size - Size of the square
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
square: (size: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a star shape
*
* Draws a star by alternating between inner and outer radius points.
* The star has the specified number of points and uses two different
* radii to create the characteristic star appearance.
*
* @param {number} outerSize - Diameter of outer circle for star points
* @param {number} innerSize - Diameter of inner circle for star valleys
* @param {number} points - Number of star points
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
star: (outerSize: number, innerSize: number, points: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a triangle
*
* Draws an equilateral triangle centered at (cx, cy) with the specified size.
* The triangle points upward by default.
*
* @param {number} size - Size of the triangle (length of each side)
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
triangle: (size: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a sector (pie slice)
*
* Draws a pie slice from startAngle to endAngle. The sector is filled
* and includes lines from the center to both edges.
*
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {number} size - Diameter of the circle
* @param {number} startAngle - Starting angle in degrees
* @param {number} endAngle - Ending angle in degrees
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
sector: (cx: number, cy: number, size: number, startAngle: number, endAngle: number, centerEnd?: boolean) => Path;
/**
* Create a segment (arc without center lines)
*
* Draws an arc segment from startAngle to endAngle without filling
* the center area. This creates just the curved edge.
*
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {number} size - Diameter of the circle
* @param {number} startAngle - Starting angle in degrees
* @param {number} endAngle - Ending angle in degrees
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
segment: (cx: number, cy: number, size: number, startAngle: number, endAngle: number, centerEnd?: boolean) => Path;
/**
* Create radial lines pattern
*
* Draws lines radiating from inner to outer circles at regular intervals.
* Creates a sunburst or starburst effect.
*
* @param {number} outerSize - Diameter of outer circle
* @param {number} innerSize - Diameter of inner circle
* @param {number} points - Number of radial lines
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
radialLines: (outerSize: number, innerSize: number, points: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a lens shape
*
* Draws a lens (oval with pointed ends) using quadratic curves.
* The lens is centered at (cx, cy) with the specified width and height.
*
* @param {number} width - Width of the lens
* @param {number} height - Height of the lens
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
lens: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create an omino pattern
*
* Draws a pattern based on a grid arrangement where each cell can be
* connected to its neighbors. The shape array defines which cells are
* occupied, and the method draws lines between adjacent cells.
*
* @param {number} size - Size of each grid cell
* @param {any[]} shape - 2D array defining the pattern (1 = occupied, 0 = empty)
* @param {number} sx - Starting X coordinate
* @param {number} sy - Starting Y coordinate
* @param {boolean} lined - Whether to always draw lines (default: false)
* @returns {Path} The Path instance for chaining
*/
omino: (size: number, shape: any[], sx: number, sy: number, lined?: boolean) => Path;
/**
* Create an isometric cube
*
* Draws a hexagon (top view of cube) with lines extending from inner
* to outer points to create a 3D cube effect.
*
* @param {number} size - Size of the cube
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
isocube: (size: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a cross shape
*
* Draws a cross with horizontal and vertical lines intersecting at center.
* The cross extends width/2 pixels left and right, height/2 pixels up and down.
*
* @param {number} width - Width of the cross
* @param {number} height - Height of the cross
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
cross: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create an H-shaped symmetry pattern
*
* Draws an H shape with vertical lines on left and right sides,
* connected by a horizontal line in the center.
*
* @param {number} width - Width of the H pattern
* @param {number} height - Height of the H pattern
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
symH: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create an I-shaped symmetry pattern
*
* Draws an I shape with horizontal lines on top and bottom,
* connected by a vertical line in the center.
*
* @param {number} width - Width of the I pattern
* @param {number} height - Height of the I pattern
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
symI: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create a V-shaped symmetry pattern
*
* Draws a V shape with lines from the top corners meeting at the center bottom.
*
* @param {number} width - Width of the V pattern
* @param {number} height - Height of the V pattern
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
symV: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
/**
* Create an X-shaped symmetry pattern
*
* Draws an X shape with diagonal lines crossing at the center.
*
* @param {number} width - Width of the X pattern
* @param {number} height - Height of the X pattern
* @param {number} cx - Center X coordinate
* @param {number} cy - Center Y coordinate
* @param {boolean} centerEnd - Whether to end at center (default: true)
* @returns {Path} The Path instance for chaining
*/
symX: (width: number, height: number, cx: number, cy: number, centerEnd?: boolean) => Path;
}
export { Path as default };