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
|
import { attrs as defaults } from './defaults.js'
import { isNumber } from './regex.js'
import Color from '../../types/Color.js'
import SVGArray from '../../types/SVGArray.js'
import SVGNumber from '../../types/SVGNumber.js'
const colorAttributes = new Set([
'fill',
'stroke',
'color',
'bgcolor',
'stop-color',
'flood-color',
'lighting-color'
])
const hooks = []
export function registerAttrHook(fn) {
hooks.push(fn)
}
// Set svg element attribute
export default function attr(attr, val, ns) {
// act as full getter
if (attr == null) {
// get an object of attributes
attr = {}
val = this.node.attributes
for (const node of val) {
attr[node.nodeName] = isNumber.test(node.nodeValue)
? parseFloat(node.nodeValue)
: node.nodeValue
}
return attr
} else if (attr instanceof Array) {
// loop through array and get all values
return attr.reduce((last, curr) => {
last[curr] = this.attr(curr)
return last
}, {})
} else if (typeof attr === 'object' && attr.constructor === Object) {
// apply every attribute individually if an object is passed
for (val in attr) this.attr(val, attr[val])
} else if (val === null) {
// remove value
this.node.removeAttribute(attr)
} else if (val == null) {
// act as a getter if the first and only argument is not an object
val = this.node.getAttribute(attr)
return val == null
? defaults[attr]
: isNumber.test(val)
? parseFloat(val)
: val
} else {
// Loop through hooks and execute them to convert value
val = hooks.reduce((_val, hook) => {
return hook(attr, _val, this)
}, val)
// ensure correct numeric values (also accepts NaN and Infinity)
if (typeof val === 'number') {
val = new SVGNumber(val)
} else if (colorAttributes.has(attr) && Color.isColor(val)) {
// ensure full hex color
val = new Color(val)
} else if (val.constructor === Array) {
// Check for plain arrays and parse array values
val = new SVGArray(val)
}
// if the passed attribute is leading...
if (attr === 'leading') {
// ... call the leading method instead
if (this.leading) {
this.leading(val)
}
} else {
// set given attribute on node
typeof ns === 'string'
? this.node.setAttributeNS(ns, attr, val.toString())
: this.node.setAttribute(attr, val.toString())
}
// rebuild if required
if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
this.rebuild()
}
}
return this
}
|