二维Svg转矢量 不支持Svg2.0

2023-03-18,,

import { ElMessage } from 'element-plus'
import { parse } from 'svgson'
import JsonToView from './view' const TAU = Math.PI * 2
let StyleClasse = '' const mapToEllipse = ({ x, y }, rx, ry, cosphi, sinphi, centerx, centery) => {
x *= rx
y *= ry const xp = cosphi * x - sinphi * y
const yp = sinphi * x + cosphi * y return {
x: xp + centerx,
y: yp + centery
}
} const approxUnitArc = (ang1, ang2) => {
// If 90 degree circular arc, use a constant
// as derived from http://spencermortensen.com/articles/bezier-circle
const a =
ang2 === 1.5707963267948966
? 0.551915024494
: ang2 === -1.5707963267948966
? -0.551915024494
: (4 / 3) * Math.tan(ang2 / 4) const x1 = Math.cos(ang1)
const y1 = Math.sin(ang1)
const x2 = Math.cos(ang1 + ang2)
const y2 = Math.sin(ang1 + ang2) return [
{
x: x1 - y1 * a,
y: y1 + x1 * a
},
{
x: x2 + y2 * a,
y: y2 - x2 * a
},
{
x: x2,
y: y2
}
]
} const vectorAngle = (ux, uy, vx, vy) => {
const sign = ux * vy - uy * vx < 0 ? -1 : 1 let dot = ux * vx + uy * vy if (dot > 1) {
dot = 1
} if (dot < -1) {
dot = -1
} return sign * Math.acos(dot)
} const getArcCenter = (
px,
py,
cx,
cy,
rx,
ry,
largeArcFlag,
sweepFlag,
sinphi,
cosphi,
pxp,
pyp
) => {
const rxsq = Math.pow(rx, 2)
const rysq = Math.pow(ry, 2)
const pxpsq = Math.pow(pxp, 2)
const pypsq = Math.pow(pyp, 2) let radicant = rxsq * rysq - rxsq * pypsq - rysq * pxpsq if (radicant < 0) {
radicant = 0
} radicant /= rxsq * pypsq + rysq * pxpsq
radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1) const centerxp = ((radicant * rx) / ry) * pyp
const centeryp = ((radicant * -ry) / rx) * pxp const centerx = cosphi * centerxp - sinphi * centeryp + (px + cx) / 2
const centery = sinphi * centerxp + cosphi * centeryp + (py + cy) / 2 const vx1 = (pxp - centerxp) / rx
const vy1 = (pyp - centeryp) / ry
const vx2 = (-pxp - centerxp) / rx
const vy2 = (-pyp - centeryp) / ry let ang1 = vectorAngle(1, 0, vx1, vy1)
let ang2 = vectorAngle(vx1, vy1, vx2, vy2) if (sweepFlag === 0 && ang2 > 0) {
ang2 -= TAU
} if (sweepFlag === 1 && ang2 < 0) {
ang2 += TAU
} return [centerx, centery, ang1, ang2]
} const arcToBezier = ({
px,
py,
cx,
cy,
rx,
ry,
xAxisRotation = 0,
largeArcFlag = 0,
sweepFlag = 0
}) => {
const curves: any = [] if (rx === 0 || ry === 0) {
return []
} const sinphi = Math.sin((xAxisRotation * TAU) / 360)
const cosphi = Math.cos((xAxisRotation * TAU) / 360) const pxp = (cosphi * (px - cx)) / 2 + (sinphi * (py - cy)) / 2
const pyp = (-sinphi * (px - cx)) / 2 + (cosphi * (py - cy)) / 2 if (pxp === 0 && pyp === 0) {
return []
} rx = Math.abs(rx)
ry = Math.abs(ry) const lambda =
Math.pow(pxp, 2) / Math.pow(rx, 2) + Math.pow(pyp, 2) / Math.pow(ry, 2) if (lambda > 1) {
rx *= Math.sqrt(lambda)
ry *= Math.sqrt(lambda)
} let [centerx, centery, ang1, ang2] = getArcCenter(
px,
py,
cx,
cy,
rx,
ry,
largeArcFlag,
sweepFlag,
sinphi,
cosphi,
pxp,
pyp
) // If 'ang2' == 90.0000000001, then `ratio` will evaluate to
// 1.0000000001. This causes `segments` to be greater than one, which is an
// unecessary split, and adds extra points to the bezier curve. To alleviate
// this issue, we round to 1.0 when the ratio is close to 1.0.
let ratio = Math.abs(ang2) / (TAU / 4)
if (Math.abs(1.0 - ratio) < 0.0000001) {
ratio = 1.0
} const segments = Math.max(Math.ceil(ratio), 1) ang2 /= segments for (let i = 0; i < segments; i++) {
curves.push(approxUnitArc(ang1, ang2))
ang1 += ang2
} return curves.map(curve => {
const { x: x1, y: y1 } = mapToEllipse(
curve[0],
rx,
ry,
cosphi,
sinphi,
centerx,
centery
)
const { x: x2, y: y2 } = mapToEllipse(
curve[1],
rx,
ry,
cosphi,
sinphi,
centerx,
centery
)
const { x, y } = mapToEllipse(
curve[2],
rx,
ry,
cosphi,
sinphi,
centerx,
centery
) return { x1, y1, x2, y2, x, y }
})
} const SvgToShape = (oBJht, file = undefined, URL = undefined, callback: any = undefined) => { let refX = 0
let refY = 0
let scaleX: any = 1
let scaleY: any = 1
const set16ToRgb = str => {
var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
if (!reg.test(str)) {
return str
}
let newStr = str.toLowerCase().replace(/\#/g, '')
let len = newStr.length
if (len == 3) {
let t = ''
for (var i = 0; i < len; i++) {
t += newStr.slice(i, i + 1).concat(newStr.slice(i, i + 1))
}
newStr = t
}
let arr: any = [] //将字符串分隔,两个两个的分隔
for (var i = 0; i < 6; i = i + 2) {
let s = newStr.slice(i, i + 2)
arr.push(parseInt('0x' + s))
}
return 'rgb(' + arr.join(',') + ')'
} //hex -> rgba
const hexToRgba = (hex, opacity) => {
hex && hex.toLowerCase()
!hex && (hex = '#000')
if (hex === 'none') return undefined return rgbToRgba(set16ToRgb(hex), opacity)
}
const rgbToRgba = (color, alp = 1) => {
let rgbaAttr = color.match(/[\d.]+/g) if (rgbaAttr && rgbaAttr.length >= 3) {
let r, g, b
r = rgbaAttr[0]
g = rgbaAttr[1]
b = rgbaAttr[2]
return 'rgba(' + r + ',' + g + ',' + b + ',' + alp + ')'
}
return 'rgba(0,0,0,' + alp + ')'
} // X偏量
const X = value => {
const v = Number(value) || 0 return (v - refX) / (scaleX === undefined ? 1 : scaleX)
}
// Y偏量
const Y = value => {
const v = Number(value) || 0 return (v - refY) / (scaleY === undefined ? 1 : scaleY)
} const k: any = {
modified: new Date().toString(),
comps: [],
background: undefined,
width: 512,
height: 512
}
const trim = function (x) {
return x.replace(/^\s+|\s+$/g, '')
}
const compressSpaces = function (x) {
return x.replace(/[\s\r\t\n]+/gm, ' ')
} function Rect2path(x, y, width, height, rx, ry) {
/*
* rx 和 ry 的规则是:
* 1. 如果其中一个设置为 0 则圆角不生效
* 2. 如果有一个没有设置则取值为另一个
*/
rx = rx || ry || 0;
ry = ry || rx || 0;
//非数值单位计算,如当宽度像100%则移除
if (isNaN(x - y + width - height + rx - ry)) return;
rx = rx > width / 2 ? width / 2 : rx;
ry = ry > height / 2 ? height / 2 : ry;
//如果其中一个设置为 0 则圆角不生效
if (0 == rx || 0 == ry) {
// var path =
// 'M' + x + ' ' + y +
// 'H' + (x + width) + 不推荐用绝对路径,相对路径节省代码量
// 'V' + (y + height) +
// 'H' + x +
// 'z';
var path =
'M' + x + ' ' + y +
'h' + width +
'v' + height +
'h' + -width +
'z';
} else {
var path =
'M' + x + ' ' + (y + ry) +
'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + (-ry) +
'h' + (width - rx - rx) +
'a' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + ry +
'v' + (height - ry - ry) +
'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' ' + ry +
'h' + (rx + rx - width) +
'a' + rx + ' ' + ry + ' 0 0 1 ' + (-rx) + ' ' + (-ry) +
'z';
}
return path;
} const CreateDefalutShape = (comp, attributes) => {
let style = {} if (attributes)
for (const key in attributes) {
if (Object.prototype.hasOwnProperty.call(attributes, key)) {
const element = attributes[key]
style[key] = element
}
} if (attributes && attributes.style) {
const S = attributes.style
.replace(
/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm,
''
)
.replace(/[\s\r\t\n]+/gm, ' ')
.split(';')
S &&
S.forEach(ele => {
ele = trim(compressSpaces((ele || '').replace(/,/g, ' ')))
var sv = ele.split(':')
if (sv && sv.length === 2) style[sv[0]] = sv[1]
})
} if ('fill' in style)
comp.background =
hexToRgba(style['fill'], Number(style['fill-opacity'] === undefined ? 1 : style['fill-opacity'])) ||
undefined if ('stroke' in style)
comp.borderColor =
hexToRgba(style['stroke'], Number(style['stroke-opacity'] === undefined ? 1 : style['stroke-opacity'])) ||
undefined
if ('opacity' in style) comp.opacity = Number(style['opacity'])
if ('stroke-width' in style) comp.borderWidth =
style['stroke-width'] === undefined ? 1 : style['stroke-width'] if (attributes?.class) { function configobj(arr) {
const result = {}
if (arr && arr.length > 0) {
let currentKey = ""
let currentValue = ""
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
currentKey = arr[i].match(/([^:;]\S[^:;]+)(?=\:)/)[0]
currentValue = arr[i].match(/(?<=\:)([^:;]\S[^:;]+)/)[0]
}
result[currentKey] = currentValue
}
}
return result
}
var sls = StyleClasse.match(/(\w*?-\w*)\s+\{\s+(\w*)\:\s+.?\w*.?\s+\}/g) || StyleClasse.match(/(?<=\.).*?\}/g)
sls && sls.forEach(element => { var r = RegExp(".*" + attributes.class + ".*", "i"); if (r.test(element)) {
var val = element.substring(element.indexOf('{') + 1, element.length).replace(/}/g, '').replace(/\s/g, "").match(/([^;]\S[^;]+)\:([^;]\S[^;]+)/g)
var values = configobj(val)
if (values) { if ('fill' in values)
comp.background =
hexToRgba(values['fill'], Number(values['fill-opacity'] === undefined ? 1 : style['fill-opacity'])) ||
undefined if ('stroke' in values)
comp.borderColor =
hexToRgba(values['stroke'], Number(values['stroke-opacity'] === undefined ? 1 : style['stroke-opacity'])) ||
undefined
if ('opacity' in values) comp.opacity = Number(values['opacity']) } } }); } comp.pixelPerfect = true
return comp
} const parseText = (k, ele) => {
let style = {} if (ele.attributes)
for (const key in ele.attributes) {
if (Object.prototype.hasOwnProperty.call(ele.attributes, key)) {
const element = ele.attributes[key]
style[key] = element
}
} const fontsize = style['font-size'] === undefined ? 24 : style['font-size']
let txt = ''
if (ele.children)
ele.children.forEach(e => {
txt += e.value || ''
}) let text: any = CreateDefalutShape(
{
type: 'text',
rect: [
X(ele.attributes.x),
Y(ele.attributes.y),
(X(fontsize) * (txt.length === undefined ? 1 : txt.length)) / 2,
Y(fontsize)
],
text: txt,
color:
hexToRgba(
style['fill'] || '#000',
Number(style['fill-opacity'] === undefined ? 1 : style['fill-opacity'])
) || undefined,
font: style['font-size'] + ' ' + style['font-family']
},
undefined
)
if ('opacity' in style) text.opacity = Number(style['opacity']) // text.rotation = style['transform']
k.comps.push(text)
} // 多线段
const parsepolygon = (k, ele) => {
let style = {} if (ele.attributes)
for (const key in ele.attributes) {
if (Object.prototype.hasOwnProperty.call(ele.attributes, key)) {
const element = ele.attributes[key]
style[key] = element
}
}
let points: any = []
if (!style['points']) return const lpoint = style['points'].split(' ') let indexkey = 0
lpoint.forEach(e => {
const p = e.split(',')
if (p && p.length === 2) points.push(X(p[0])), points.push(Y(p[1])) if (p && p.length === 1) {
indexkey % 2 === 0 && points.push(X(p[0])),
indexkey % 2 !== 0 && points.push(Y(p[0])),
indexkey++
}
}) let text: any = CreateDefalutShape(
{
type: 'shape',
points: points
},
undefined
)
if ('fill' in style)
text.background =
hexToRgba(style['fill'], Number(style['fill-opacity'] === undefined ? 1 : style['fill-opacity'])) ||
undefined
if ('stroke-linejoin' in style) text.borderJoin = style['stroke-linejoin']
if ('stroke-linecap' in style) text.orderCap = style['stroke-linecap']
if ('stroke' in style)
text.borderColor =
hexToRgba(style['stroke'], Number(style['stroke-opacity'] === undefined ? 1 : style['stroke-opacity'])) ||
undefined
if ('opacity' in style) text.opacity = Number(style['opacity'])
text.borderWidth =
style['stroke-width'] === undefined ? 1 : style['stroke-width']
k.comps.push(text)
} const parseImage = (k, ele) => {
let style = {} if (ele.attributes)
for (const key in ele.attributes) {
if (Object.prototype.hasOwnProperty.call(ele.attributes, key)) {
const element = ele.attributes[key]
style[key] = element
}
} let text: any = CreateDefalutShape(
{
type: 'image',
rect: [
X(ele.attributes.x),
Y(ele.attributes.y),
X(style['width']),
Y(style['height'])
],
name: style['href']
},
undefined
)
if ('opacity' in style) text.opacity = Number(style['opacity'])
if (
ele.attributes.x !== undefined &&
ele.attributes.y !== undefined &&
style['width'] !== undefined &&
style['height'] !== undefined &&
style['href']
)
k.comps.push(text)
} // 添加线
const parseline = (k, ele) => {
let style = {}
if (ele.attributes)
for (const key in ele.attributes) {
if (Object.prototype.hasOwnProperty.call(ele.attributes, key)) {
const element = ele.attributes[key]
style[key] = element
}
}
if (style['x1'] && style['y1'] && style['x2'] && style['y2'])
k.comps.push(
CreateDefalutShape(
{
type: 'shape',
points: [
X(style['x1']),
Y(style['y1']),
X(style['x2']),
Y(style['y2'])
],
opacity: Number(style['opacity'] === undefined ? 1 : style['opacity']),
borderColor:
hexToRgba(
style['stroke'],
Number(style['stroke-opacity'] === undefined ? 1 : style['stroke-opacity'])
) || undefined, borderWidth:
style['stroke-width'] === undefined ? 1 : style['stroke-width']
},
undefined
)
)
} // 转换形状
const parepath = (k, ele) => {
let style = {} if (ele.attributes)
for (const key in ele.attributes) {
if (Object.prototype.hasOwnProperty.call(ele.attributes, key)) {
const element = ele.attributes[key]
style[key] = element
}
} if (!style['d']) return
let S = style['d']
S = S.replace(/,/gm, ' ')
for (var r = 0; r < 2; r++)
S = S.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm, '$1 $2')
; (S = S.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2')),
(S = S.replace(/([0-9])([+\-])/gm, '$1 $2'))
for (var r = 0; r < 2; r++) S = S.replace(/(\.[0-9]*)(\.)/gm, '$1 $2')
; (S = S.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm, '$1 $3 $4 ')),
(S = compressSpaces(S)),
(S = trim(S)) let points: any = []
let segments: any = [] // 获取数据 const GetPathData = () => {
let lastkey = '' //本次key
let M_lastkey = '' // 上一次key let lastpoint = { x: 0, y: 0 }
let controlpoint = { x: 0, y: 0 }
let lastindex = 0 let A1 = 0,
A2 = 0,
A3 = 0,
A4 = 0,
A5 = 0,
A6 = 0,
A7 = 0,
c1 = 0,
c2 = 0
const Path = (key, points) => {
if (
[
'm',
'l',
'h',
'v',
'c',
's',
'q',
't',
'a',
'z',
'M',
'L',
'H',
'V',
'C',
'S',
'Q',
'T',
'A',
'Z'
].indexOf(key) > -1
) {
switch (key) {
case 'Z':
case 'z':
segments.push(5)
break
}
lastindex = 0
M_lastkey = lastkey
lastkey = key return
}
const keylst = ['c', 's', 't', 'q']
if (lastkey && key != undefined)
switch (lastkey) {
case 'M':
lastindex % 2 === 0 && lastindex === 0 &&
(segments.push(1),
(lastpoint.x = Number(key)),
points.push(X(lastpoint.x))) lastindex % 2 === 0 && lastindex > 1 &&
(segments.push(2),
(lastpoint.x = Number(key)),
points.push(X(lastpoint.x))) lastindex % 2 !== 0 &&
((lastpoint.y = Number(key)), points.push(Y(lastpoint.y)))
break case 'm':
lastindex % 2 === 0 && lastindex === 0 &&
(segments.push(1),
(lastpoint.x += Number(key)),
points.push(X(lastpoint.x)))
lastindex % 2 === 0 && lastindex > 1 &&
(segments.push(2),
(lastpoint.x += Number(key)),
points.push(X(lastpoint.x))) lastindex % 2 !== 0 &&
((lastpoint.y += Number(key)), points.push(Y(lastpoint.y))) break
case 'L':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.x = Number(key)),
points.push(X(lastpoint.x)))
lastindex % 2 !== 0 &&
((lastpoint.y = Number(key)), points.push(Y(lastpoint.y)))
break
case 'l':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.x += Number(key)),
points.push(X(lastpoint.x)))
lastindex % 2 !== 0 &&
((lastpoint.y += Number(key)), points.push(Y(lastpoint.y))) break
case 'H':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.x = Number(key)),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y)))
break
case 'h':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.x += Number(key)),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y))) break
case 'V':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.y = Number(key)),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y)))
break
case 'v':
lastindex % 2 === 0 &&
(segments.push(2),
(lastpoint.y += Number(key)),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y)))
break
case 'C':
lastindex % 2 === 0 && points.push(X(key))
lastindex % 2 !== 0 && points.push(Y(key))
if (lastindex % 6 === 4) lastpoint.x = Number(key)
if (lastindex % 6 === 5) lastpoint.y = Number(key)
if (lastindex % 6 === 0) segments.push(4) if (lastindex % 6 === 2) controlpoint.x = Number(key)
if (lastindex % 6 === 3) controlpoint.y = Number(key) break
case 'c':
lastindex % 2 === 0 && points.push(X(lastpoint.x + Number(key)))
lastindex % 2 !== 0 && points.push(Y(lastpoint.y + Number(key))) if (lastindex % 6 === 2)
controlpoint.x = lastpoint.x + Number(key)
if (lastindex % 6 === 3)
controlpoint.y = lastpoint.y + Number(key)
if (lastindex % 6 === 4) lastpoint.x += Number(key)
if (lastindex % 6 === 5) lastpoint.y += Number(key)
if (lastindex % 6 === 0) segments.push(4) if (lastindex % 6 === 2) controlpoint.x = lastpoint.x + Number(key)
if (lastindex % 6 === 3) controlpoint.y = lastpoint.y + Number(key) break
case 'S': lastindex % 4 === 0 &&
(points.push(
X(
keylst.indexOf(M_lastkey.toLowerCase()) < 0
? lastpoint.x
: 2 * lastpoint.x - controlpoint.x
)
),
points.push(
Y(
keylst.indexOf(M_lastkey.toLowerCase()) < 0
? lastpoint.y
: 2 * lastpoint.y - controlpoint.y
)
)) lastindex % 2 === 0 && points.push(X(key))
lastindex % 2 !== 0 && points.push(Y(key)) if (lastindex % 4 === 0) controlpoint.x = Number(key)
if (lastindex % 4 === 1) controlpoint.y = Number(key)
if (lastindex % 4 === 2) lastpoint.x = Number(key)
if (lastindex % 4 === 3) lastpoint.y = Number(key)
if (lastindex % 4 === 0) segments.push(4)
break
case 's': lastindex % 4 === 0 &&
(points.push(
X(
keylst.indexOf(M_lastkey.toLowerCase()) < 0
? lastpoint.x
: 2 * lastpoint.x - controlpoint.x
)
),
points.push(
Y(
keylst.indexOf(M_lastkey.toLowerCase()) < 0
? lastpoint.y
: 2 * lastpoint.y - controlpoint.y
)
))
lastindex % 2 === 0 && points.push(X(lastpoint.x + Number(key)))
lastindex % 2 !== 0 && points.push(Y(lastpoint.y + Number(key)))
if (lastindex % 4 === 0)
controlpoint.x = lastpoint.x + Number(key)
if (lastindex % 4 === 1)
controlpoint.y = lastpoint.y + Number(key)
if (lastindex % 4 === 2) lastpoint.x += Number(key)
if (lastindex % 4 === 3) lastpoint.y += Number(key)
if (lastindex % 4 === 0) segments.push(4)
break case 'Q':
case 'T':
lastindex % 2 === 0 && points.push(X(key))
lastindex % 2 !== 0 && points.push(Y(key))
if (lastindex % 4 === 2) lastpoint.x = Number(key)
if (lastindex % 4 === 3) lastpoint.y = Number(key)
if (lastindex % 4 === 0) segments.push(3)
break
case 'q':
case 't':
lastindex % 2 === 0 && points.push(X(lastpoint.x + Number(key)))
lastindex % 2 !== 0 && points.push(Y(lastpoint.y + Number(key)))
if (lastindex % 4 === 0)
controlpoint.x = lastpoint.x + Number(key)
if (lastindex % 4 === 1)
controlpoint.y = lastpoint.y + Number(key)
if (lastindex % 4 === 2) lastpoint.x += Number(key)
if (lastindex % 4 === 3) lastpoint.y += Number(key)
if (lastindex % 4 === 0) segments.push(3)
case 'A':
if (lastindex % 7 === 0)
(A1 = Number(key)), (c1 = lastpoint.x), (c2 = lastpoint.y)
if (lastindex % 7 === 1) A2 = Number(key)
if (lastindex % 7 === 2) A3 = Number(key) * (Math.PI / 180)
if (lastindex % 7 === 3) A4 = Number(key)
if (lastindex % 7 === 4) A5 = Number(key) if (lastindex % 7 === 5)
(lastpoint.x = Number(key)), (A6 = lastpoint.x)
if (lastindex % 7 === 6)
(lastpoint.y = Number(key)), (A7 = lastpoint.y)
if (lastindex % 7 === 6) {
const x =
(Math.cos(A3) * (c1 - A6)) / 2 +
(Math.sin(A3) * (c2 - A7)) / 2
const y =
(-Math.sin(A3) * (c1 - A6)) / 2 +
(Math.cos(A3) * (c2 - A7)) / 2
const M =
Math.pow(x, 2) / Math.pow(A1, 2) +
Math.pow(y, 2) / Math.pow(A2, 2)
M < 1e-6 &&
(segments.push(2),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y))) if (!(M < 1e-6)) {
const curves = arcToBezier({
px: c1,
py: c2,
cx: A6,
cy: A7,
rx: A1,
ry: A2,
xAxisRotation: A3,
largeArcFlag: A4,
sweepFlag: A5
})
curves &&
curves.forEach(c => {
c &&
(segments.push(4),
points.push(X(c['x1'])),
points.push(Y(c['y1'])),
points.push(X(c['x2'])),
points.push(Y(c['y2'])),
points.push(X(c['x'])),
points.push(Y(c['y'])))
})
}
} break
case 'a':
if (lastindex % 7 === 0)
(A1 = Number(key)), (c1 = lastpoint.x), (c2 = lastpoint.y)
if (lastindex % 7 === 1) A2 = Number(key)
if (lastindex % 7 === 2) A3 = Number(key) * (Math.PI / 180)
if (lastindex % 7 === 3) A4 = Number(key)
if (lastindex % 7 === 4) A5 = Number(key) if (lastindex % 7 === 5)
(lastpoint.x += Number(key)), (A6 = lastpoint.x)
if (lastindex % 7 === 6)
(lastpoint.y += Number(key)), (A7 = lastpoint.y)
if (lastindex % 7 === 6) {
const x =
(Math.cos(A3) * (c1 - A6)) / 2 +
(Math.sin(A3) * (c2 - A7)) / 2
const y =
(-Math.sin(A3) * (c1 - A6)) / 2 +
(Math.cos(A3) * (c2 - A7)) / 2
const M =
Math.pow(x, 2) / Math.pow(A1, 2) +
Math.pow(y, 2) / Math.pow(A2, 2)
M < 1e-6 &&
(segments.push(2),
points.push(X(lastpoint.x)),
points.push(Y(lastpoint.y))) if (!(M < 1e-6)) {
const curves = arcToBezier({
px: c1,
py: c2,
cx: A6,
cy: A7,
rx: A1,
ry: A2,
xAxisRotation: A3,
largeArcFlag: A4,
sweepFlag: A5
})
curves &&
curves.forEach(c => {
c &&
(segments.push(4),
points.push(X(c['x1'])),
points.push(Y(c['y1'])),
points.push(X(c['x2'])),
points.push(Y(c['y2'])),
points.push(X(c['x'])),
points.push(Y(c['y'])))
})
}
} break default:
break
} lastindex++
} const tonkes = S.split(' ') tonkes.forEach((element, _index) => {
Path(element, points)
})
} GetPathData()
let text: any = CreateDefalutShape(
{
type: 'shape',
points: points,
segments: segments
},
undefined
) if ('fill' in style) {
text.background = hexToRgba(
style['fill'],
Number(style['fill-opacity'] === undefined ? 1 : style['fill-opacity'])
)
} else {
text.background = hexToRgba('#000', Number(style['fill-opacity'] === undefined ? 1 : style['fill-opacity']))
} if ('stroke-linejoin' in style) text.borderJoin = style['stroke-linejoin']
if ('stroke-linecap' in style) text.orderCap = style['stroke-linecap']
if ('stroke' in style)
text.borderColor =
hexToRgba(style['stroke'], Number(style['stroke-opacity'] === undefined ? 1 : style['stroke-opacity'])) ||
undefined
if ('opacity' in style) text.opacity = Number(style['opacity'] === undefined ? 1 : style['opacity'])
text.borderWidth =
style['stroke-width'] === undefined ? 1 : style['stroke-width'] if (ele?.attributes?.class) { function configobj(arr) {
const result = {}
if (arr && arr.length > 0) {
let currentKey = ""
let currentValue = ""
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
currentKey = arr[i].match(/([^:;]\S[^:;]+)(?=\:)/)[0]
currentValue = arr[i].match(/(?<=\:)([^:;]\S[^:;]+)/)[0]
}
result[currentKey] = currentValue
}
}
return result
}
var sls = StyleClasse.match(/(\w*?-\w*)\s+\{\s+(\w*)\:\s+.?\w*.?\s+\}/g) || StyleClasse.match(/(?<=\.).*?\}/g)
sls && sls.forEach(element => { var r = RegExp(".*" + ele.attributes.class + ".*", "i"); if (r.test(element)) { var val = element.substring(element.indexOf('{') + 1, element.length).replace(/}/g, '').replace(/\s/g, "").match(/([^;]\S[^;]+)\:([^;]\S[^;]+)/g)
var values = configobj(val)
if (values) {
if ('fill' in values) {
text.background = hexToRgba(
values['fill'],
Number(values['fill-opacity'] === undefined ? 1 : values['fill-opacity'])
)
} if ('stroke-linejoin' in values) text.borderJoin = values['stroke-linejoin']
if ('stroke-linecap' in values) text.orderCap = values['stroke-linecap']
if ('stroke' in values)
text.borderColor =
hexToRgba(values['stroke'], Number(values['stroke-opacity'] === undefined ? 1 : values['stroke-opacity'])) ||
undefined
if ('opacity' in values) text.opacity = Number(values['opacity'] === undefined ? 1 : values['opacity'])
text.borderWidth =
values['stroke-width'] === undefined ? 1 : values['stroke-width'] } } }); } k.comps.push(text)
} let linearGradient_list: any = []
let linearGradient_comp: any
// 渐变色
const linearGradient = ele => {
if (ele && ele.attributes && ele.attributes.id) {
linearGradient_comp = new Object()
linearGradient_comp.id = ele.attributes.id
ele.attributes.x1 && (linearGradient_comp.x1 = X(ele.attributes.x1))
ele.attributes.y1 && (linearGradient_comp.y1 = Y(ele.attributes.y1))
ele.attributes.x2 && (linearGradient_comp.x2 = X(ele.attributes.x2))
ele.attributes.y2 && (linearGradient_comp.y2 = Y(ele.attributes.y2))
linearGradient_comp.styles = []
linearGradient_list.push(linearGradient_comp)
}
ele.children &&
ele.children.forEach(element => {
element.attributes &&
linearGradient_comp.styles.push({
offset: element.attributes.offset,
color: element.attributes.style
})
}) } //样式
const parseClass = (val, defs: any = undefined) => { if (val && val.value) {
StyleClasse += val.value
}
val && val.children && val.children.forEach(o => parseClass(o)) if (defs) {
// 样式对象
}
} const parseSvg = (k, list, _value = undefined) => {
list &&
list.forEach((ele, _index) => { if (ele.type === 'element' && ele.name === 'style') {
// 样式
parseClass(ele)
}
if (ele.type === 'element' && ele.name === 'linearGradient') {
// 渐变色
linearGradient(ele)
} if (ele.type === 'element' && ele.name === 'text') {
parseText(k, ele) return
}
if (ele.children && ele.children.length > 0) {
parseSvg(k, ele.children, ele.value)
} else if (ele.attributes) { switch (ele.name || ele.type) {
case 'g':
parseSvg(k, ele.children, ele.value)
break
case 'circle':
k.comps.push(
CreateDefalutShape(
{
type: 'circle',
rect: [
X(ele.attributes.cx) - X(ele.attributes.r),
Y(ele.attributes.cy) - Y(ele.attributes.r),
X(ele.attributes.r) * 2,
Y(ele.attributes.r) * 2
]
},
ele.attributes
)
)
break
case 'rect': ele.attributes.d = Rect2path(X(ele.attributes.x), Y(ele.attributes.y), X(ele.attributes.width), Y(ele.attributes.height), X(ele.attributes.rx), Y(ele.attributes.ry))
parepath(k, ele) break
case 'ellipse': // ele.attributes.d = Ellipse2path(X(ele.attributes.cx), Y(ele.attributes.cy), X(ele.attributes.rx), Y(ele.attributes.ry)) // parepath(k, ele) k.comps.push(
CreateDefalutShape(
{
type: 'oval',
rect: [
X(ele.attributes.cx) - X(ele.attributes.rx),
Y(ele.attributes.cy) - Y(ele.attributes.ry),
X(ele.attributes.rx) * 2,
Y(ele.attributes.ry) * 2
]
},
ele.attributes
)
) break
case 'path':
parepath(k, ele)
break case 'polygon':
parsepolygon(k, ele) break
case 'line':
parseline(k, ele) break case 'image':
parseImage(k, ele) break
default:
break
}
} })
}
StyleClasse = ''
URL &&
ht.Default.xhrLoad(URL, text => {
parse(text)
.then(json => { const ToNumberArray = function (x) {
for (
var S = trim(compressSpaces((x || '').replace(/,/g, ' '))).split(
' '
),
r = 0;
r < S.length;
r++
)
S[r] = parseFloat(S[r])
return S
} json.attributes &&
((k.width = Number(json.attributes.width === undefined ? 512 : json.attributes.width)),
(k.height = Number(json.attributes.height === undefined ? 512 : json.attributes.height)))
if (json.attributes.viewBox) {
const viewBox = ToNumberArray(json.attributes.viewBox)
scaleX = (viewBox[2] - viewBox[0]) / k.width
scaleY = (viewBox[3] - viewBox[1]) / k.height
}
refX = parseFloat(json.attributes.refX) || 0
refY = parseFloat(json.attributes.refY) || 0 json.children && parseClass(undefined, json.children.map(o => o.name === 'defs')) json.children && parseSvg(k, json.children) JsonToView(k, oBJht)
})
.catch(error => {
ElMessage({
type: 'error',
message: error?.toString()
})
})
})
file &&
parse(file)
.then(json => {
const ToNumberArray = function (x) {
for (
var S = trim(compressSpaces((x || '').replace(/,/g, ' '))).split(
' '
),
r = 0;
r < S.length;
r++
)
S[r] = parseFloat(S[r])
return S
} json.attributes &&
json.attributes.width &&
(k.width = Number(
json.attributes.width.toLowerCase().replace('px', '')
)) json.attributes &&
json.attributes.height &&
(k.height = Number(
json.attributes.height.toLowerCase().replace('px', '')
))
if (json.attributes.viewBox) {
const viewBox = ToNumberArray(json.attributes.viewBox)
scaleX = (viewBox[2] - viewBox[0]) / k.width
scaleY = (viewBox[3] - viewBox[1]) / k.height
}
refX = parseFloat(json.attributes.refX) || 0
refY = parseFloat(json.attributes.refY) || 0 json.children && parseClass(undefined, json.children.filter(o => o.name === 'defs'))
json.children && parseSvg(k, json.children) JsonToView(k, oBJht)
callback && callback()
})
.catch(error => {
ElMessage({
type: 'error',
message: error?.toString()
})
})
} export default SvgToShape

二维Svg转矢量 不支持Svg2.0的相关教程结束。

《二维Svg转矢量 不支持Svg2.0.doc》

下载本文的Word格式文档,以方便收藏与打印。