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