@svgedit/svgcanvas 7.2.6 → 7.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # svgcanvas CHANGES
2
2
 
3
+
4
+ ## 7.2.7
5
+ - Prefer href to xlink href (#1059)
6
+ - Fix group rotation (#1058)
7
+ - Fixed a bug where a rotated text or image did not translate correctly. (#1055)
8
+
3
9
  ## 7.2.5
4
10
  - update dependencies
5
11
 
package/core/history.js CHANGED
@@ -425,7 +425,7 @@ export class BatchCommand extends Command {
425
425
  */
426
426
  unapply (handler) {
427
427
  super.unapply(handler, () => {
428
- this.stack.reverse().forEach((stackItem) => {
428
+ [...this.stack].reverse().forEach((stackItem) => {
429
429
  console.assert(stackItem, 'stack item should not be null')
430
430
  stackItem && stackItem.unapply(handler)
431
431
  })
package/core/paint.js CHANGED
@@ -4,7 +4,7 @@
4
4
  export default class Paint {
5
5
  /**
6
6
  * @param {module:jGraduate.jGraduatePaintOptions} [opt]
7
- */
7
+ */
8
8
  constructor (opt) {
9
9
  const options = opt || {}
10
10
  this.alpha = isNaN(options.alpha) ? 100 : options.alpha
@@ -51,33 +51,39 @@ export default class Paint {
51
51
  this.radialGradient = options.copy.radialGradient.cloneNode(true)
52
52
  break
53
53
  }
54
- // create linear gradient paint
54
+ // create linear gradient paint
55
55
  } else if (options.linearGradient) {
56
56
  this.type = 'linearGradient'
57
57
  this.solidColor = null
58
58
  this.radialGradient = null
59
- if (options.linearGradient.hasAttribute('xlink:href')) {
60
- const xhref = document.getElementById(options.linearGradient.getAttribute('xlink:href').substr(1))
59
+ const hrefAttr =
60
+ options.linearGradient.getAttribute('href') ||
61
+ options.linearGradient.getAttribute('xlink:href')
62
+ if (hrefAttr) {
63
+ const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
61
64
  this.linearGradient = xhref.cloneNode(true)
62
65
  } else {
63
66
  this.linearGradient = options.linearGradient.cloneNode(true)
64
67
  }
65
- // create linear gradient paint
68
+ // create linear gradient paint
66
69
  } else if (options.radialGradient) {
67
70
  this.type = 'radialGradient'
68
71
  this.solidColor = null
69
72
  this.linearGradient = null
70
- if (options.radialGradient.hasAttribute('xlink:href')) {
71
- const xhref = document.getElementById(options.radialGradient.getAttribute('xlink:href').substr(1))
73
+ const hrefAttr =
74
+ options.radialGradient.getAttribute('href') ||
75
+ options.radialGradient.getAttribute('xlink:href')
76
+ if (hrefAttr) {
77
+ const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
72
78
  this.radialGradient = xhref.cloneNode(true)
73
79
  } else {
74
80
  this.radialGradient = options.radialGradient.cloneNode(true)
75
81
  }
76
- // create solid color paint
82
+ // create solid color paint
77
83
  } else if (options.solidColor) {
78
84
  this.type = 'solidColor'
79
85
  this.solidColor = options.solidColor
80
- // create empty paint
86
+ // create empty paint
81
87
  } else {
82
88
  this.type = 'none'
83
89
  this.solidColor = null
@@ -236,16 +236,35 @@ export const recalculateDimensions = selected => {
236
236
  // Handle rotation transformations
237
237
  const angle = getRotationAngle(selected)
238
238
  if (angle) {
239
- // Include x and y in the rotation center calculation
240
- oldcenter = {
241
- x: box.x + box.width / 2 + x,
242
- y: box.y + box.height / 2 + y
239
+ if (selected.localName === 'image') {
240
+ // Use the center of the image as the rotation center
241
+ const xAttr = convertToNum('x', selected.getAttribute('x') || '0')
242
+ const yAttr = convertToNum('y', selected.getAttribute('y') || '0')
243
+ const width = convertToNum('width', selected.getAttribute('width') || '0')
244
+ const height = convertToNum('height', selected.getAttribute('height') || '0')
245
+ const cx = xAttr + width / 2
246
+ const cy = yAttr + height / 2
247
+ oldcenter = { x: cx, y: cy }
248
+ const transform = transformListToTransform(tlist).matrix
249
+ newcenter = transformPoint(cx, cy, transform)
250
+ } else if (selected.localName === 'text') {
251
+ // Use the center of the bounding box as the rotation center for text
252
+ const cx = box.x + box.width / 2
253
+ const cy = box.y + box.height / 2
254
+ oldcenter = { x: cx, y: cy }
255
+ newcenter = transformPoint(cx, cy, transformListToTransform(tlist).matrix)
256
+ } else {
257
+ // Include x and y in the rotation center calculation for other elements
258
+ oldcenter = {
259
+ x: box.x + box.width / 2 + x,
260
+ y: box.y + box.height / 2 + y
261
+ }
262
+ newcenter = transformPoint(
263
+ box.x + box.width / 2 + x,
264
+ box.y + box.height / 2 + y,
265
+ transformListToTransform(tlist).matrix
266
+ )
243
267
  }
244
- newcenter = transformPoint(
245
- box.x + box.width / 2 + x,
246
- box.y + box.height / 2 + y,
247
- transformListToTransform(tlist).matrix
248
- )
249
268
 
250
269
  // Remove the rotation transform from the list
251
270
  for (let i = 0; i < tlist.numberOfItems; ++i) {
package/core/sanitize.js CHANGED
@@ -21,7 +21,7 @@ const REVERSE_NS = getReverseNS()
21
21
  const svgGenericWhiteList = ['class', 'id', 'display', 'transform', 'style']
22
22
  const svgWhiteList_ = {
23
23
  // SVG Elements
24
- a: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title'],
24
+ a: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'href', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title'],
25
25
  circle: ['clip-path', 'clip-rule', 'cx', 'cy', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'],
26
26
  clipPath: ['clipPathUnits'],
27
27
  defs: [],
@@ -36,20 +36,20 @@ const svgWhiteList_ = {
36
36
  feMergeNode: ['in'],
37
37
  feMorphology: ['in', 'operator', 'radius'],
38
38
  feOffset: ['dx', 'in', 'dy', 'result'],
39
- filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
39
+ filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'href', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
40
40
  foreignObject: ['font-size', 'height', 'opacity', 'requiredFeatures', 'width', 'x', 'y'],
41
41
  g: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'],
42
- image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'xlink:href', 'xlink:title', 'y'],
42
+ image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'href', 'xlink:href', 'xlink:title', 'y'],
43
43
  line: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'x1', 'x2', 'y1', 'y2'],
44
- linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'],
44
+ linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'href', 'xlink:href', 'y1', 'y2'],
45
45
  marker: ['markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'se_type', 'systemLanguage', 'viewBox'],
46
46
  mask: ['height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
47
47
  metadata: [],
48
48
  path: ['clip-path', 'clip-rule', 'd', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'],
49
- pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'],
49
+ pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'href', 'xlink:href', 'y'],
50
50
  polygon: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'sides', 'shape', 'edge', 'point', 'starRadiusMultiplier', 'r', 'radialshift', 'r2', 'orient', 'cx', 'cy'],
51
51
  polyline: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'se:connector'],
52
- radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
52
+ radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'href', 'xlink:href'],
53
53
  rect: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'width', 'x', 'y'],
54
54
  stop: ['offset', 'requiredFeatures', 'stop-opacity', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform'],
55
55
  style: ['type'],
@@ -57,10 +57,10 @@ const svgWhiteList_ = {
57
57
  switch: ['requiredFeatures', 'systemLanguage'],
58
58
  symbol: ['fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'opacity', 'overflow', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'viewBox', 'width', 'height'],
59
59
  text: ['clip-path', 'clip-rule', 'dominant-baseline', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'letter-spacing', 'word-spacing', 'text-decoration', 'textLength', 'lengthAdjust', 'x', 'xml:space', 'y'],
60
- textPath: ['dominant-baseline', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
60
+ textPath: ['dominant-baseline', 'href', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
61
61
  title: [],
62
62
  tspan: ['clip-path', 'clip-rule', 'dx', 'dy', 'dominant-baseline', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'textLength', 'x', 'xml:space', 'y'],
63
- use: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow'],
63
+ use: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'href', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow'],
64
64
  // Filter Primitives
65
65
  feComponentTransfer: ['in', 'result'],
66
66
  feFuncR: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'],
@@ -91,7 +91,7 @@ const svgWhiteList_ = {
91
91
  mphantom: [],
92
92
  mprescripts: [],
93
93
  mroot: [],
94
- mrow: ['xlink:href', 'xlink:type', 'xmlns:xlink'],
94
+ mrow: ['href', 'xlink:href', 'xlink:type', 'xmlns:xlink'],
95
95
  mspace: ['depth', 'height', 'width'],
96
96
  msqrt: [],
97
97
  mstyle: ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'],
@@ -190,16 +190,20 @@ export const sanitizeSvg = (node) => {
190
190
  // our whitelist or is a namespace declaration for one of our allowed namespaces
191
191
  if (attrNsURI !== allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS &&
192
192
  !(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) {
193
- // Bypassing the whitelist to allow se: and oi: prefixes
194
- // We can add specific namepaces on demand for now.
195
- // Is there a more appropriate way to do this?
196
- if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) {
197
- // We should bypass the namespace aswell
198
- const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null)
199
- seAttrs.push([attrName, attr.value, seAttrNS])
200
- } else {
201
- console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed`)
202
- node.removeAttributeNS(attrNsURI, attrLocalName)
193
+ // Special case: allow href attribute even without namespace if it's in the whitelist
194
+ const isHrefAttribute = (attrLocalName === 'href' && allowedAttrs.includes('href'))
195
+ if (!isHrefAttribute) {
196
+ // Bypassing the whitelist to allow se: and oi: prefixes
197
+ // We can add specific namepaces on demand for now.
198
+ // Is there a more appropriate way to do this?
199
+ if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) {
200
+ // We should bypass the namespace aswell
201
+ const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null)
202
+ seAttrs.push([attrName, attr.value, seAttrNS])
203
+ } else {
204
+ console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed: ${node.outerHTML}`)
205
+ node.removeAttributeNS(attrNsURI, attrLocalName)
206
+ }
203
207
  }
204
208
  }
205
209
 
@@ -224,34 +228,35 @@ export const sanitizeSvg = (node) => {
224
228
  node.setAttributeNS(ns, att, val)
225
229
  })
226
230
 
227
- // for some elements that have a xlink:href, ensure the URI refers to a local element
228
- // (but not for links)
231
+ // for some elements that have a xlink:href or href, ensure the URI refers to a local element
232
+ // (but not for links and other elements where external hrefs are allowed)
229
233
  const href = getHref(node)
230
234
  if (href &&
231
235
  ['filter', 'linearGradient', 'pattern',
232
236
  'radialGradient', 'textPath', 'use'].includes(node.nodeName) && href[0] !== '#') {
233
237
  // remove the attribute (but keep the element)
234
238
  setHref(node, '')
235
- console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed`)
239
+ console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed: ${node.outerHTML}`)
236
240
  node.removeAttributeNS(NS.XLINK, 'href')
241
+ node.removeAttribute('href')
237
242
  }
238
243
 
239
244
  // Safari crashes on a <use> without a xlink:href, so we just remove the node here
240
245
  if (node.nodeName === 'use' && !getHref(node)) {
241
- console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href is removed`)
246
+ console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href or href is removed: ${node.outerHTML}`)
242
247
  node.remove()
243
248
  return
244
249
  }
245
250
  // if the element has attributes pointing to a non-local reference,
246
251
  // need to remove the attribute
247
- Object.values(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], (attr) => {
252
+ ['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'].forEach((attr) => {
248
253
  let val = node.getAttribute(attr)
249
254
  if (val) {
250
255
  val = getUrlFromAttr(val)
251
256
  // simply check for first character being a '#'
252
257
  if (val && val[0] !== '#') {
253
258
  node.setAttribute(attr, '')
254
- console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed`)
259
+ console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed: ${node.outerHTML}`)
255
260
  node.removeAttribute(attr)
256
261
  }
257
262
  }
@@ -264,7 +269,7 @@ export const sanitizeSvg = (node) => {
264
269
  } else {
265
270
  // remove all children from this node and insert them before this node
266
271
  // TODO: in the case of animation elements this will hardly ever be correct
267
- console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed`)
272
+ console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed: ${node.outerHTML}`)
268
273
  const children = []
269
274
  while (node.hasChildNodes()) {
270
275
  children.push(parent.insertBefore(node.firstChild, node))
package/core/svg-exec.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  text2xml,
13
13
  cleanupElement,
14
14
  findDefs,
15
+ setHref,
15
16
  getHref,
16
17
  preventClickDefault,
17
18
  toXml,
@@ -443,7 +444,8 @@ const setSvgString = (xmlString, preventUndo) => {
443
444
  // const url = decodeURIComponent(m.groups.url);
444
445
  const iimg = new Image()
445
446
  iimg.addEventListener('load', () => {
446
- image.setAttributeNS(NS.XLINK, 'xlink:href', url)
447
+ // Set the href attribute to the data URL
448
+ setHref(image, val)
447
449
  })
448
450
  iimg.src = url
449
451
  }
@@ -858,7 +860,7 @@ const convertImagesToBase64 = async svgElement => {
858
860
  const reader = new FileReader()
859
861
  return new Promise(resolve => {
860
862
  reader.onload = () => {
861
- img.setAttribute('xlink:href', reader.result)
863
+ setHref(img, reader.result)
862
864
  resolve()
863
865
  }
864
866
  reader.readAsDataURL(blob)
package/core/utilities.js CHANGED
@@ -376,21 +376,22 @@ export const getUrlFromAttr = function (attrVal) {
376
376
  /**
377
377
  * @function module:utilities.getHref
378
378
  * @param {Element} elem
379
- * @returns {string} The given element's `xlink:href` value
379
+ * @returns {string} The given element's `href` value
380
380
  */
381
381
  export let getHref = function (elem) {
382
- return elem.getAttributeNS(NS.XLINK, 'href')
382
+ // Prefer 'href', fallback to 'xlink:href'
383
+ return elem.getAttribute('href') || elem.getAttributeNS(NS.XLINK, 'href')
383
384
  }
384
385
 
385
386
  /**
386
- * Sets the given element's `xlink:href` value.
387
+ * Sets the given element's `href` value.
387
388
  * @function module:utilities.setHref
388
389
  * @param {Element} elem
389
390
  * @param {string} val
390
391
  * @returns {void}
391
392
  */
392
393
  export let setHref = function (elem, val) {
393
- elem.setAttributeNS(NS.XLINK, 'xlink:href', val)
394
+ elem.setAttribute('href', val)
394
395
  }
395
396
 
396
397
  /**
@@ -665,38 +666,38 @@ export const getPathDFromElement = function (elem) {
665
666
  const h = b.height
666
667
  num = 4 - num // Why? Because!
667
668
 
668
- d = (!rx && !ry)
669
- // Regular rect
670
- ? getPathDFromSegments([
671
- ['M', [x, y]],
672
- ['L', [x + w, y]],
673
- ['L', [x + w, y + h]],
674
- ['L', [x, y + h]],
675
- ['L', [x, y]],
676
- ['Z', []]
677
- ])
678
- : getPathDFromSegments([
679
- ['M', [x, y + ry]],
680
- ['C', [x, y + ry / num, x + rx / num, y, x + rx, y]],
681
- ['L', [x + w - rx, y]],
682
- ['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]],
683
- ['L', [x + w, y + h - ry]],
684
- [
685
- 'C',
669
+ d =
670
+ !rx && !ry // Regular rect
671
+ ? getPathDFromSegments([
672
+ ['M', [x, y]],
673
+ ['L', [x + w, y]],
674
+ ['L', [x + w, y + h]],
675
+ ['L', [x, y + h]],
676
+ ['L', [x, y]],
677
+ ['Z', []]
678
+ ])
679
+ : getPathDFromSegments([
680
+ ['M', [x, y + ry]],
681
+ ['C', [x, y + ry / num, x + rx / num, y, x + rx, y]],
682
+ ['L', [x + w - rx, y]],
683
+ ['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]],
684
+ ['L', [x + w, y + h - ry]],
686
685
  [
687
- x + w,
688
- y + h - ry / num,
689
- x + w - rx / num,
690
- y + h,
691
- x + w - rx,
692
- y + h
693
- ]
694
- ],
695
- ['L', [x + rx, y + h]],
696
- ['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]],
697
- ['L', [x, y + ry]],
698
- ['Z', []]
699
- ])
686
+ 'C',
687
+ [
688
+ x + w,
689
+ y + h - ry / num,
690
+ x + w - rx / num,
691
+ y + h,
692
+ x + w - rx,
693
+ y + h
694
+ ]
695
+ ],
696
+ ['L', [x + rx, y + h]],
697
+ ['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]],
698
+ ['L', [x, y + ry]],
699
+ ['Z', []]
700
+ ])
700
701
  break
701
702
  }
702
703
  default: