diff options
author | wout <wout@impinc.co.uk> | 2013-03-06 19:43:17 +0000 |
---|---|---|
committer | wout <wout@impinc.co.uk> | 2013-03-06 19:43:17 +0000 |
commit | 5e3ff072994d3d9b224c62d71ca1331951249bac (patch) | |
tree | 9bb8b5af1ca4372fcf0c03b0444530fefee20735 /src | |
parent | 6a8a3fee7dbfc9a9f4a36dc5877f955f5743a4ac (diff) | |
download | svg.js-5e3ff072994d3d9b224c62d71ca1331951249bac.tar.gz svg.js-5e3ff072994d3d9b224c62d71ca1331951249bac.zip |
Reworked color management
Diffstat (limited to 'src')
-rw-r--r-- | src/color.js | 165 | ||||
-rw-r--r-- | src/element.js | 4 | ||||
-rw-r--r-- | src/fx.js | 46 | ||||
-rw-r--r-- | src/regex.js | 15 | ||||
-rw-r--r-- | src/sugar.js | 2 |
5 files changed, 191 insertions, 41 deletions
diff --git a/src/color.js b/src/color.js new file mode 100644 index 0000000..dde2c65 --- /dev/null +++ b/src/color.js @@ -0,0 +1,165 @@ +// Module for color convertions +SVG.Color = function(color) { + var match + + /* initialize defaults */ + this.r = 0 + this.g = 0 + this.b = 0 + + /* parse color */ + if (typeof color == 'string') { + if (SVG.regex.isRgb.test(color)) { + /* get rgb values */ + match = SVG.regex.rgb.exec(color.replace(/\s/g,'')) + + /* parse numeric values */ + this.r = parseInt(m[1]) + this.g = parseInt(m[2]) + this.b = parseInt(m[3]) + + } else if (SVG.regex.isHex.test(color)) { + /* get hex values */ + match = SVG.regex.hex.exec(this._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 (SVG.regex.isHsb.test(color)) { + /* get hsb values */ + match = SVG.regex.hsb.exec(color.replace(/\s/g,'')) + + /* convert hsb to rgb */ + color = this._hsbToRgb(match[1], match[2], match[3]) + } + + } else if (typeof color == 'object') { + if (SVG.Color.isHsb(color)) + color = this._hsbToRgb(color.h, color.s, color.b) + + this.r = color.r + this.g = color.g + this.b = color.b + + } + +} + +SVG.extend(SVG.Color, { + // Default to hex conversion + toString: function() { + return this.toHex() + } + // Build hex value +, toHex: function() { + return '#' + + this._compToHex(this.r) + + this._compToHex(this.g) + + this._compToHex(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) + } + // Private: convert hsb to rgb +, _hsbToRgb: function(h, s, v) { + var vs, vsf + + /* process hue */ + h = parseInt(h) % 360 + if (h < 0) h += 360 + + /* process saturation */ + s = parseInt(s) + s = s > 100 ? 100 : s + + /* process brightness */ + v = parseInt(v) + v = (v < 0 ? 0 : v > 100 ? 100 : v) * 255 / 100 + + /* compile rgb */ + vs = v * s / 100 + vsf = (vs * ((h * 256 / 60) % 256)) / 256 + + switch (Math.floor(h / 60)) { + case 0: + r = v + g = v - vs + vsf + b = v - vs + break + case 1: + r = v - vsf + g = v + b = v - vs + break + case 2: + r = v - vs + g = v + b = v - vs + vsf + break + case 3: + r = v - vs + g = v - vsf + b = v + break + case 4: + r = v - vs + vsf + g = v - vs + b = v + break + case 5: + r = v + g = v - vs + b = v - vsf + break + } + + /* parse values */ + return { + r: Math.floor(r + 0.5) + , g: Math.floor(g + 0.5) + , b: Math.floor(b + 0.5) + } + } + // Private: ensure to six-based hex +, _fullHex: function(hex) { + return hex.length == 4 ? + [ '#', + hex.substring(1, 2), hex.substring(1, 2) + , hex.substring(2, 3), hex.substring(2, 3) + , hex.substring(3, 4), hex.substring(3, 4) + ].join('') : hex + } + // Private: component to hex value +, _compToHex: function(comp) { + var hex = comp.toString(16) + return hex.length == 1 ? '0' + hex : hex + } + +}) + +// 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) + || SVG.regex.isHsb.test(color) +} + +// Test if given value is a rgb object +SVG.Color.isRgb = function(color) { + return typeof color.r == 'number' +} + +// Test if given value is a hsb object +SVG.Color.isHsb = function(color) { + return typeof color.h == 'number' +}
\ No newline at end of file diff --git a/src/element.js b/src/element.js index 63f8c31..e11f650 100644 --- a/src/element.js +++ b/src/element.js @@ -160,6 +160,10 @@ SVG.extend(SVG.Element, { if (a == 'stroke-width') this.attr('stroke', parseFloat(v) > 0 ? this.attrs.stroke : null) + /* ensure hex color */ + if (SVG.Color.test(v) || SVG.Color.isRgb(v) || SVG.Color.isHsb(v)) + v = new SVG.Color(v).toHex() + /* set give attribute on node */ n != null ? this.node.setAttributeNS(n, a, v) : @@ -14,14 +14,14 @@ SVG.extend(SVG.FX, { var akeys, tkeys, tvalues , element = this.target , fx = this - , start = (new Date).getTime() + , start = new Date().getTime() , finish = start + duration /* start animation */ this.interval = setInterval(function(){ // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby. var index - , time = (new Date).getTime() + , time = new Date().getTime() , pos = time > finish ? 1 : (time - start) / duration /* collect attribute keys */ @@ -180,7 +180,7 @@ SVG.extend(SVG.FX, { this._unit(o, pos) : /* color recalculation */ - o.to && (o.to.r || /^#/.test(o.to)) ? + o.to && (o.to.r || SVG.Color.test(o.to)) ? this._color(o, pos) : /* for all other values wait until pos has reached 1 to return the final value */ @@ -206,48 +206,18 @@ SVG.extend(SVG.FX, { /* normalise pos */ pos = pos < 0 ? 0 : pos > 1 ? 1 : pos - /* convert FROM hex to rgb */ - from = this._h2r(o.from || '#000') + /* convert FROM */ + from = new SVG.Color(o.from) /* convert TO hex to rgb */ - to = this._h2r(o.to) + to = new SVG.Color(o.to) /* tween color and return hex */ - return this._r2h({ + return new SVG.Color({ r: ~~(from.r + (to.r - from.r) * pos) , g: ~~(from.g + (to.g - from.g) * pos) , b: ~~(from.b + (to.b - from.b) * pos) - }) - } - // Private: convert hex to rgb object -, _h2r: function(hex) { - /* parse full hex */ - var match = SVG.regex.hex.exec(this._fh(hex)) - - /* if the hex is successfully parsed, return it in rgb, otherwise return black */ - return match ? { - r: parseInt(match[1], 16) - , g: parseInt(match[2], 16) - , b: parseInt(match[3], 16) - } : { r: 0, g: 0, b: 0 } - } - // Private: convert rgb object to hex string -, _r2h: function(rgb) { - return '#' + this._c2h(rgb.r) + this._c2h(rgb.g) + this._c2h(rgb.b) - } - // Private: convert component to hex -, _c2h: function(c) { - var hex = c.toString(16) - return hex.length == 1 ? '0' + hex : hex - } - // Private: force potential 3-based hex to 6-based -, _fh: function(hex) { - return hex.length == 4 ? - [ '#', - hex.substring(1, 2), hex.substring(1, 2) - , hex.substring(2, 3), hex.substring(2, 3) - , hex.substring(3, 4), hex.substring(3, 4) - ].join('') : hex + }).toHex() } }) diff --git a/src/regex.js b/src/regex.js index 7ecb557..e89dc85 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,7 +1,18 @@ // Storage for regular expressions SVG.regex = { - unit: /^([\d\.]+)([a-z%]{0,2})$/ + unit: /^([\d\.]+)([a-z%]{0,2})$/ + +, hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i + +, rgb: /rgb\((\d+),(\d+),(\d+),([\d\.]+)\)/ + +, hsb: /hsb\((\d+),(\d+),(\d+),([\d\.]+)\)/ + +, isHex: /^#/i + +, isRgb: /^rgb\(/ + +, isHsb: /^hsb\(/ -, hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i }
\ No newline at end of file diff --git a/src/sugar.js b/src/sugar.js index 42883e5..f8a5660 100644 --- a/src/sugar.js +++ b/src/sugar.js @@ -15,7 +15,7 @@ var _colorPrefix = function(type, attr) { SVG.Shape.prototype[method] = function(o) { var indexOf - if (typeof o == 'string') + if (typeof o == 'string' || SVG.Color.isRgb(o) || SVG.Color.isHsb(o)) this.attr(method, o) else |