summaryrefslogtreecommitdiffstats
path: root/src/color.js
blob: 43bafcb9c697385d21340a1abd13c88ef0eb561a (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* globals fullHex, compToHex */

/*

Color {
  constructor (a, b, c, space) {
    space: 'hsl'
    a: 30
    b: 20
    c: 10
  },

  toRgb () { return new Color in rgb space }
  toHsl () { return new Color in hsl space }
  toLab () { return new Color in lab space }

  toArray () { [space, a, b, c] }
  fromArray () { convert it back }
}

// Conversions aren't always exact because of monitor profiles etc...
new Color(h, s, l, 'hsl') !== new Color(r, g, b).hsl()
new Color(100, 100, 100, [space])
new Color('hsl(30, 20, 10)')

// Sugar
SVG.rgb(30, 20, 50).lab()
SVG.hsl()
SVG.lab('rgb(100, 100, 100)')
*/

// Module for color convertions
SVG.Color = function (color, g, b) {
  var match

  // initialize defaults
  this.r = 0
  this.g = 0
  this.b = 0

  if (!color) return

  // parse color
  if (typeof color === 'string') {
    if (SVG.regex.isRgb.test(color)) {
      // get rgb values
      match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace, ''))

      // parse numeric values
      this.r = parseInt(match[1])
      this.g = parseInt(match[2])
      this.b = parseInt(match[3])
    } else if (SVG.regex.isHex.test(color)) {
      // get hex values
      match = SVG.regex.hex.exec(fullHex(color))

      // parse numeric values
      this.r = parseInt(match[1], 16)
      this.g = parseInt(match[2], 16)
      this.b = parseInt(match[3], 16)
    }
  } else if (Array.isArray(color)) {
    this.r = color[0]
    this.g = color[1]
    this.b = color[2]
  } else if (typeof color === 'object') {
    this.r = color.r
    this.g = color.g
    this.b = color.b
  } else if (arguments.length === 3) {
    this.r = color
    this.g = g
    this.b = b
  }
}

SVG.extend(SVG.Color, {
  // Default to hex conversion
  toString: function () {
    return this.toHex()
  },
  toArray: function () {
    return [this.r, this.g, this.b]
  },
  fromArray: function (a) {
    return new SVG.Color(a)
  },
  // Build hex value
  toHex: function () {
    return '#' +
      compToHex(Math.round(this.r)) +
      compToHex(Math.round(this.g)) +
      compToHex(Math.round(this.b))
  },
  // Build rgb value
  toRgb: function () {
    return 'rgb(' + [this.r, this.g, this.b].join() + ')'
  },
  // Calculate true brightness
  brightness: function () {
    return (this.r / 255 * 0.30) +
      (this.g / 255 * 0.59) +
      (this.b / 255 * 0.11)
  },
  // Make color morphable
  morph: function (color) {
    this.destination = new SVG.Color(color)

    return this
  },
  // Get morphed color at given position
  at: function (pos) {
    // make sure a destination is defined
    if (!this.destination) return this

    // normalise pos
    pos = pos < 0 ? 0 : pos > 1 ? 1 : pos

    // generate morphed color
    return new SVG.Color({
      r: ~~(this.r + (this.destination.r - this.r) * pos),
      g: ~~(this.g + (this.destination.g - this.g) * pos),
      b: ~~(this.b + (this.destination.b - this.b) * pos)
    })
  }

})

// Testers

// Test if given value is a color string
SVG.Color.test = function (color) {
  color += ''
  return SVG.regex.isHex.test(color) ||
    SVG.regex.isRgb.test(color)
}

// Test if given value is a rgb object
SVG.Color.isRgb = function (color) {
  return color && typeof color.r === 'number' &&
    typeof color.g === 'number' &&
    typeof color.b === 'number'
}

// Test if given value is a color
SVG.Color.isColor = function (color) {
  return SVG.Color.isRgb(color) || SVG.Color.test(color)
}