aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/core/attr.js
blob: 7cb9e2a2a171d7eeae7832b2789dd9ede3371b97 (plain)
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
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 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 ( let 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' ) {

    // 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 ( 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

}