File size: 3,144 Bytes
89ce340 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
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<typeof parseSvgPath>
/**
* 解析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<typeof toPoints> |