import { SVGPathData } from 'svg-pathdata'; import arcToBezier from 'svg-arc-to-cubic-bezier'; const typeMap = { 1: 'Z', 2: 'M', 4: 'H', 8: 'V', 16: 'L', 32: 'C', 64: 'S', 128: 'Q', 256: 'T', 512: 'A', }; /** * 简单解析SVG路径 * @param d SVG path d属性 */ export const parseSvgPath = (d: string) => { const pathData = new SVGPathData(d); const ret = pathData.commands.map((item) => { return { ...item, type: typeMap[item.type] }; }); return ret; }; export type SvgPath = ReturnType; /** * 解析SVG路径,并将圆弧(A)类型的路径转为三次贝塞尔(C)类型的路径 * @param d SVG path d属性 */ export const toPoints = (d: string) => { const pathData = new SVGPathData(d); const points = []; for (const item of pathData.commands) { const type = typeMap[item.type]; if (item.type === 2 || item.type === 16) { points.push({ x: item.x, y: item.y, relative: item.relative, type, }); } if (item.type === 32) { points.push({ x: item.x, y: item.y, curve: { type: 'cubic', x1: item.x1, y1: item.y1, x2: item.x2, y2: item.y2, }, relative: item.relative, type, }); } else if (item.type === 128) { points.push({ x: item.x, y: item.y, curve: { type: 'quadratic', x1: item.x1, y1: item.y1, }, relative: item.relative, type, }); } else if (item.type === 512) { const lastPoint = points[points.length - 1]; if (!['M', 'L', 'Q', 'C'].includes(lastPoint.type)) continue; const cubicBezierPoints = arcToBezier({ px: lastPoint.x as number, py: lastPoint.y as number, cx: item.x, cy: item.y, rx: item.rX, ry: item.rY, xAxisRotation: item.xRot, largeArcFlag: item.lArcFlag, sweepFlag: item.sweepFlag, }); for (const cbPoint of cubicBezierPoints) { points.push({ x: cbPoint.x, y: cbPoint.y, curve: { type: 'cubic', x1: cbPoint.x1, y1: cbPoint.y1, x2: cbPoint.x2, y2: cbPoint.y2, }, relative: false, type: 'C', }); } } else if (item.type === 1) { points.push({ close: true, type }); } else continue; } return points; }; export const getSvgPathRange = (path: string) => { try { const pathData = new SVGPathData(path); const xList = []; const yList = []; for (const item of pathData.commands) { const x = 'x' in item ? item.x : 0; const y = 'y' in item ? item.y : 0; xList.push(x); yList.push(y); } return { minX: Math.min(...xList), minY: Math.min(...yList), maxX: Math.max(...xList), maxY: Math.max(...yList), }; } catch { return { minX: 0, minY: 0, maxX: 0, maxY: 0, }; } }; export type SvgPoints = ReturnType;