@technosyr/path2df
v0.2.1
Published
High-performance vector path library with length parameterization, projection, and Bezier curve support
Maintainers
Readme
@technosyr/path2df
High-performance vector path library with length parameterization, Bezier curve support, and point projection.
Features
✅ SVG Path Compatible — full support for SVG path commands (H, V, S, T, A) ✅ Length Parameterization — get points, tangents, and angles by normalized length (0-1) ✅ Real-time Calculation — geometry computed on-the-fly during path construction ✅ Bezier Support — quadratic and cubic curves with precise bounds ✅ Point Projection — project any point onto the path ✅ Path2D Cache — optimized Canvas rendering ✅ TypeScript — full type safety ✅ Zero Dependencies — no external libs required
Installation
npm install @technosyr/path2dfQuick Start
import { VectorPath } from '@technosyr/path2df';
// Create path (API similar to Canvas)
const path = new VectorPath();
path
.moveTo(0, 0)
.lineTo(100, 0)
.bezierCurveTo(150, 0, 150, 50, 150, 100)
.closePath();
// Length is computed automatically
console.log(path.totalLength); // e.g., 250.5
// Get point at 50% of the path
const midPoint = path.pointAtF(0.5);
console.log(midPoint); // { x: 125, y: 25 }
// Get tangent angle at 75%
const angle = path.angleAtF(0.75);
console.log(angle); // in radians
// Project external point onto path
const proj = path.project({ x: 120, y: 30 });
console.log(proj);
// { f: 0.65, distance: 5.2, point: { x: 118, y: 28 } }
// Render to Canvas
const ctx = canvas.getContext('2d');
ctx.stroke(path.getPath2D());API
VectorPath
Path Construction (Canvas-compatible)
moveTo(x: number, y: number): this
lineTo(x: number, y: number): this
quadraticCurveTo(cx: number, cy: number, x: number, y: number): this
bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this
closePath(): this
clear(): thisSVG Path Commands
horizontalLineTo(x: number): this
// Horizontal line to (x, currentY) — SVG H command
verticalLineTo(y: number): this
// Vertical line to (currentX, y) — SVG V command
smoothCubicTo(cx2: number, cy2: number, x: number, y: number): this
// Smooth cubic Bezier with automatic first control point — SVG S command
smoothQuadraticTo(x: number, y: number): this
// Smooth quadratic Bezier with automatic control point — SVG T command
arcTo(rx: number, ry: number, rotation: number, largeArc: 0 | 1, sweep: 0 | 1, x: number, y: number): this
// Elliptical arc — SVG A commandHelper Methods
getCurrentPoint(): Vec2 | null
// Get current pen position
getLastControlPoint(): Vec2 | null
// Get last control point (for smooth curves)Properties
totalLength: number // Total path length (computed on-the-fly)
bounds: Bounds // AABB { minX, minY, maxX, maxY }
segmentCount: number // Number of segmentsParameterization by Length
pointAtF(f: number): Vec2
// Get point at normalized position f ∈ [0, 1]
tangentAtF(f: number): Vec2
// Get tangent vector (not normalized) at position f
angleAtF(f: number): number
// Get tangent angle in radians at position f
segmentAtF(f: number): { segment: ISegment; localT: number; index: number } | null
// Find which segment contains position fProjection
project(p: Vec2): { f: number; distance: number; point: Vec2 }
// Project point p onto the path
// Returns: normalized position, distance, and closest pointRendering
getPath2D(): Path2D
// Get cached Path2D for Canvas renderingUtilities
getSegments(): readonly ISegment[]
// Get all segments
samplePoints(step: number): Generator<Vec2>
// Generate points along the path with given pixel stepSegments
You can also use segments directly:
import { LineSegment, QuadraticSegment, CubicSegment } from '@technosyr/path2df/segments';
const line = new LineSegment(
{ x: 0, y: 0 },
{ x: 100, y: 100 }
);
console.log(line.length); // 141.42...
console.log(line.pointAt(0.5)); // { x: 50, y: 50 }
console.log(line.tangentAt(0.5)); // { x: 100, y: 100 }
const projection = line.project({ x: 60, y: 40 });
console.log(projection);
// { t: 0.5, d2: 200 } // t = local parameter, d2 = distance²Types
interface Vec2 {
x: number;
y: number;
}
interface Bounds {
minX: number;
minY: number;
maxX: number;
maxY: number;
}
interface ISegment {
readonly length: number;
readonly start: Vec2;
readonly end: Vec2;
readonly bounds: Bounds;
pointAt(t: number): Vec2;
tangentAt(t: number): Vec2;
project(p: Vec2): { t: number; d2: number };
applyToPath(path: Path2D): void;
}Use Cases
Animate object along path
const path = new VectorPath()
.moveTo(0, 0)
.bezierCurveTo(100, 0, 100, 100, 200, 100);
function animate(time: number) {
const f = (time % 2000) / 2000; // 0-1 over 2 seconds
const pos = path.pointAtF(f);
const angle = path.angleAtF(f);
// Position and rotate sprite
sprite.x = pos.x;
sprite.y = pos.y;
sprite.rotation = angle;
}Find closest point on path
function onMouseMove(e: MouseEvent) {
const mouse = { x: e.clientX, y: e.clientY };
const proj = path.project(mouse);
if (proj.distance < 10) {
console.log('Near path at', proj.point);
console.log('Progress:', (proj.f * 100).toFixed(1) + '%');
}
}Draw evenly spaced markers
const markers = [];
for (let f = 0; f <= 1; f += 0.1) {
const pos = path.pointAtF(f);
const angle = path.angleAtF(f);
markers.push({ pos, angle });
}
markers.forEach(({ pos, angle }) => {
drawMarker(ctx, pos.x, pos.y, angle);
});Calculate total path length
// Length is computed automatically during path construction
const path = new VectorPath()
.moveTo(0, 0)
.lineTo(100, 0)
.quadraticCurveTo(150, 50, 100, 100);
console.log('Total length:', path.totalLength.toFixed(2) + 'px');Performance
- Segment lengths computed once during construction (no build step needed)
- Path2D cached and reused for rendering
- Projection uses grid search + Newton-Raphson refinement
- No memory allocations in hot paths (pointAtF, tangentAtF)
Browser Support
Requires Path2D support (all modern browsers).
License
MIT
Contributing
PRs welcome! Please open an issue first to discuss changes.
Roadmap
- [x] SVG path commands (H, V, S, T, A) — v0.2.0
- [ ] Arc segments optimization
- [ ] Adaptive LUT for faster queries
- [ ] Path offsetting (stroke to outline)
- [ ] Boolean operations
- [ ] SVG path string parsing
- [ ] Catmull-Rom splines
Built with ❤️ by TechnoCheese
