svg-pathdata
Version:
Manipulate SVG path data (path[d] attribute content) simply and efficiently.
121 lines (106 loc) • 2.7 kB
text/typescript
import { SVGPathData } from './SVGPathData.js';
import type { SVGCommand } from './types.js';
function moveTo(x: number, y: number): SVGCommand {
return { type: SVGPathData.MOVE_TO, relative: false, x, y };
}
function lineTo(x: number, y: number): SVGCommand {
return { type: SVGPathData.LINE_TO, relative: false, x, y };
}
function arcTo(
rx: number,
ry: number,
xRot: number,
largeArc: 0 | 1,
sweep: 0 | 1,
x: number,
y: number,
): SVGCommand {
return {
type: SVGPathData.ARC,
relative: false,
rX: rx,
rY: ry,
xRot,
lArcFlag: largeArc,
sweepFlag: sweep,
x,
y,
};
}
/**
* Creates an ellipse path centered at (cx,cy) with radii rx and ry
*/
function createEllipse(
rx: number,
ry: number,
cx: number,
cy: number,
): SVGPathData {
return new SVGPathData([
moveTo(cx + rx, cy),
arcTo(rx, ry, 0, 1, 1, cx - rx, cy),
arcTo(rx, ry, 0, 1, 1, cx + rx, cy),
{ type: SVGPathData.CLOSE_PATH },
]);
}
/**
* Creates a rectangle path with optional rounded corners
*/
function createRect(
x: number,
y: number,
width: number,
height: number,
rX = 0,
rY = 0,
): SVGPathData {
if (rX === 0 || rY === 0) {
return new SVGPathData([
moveTo(x, y),
lineTo(x + width, y),
lineTo(x + width, y + height),
lineTo(x, y + height),
{ type: SVGPathData.CLOSE_PATH },
]);
}
const rx = Math.min(rX, width / 2);
const ry = Math.min(rY, height / 2);
return new SVGPathData([
moveTo(x + rx, y),
lineTo(x + width - rx, y),
arcTo(rx, ry, 0, 0, 1, x + width, y + ry),
lineTo(x + width, y + height - ry),
arcTo(rx, ry, 0, 0, 1, x + width - rx, y + height),
lineTo(x + rx, y + height),
arcTo(rx, ry, 0, 0, 1, x, y + height - ry),
lineTo(x, y + ry),
arcTo(rx, ry, 0, 0, 1, x + rx, y),
{ type: SVGPathData.CLOSE_PATH },
]);
}
/**
* Creates a polyline from an array of coordinates [x1,y1,x2,y2,...]
*/
function createPolyline(coords: number[]): SVGPathData {
if (coords.length < 2) return new SVGPathData([]);
const commands: SVGCommand[] = [moveTo(coords[0], coords[1])];
for (let i = 2; i < coords.length; i += 2) {
commands.push(lineTo(coords[i], coords[i + 1]));
}
return new SVGPathData(commands);
}
/**
* Creates a closed polygon from an array of coordinates
*/
function createPolygon(coords: number[]): SVGPathData {
if (coords.length < 2) return new SVGPathData([]);
const commands = createPolyline(coords).commands;
commands.push({ type: SVGPathData.CLOSE_PATH });
return new SVGPathData(commands);
}
export const SVGShapes = {
createEllipse,
createRect,
createPolyline,
createPolygon,
};