svg-pathdata
Version:
Manipulate SVG path data (path[d] attribute content) simply and efficiently.
107 lines (94 loc) • 3.11 kB
text/typescript
import { encodeSVGPath } from './SVGPathDataEncoder.js';
import { SVGPathDataParser } from './SVGPathDataParser.js';
import { SVGPathDataTransformer } from './SVGPathDataTransformer.js';
import { TransformableSVG } from './TransformableSVG.js';
import type { SVGCommand } from './types.js';
export class SVGPathData extends TransformableSVG {
commands: SVGCommand[];
constructor(content: string | SVGCommand[]) {
super();
if ('string' === typeof content) {
this.commands = SVGPathData.parse(content);
} else {
this.commands = content;
}
}
encode() {
return SVGPathData.encode(this.commands);
}
getBounds() {
const boundsTransform = SVGPathDataTransformer.CALCULATE_BOUNDS();
this.transform(boundsTransform);
return boundsTransform;
}
transform(
transformFunction: (input: SVGCommand) => SVGCommand | SVGCommand[],
) {
const newCommands: SVGCommand[] = [];
for (const command of this.commands) {
const transformedCommand = transformFunction(command);
if (Array.isArray(transformedCommand)) {
newCommands.push(...transformedCommand);
} else {
newCommands.push(transformedCommand);
}
}
this.commands = newCommands;
return this;
}
/**
* Reverses the order of path commands to go from end to start
* IMPORTANT: This function expects absolute commands as input.
* @param preserveSubpathOrder If true, keeps subpaths in their original order
*/
reverse(preserveSubpathOrder = true) {
this.commands = SVGPathDataTransformer.REVERSE_PATH(
this.commands,
preserveSubpathOrder,
);
return this;
}
static encode(commands: SVGCommand[]) {
return encodeSVGPath(commands);
}
static parse(path: string) {
const parser = new SVGPathDataParser();
const commands: SVGCommand[] = [];
parser.parse(path, commands);
parser.finish(commands);
return commands;
}
static readonly CLOSE_PATH = 1 as const;
static readonly MOVE_TO = 2 as const;
static readonly HORIZ_LINE_TO = 4 as const;
static readonly VERT_LINE_TO = 8 as const;
static readonly LINE_TO = 16 as const;
static readonly CURVE_TO = 32 as const;
static readonly SMOOTH_CURVE_TO = 64 as const;
static readonly QUAD_TO = 128 as const;
static readonly SMOOTH_QUAD_TO = 256 as const;
static readonly ARC = 512 as const;
static readonly LINE_COMMANDS =
SVGPathData.LINE_TO | SVGPathData.HORIZ_LINE_TO | SVGPathData.VERT_LINE_TO;
static readonly DRAWING_COMMANDS =
SVGPathData.HORIZ_LINE_TO |
SVGPathData.VERT_LINE_TO |
SVGPathData.LINE_TO |
SVGPathData.CURVE_TO |
SVGPathData.SMOOTH_CURVE_TO |
SVGPathData.QUAD_TO |
SVGPathData.SMOOTH_QUAD_TO |
SVGPathData.ARC;
}
export const COMMAND_ARG_COUNTS = {
[SVGPathData.MOVE_TO]: 2,
[SVGPathData.LINE_TO]: 2,
[SVGPathData.HORIZ_LINE_TO]: 1,
[SVGPathData.VERT_LINE_TO]: 1,
[SVGPathData.CLOSE_PATH]: 0,
[SVGPathData.QUAD_TO]: 4,
[SVGPathData.SMOOTH_QUAD_TO]: 2,
[SVGPathData.CURVE_TO]: 6,
[SVGPathData.SMOOTH_CURVE_TO]: 4,
[SVGPathData.ARC]: 7,
};