chart-math/dist/catmull-rom.js

62 lines
2.5 KiB
JavaScript
Raw Normal View History

/**
* Catmull-Rom spline SVG cubic bezier conversion utilities.
*
* Generates C1-continuous curves through all control points,
* producing smoother interpolation than pairwise bezier.
*/
/**
* Generate SVG cubic bezier C commands for a Catmull-Rom spline through the given points.
* Does NOT include the initial M command only the C segments.
*
* @param pts - Control points (minimum 2)
* @param tension - Spline tension (0 = linear, 0.5 = standard Catmull-Rom, 1 = tight)
* @returns SVG path string containing only C commands
*/
export function catmullRomSegments(pts, tension = 0.5) {
if (pts.length < 2)
return '';
const out = [];
for (let i = 0; i < pts.length - 1; i++) {
const p0 = pts[Math.max(0, i - 1)];
const p1 = pts[i];
const p2 = pts[i + 1];
const p3 = pts[Math.min(pts.length - 1, i + 2)];
const c1x = p1.x + (tension * (p2.x - p0.x)) / 3;
const c1y = p1.y + (tension * (p2.y - p0.y)) / 3;
const c2x = p2.x - (tension * (p3.x - p1.x)) / 3;
const c2y = p2.y - (tension * (p3.y - p1.y)) / 3;
out.push(`C ${c1x.toFixed(1)} ${c1y.toFixed(1)},${c2x.toFixed(1)} ${c2y.toFixed(1)},${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`);
}
return out.join(' ');
}
/**
* Generate a complete SVG path (M + C commands) for a Catmull-Rom spline.
*
* @param pts - Control points (minimum 2)
* @param tension - Spline tension (default 0.5)
* @returns Complete SVG path string starting with M
*/
export function catmullRomPath(pts, tension = 0.5) {
if (pts.length < 2)
return '';
return `M ${pts[0].x.toFixed(1)} ${pts[0].y.toFixed(1)} ${catmullRomSegments(pts, tension)}`;
}
/**
* Generate a closed SVG area path for a stream ribbon.
* Traces the top edge left-to-right, then the bottom edge right-to-left,
* both as Catmull-Rom splines, closing with Z.
*
* @param top - Upper boundary points (left-to-right)
* @param bottom - Lower boundary points (left-to-right, will be reversed internally)
* @param tension - Spline tension (default 0.5)
* @returns Closed SVG path string
*/
export function catmullRomAreaPath(top, bottom, tension = 0.5) {
if (top.length < 2 || bottom.length < 2)
return '';
const reversed = [...bottom].reverse();
const topPath = catmullRomPath(top, tension);
const bottomSegs = catmullRomSegments(reversed, tension);
return `${topPath} L ${reversed[0].x.toFixed(1)} ${reversed[0].y.toFixed(1)} ${bottomSegs} Z`;
}
//# sourceMappingURL=catmull-rom.js.map