svg-pathdata
Version:
Manipulate SVG path data (path[d] attribute content) simply and efficiently.
56 lines (49 loc) • 1.85 kB
text/typescript
import { SVGPathData } from '../SVGPathData.js';
import { SVGPathDataTransformer } from '../index.js';
import { arePointsCollinear, type Point } from '../mathUtils.js';
import type { SVGCommand } from '../types.js';
/**
* Process a path and remove collinear points
* @param commands Array of SVG path commands to process (must be absolute)
* @returns New array with collinear points removed
*/
export function REMOVE_COLLINEAR(commands: SVGCommand[]): SVGCommand[] {
if (commands.length <= 2) return commands; // exit early if there are less than 3 points
const results: SVGCommand[] = [];
const points: Point[] = commands.map(
SVGPathDataTransformer.INFO((cmd, pXAbs, pYAbs) => {
// Calculate absolute coordinates and normlise HV
const isRelatve = 'relative' in cmd && cmd.relative;
return [
'x' in cmd ? cmd.x + (isRelatve ? pXAbs : 0) : pXAbs,
'y' in cmd ? cmd.y + (isRelatve ? pYAbs : 0) : pYAbs,
];
}),
);
let prevPoint = points[0];
results.push(commands[0]); // always keep the first point
for (let i = 1; i < commands.length; i++) {
const cmd = commands[i];
const nextCmd = commands[i + 1];
if (
i < commands.length - 1 &&
nextCmd &&
cmd.type & SVGPathData.LINE_COMMANDS &&
nextCmd.type & SVGPathData.LINE_COMMANDS
) {
const nextPoint = points[i + 1];
// Check triplets of points for collinearity
if (arePointsCollinear(prevPoint, points[i], nextPoint)) {
// update next point if its relative
if ('relative' in nextCmd && nextCmd.relative) {
if ('x' in nextCmd) nextCmd.x = nextPoint[0] - prevPoint[0];
if ('y' in nextCmd) nextCmd.y = nextPoint[1] - prevPoint[1];
}
continue;
}
}
results.push(cmd);
prevPoint = points[i];
}
return results;
}