| /* |
| Copyright (c) 2004-2005, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| dojo.provide("dojo.graphics.color"); |
| dojo.require("dojo.lang"); |
| dojo.require("dojo.string"); |
| dojo.require("dojo.math"); |
| |
| // TODO: rewrite the "x2y" methods to take advantage of the parsing |
| // abilities of the Color object. Also, beef up the Color |
| // object (as possible) to parse most common formats |
| |
| // takes an r, g, b, a(lpha) value, [r, g, b, a] array, "rgb(...)" string, hex string (#aaa, #aaaaaa, aaaaaaa) |
| dojo.graphics.color.Color = function(r, g, b, a) { |
| // dojo.debug("r:", r[0], "g:", r[1], "b:", r[2]); |
| if(dojo.lang.isArray(r)) { |
| this.r = r[0]; |
| this.g = r[1]; |
| this.b = r[2]; |
| this.a = r[3]||1.0; |
| } else if(dojo.lang.isString(r)) { |
| var rgb = dojo.graphics.color.extractRGB(r); |
| this.r = rgb[0]; |
| this.g = rgb[1]; |
| this.b = rgb[2]; |
| this.a = g||1.0; |
| } else if(r instanceof dojo.graphics.color.Color) { |
| this.r = r.r; |
| this.b = r.b; |
| this.g = r.g; |
| this.a = r.a; |
| } else { |
| this.r = r; |
| this.g = g; |
| this.b = b; |
| this.a = a; |
| } |
| } |
| |
| dojo.lang.extend(dojo.graphics.color.Color, { |
| toRgb: function(includeAlpha) { |
| if(includeAlpha) { |
| return this.toRgba(); |
| } else { |
| return [this.r, this.g, this.b]; |
| } |
| }, |
| |
| toRgba: function() { |
| return [this.r, this.g, this.b, this.a]; |
| }, |
| |
| toHex: function() { |
| return dojo.graphics.color.rgb2hex(this.toRgb()); |
| }, |
| |
| toCss: function() { |
| return "rgb(" + this.toRgb().join() + ")"; |
| }, |
| |
| toString: function() { |
| return this.toHex(); // decent default? |
| }, |
| |
| toHsv: function() { |
| return dojo.graphics.color.rgb2hsv(this.toRgb()); |
| }, |
| |
| toHsl: function() { |
| return dojo.graphics.color.rgb2hsl(this.toRgb()); |
| }, |
| |
| blend: function(color, weight) { |
| return dojo.graphics.color.blend(this.toRgb(), new Color(color).toRgb(), weight); |
| } |
| }); |
| |
| dojo.graphics.color.named = { |
| white: [255,255,255], |
| black: [0,0,0], |
| red: [255,0,0], |
| green: [0,255,0], |
| blue: [0,0,255], |
| navy: [0,0,128], |
| gray: [128,128,128], |
| silver: [192,192,192] |
| }; |
| |
| // blend colors a and b (both as RGB array or hex strings) with weight from -1 to +1, 0 being a 50/50 blend |
| dojo.graphics.color.blend = function(a, b, weight) { |
| if(typeof a == "string") { return dojo.graphics.color.blendHex(a, b, weight); } |
| if(!weight) { weight = 0; } |
| else if(weight > 1) { weight = 1; } |
| else if(weight < -1) { weight = -1; } |
| var c = new Array(3); |
| for(var i = 0; i < 3; i++) { |
| var half = Math.abs(a[i] - b[i])/2; |
| c[i] = Math.floor(Math.min(a[i], b[i]) + half + (half * weight)); |
| } |
| return c; |
| } |
| |
| // very convenient blend that takes and returns hex values |
| // (will get called automatically by blend when blend gets strings) |
| dojo.graphics.color.blendHex = function(a, b, weight) { |
| return dojo.graphics.color.rgb2hex(dojo.graphics.color.blend(dojo.graphics.color.hex2rgb(a), dojo.graphics.color.hex2rgb(b), weight)); |
| } |
| |
| // get RGB array from css-style color declarations |
| dojo.graphics.color.extractRGB = function(color) { |
| var hex = "0123456789abcdef"; |
| color = color.toLowerCase(); |
| if( color.indexOf("rgb") == 0 ) { |
| var matches = color.match(/rgba*\((\d+), *(\d+), *(\d+)/i); |
| var ret = matches.splice(1, 3); |
| return ret; |
| } else { |
| var colors = dojo.graphics.color.hex2rgb(color); |
| if(colors) { |
| return colors; |
| } else { |
| // named color (how many do we support?) |
| return dojo.graphics.color.named[color] || [255, 255, 255]; |
| } |
| } |
| } |
| |
| dojo.graphics.color.hex2rgb = function(hex) { |
| var hexNum = "0123456789ABCDEF"; |
| var rgb = new Array(3); |
| if( hex.indexOf("#") == 0 ) { hex = hex.substring(1); } |
| hex = hex.toUpperCase(); |
| if(hex.replace(new RegExp("["+hexNum+"]", "g"), "") != "") { |
| return null; |
| } |
| if( hex.length == 3 ) { |
| rgb[0] = hex.charAt(0) + hex.charAt(0) |
| rgb[1] = hex.charAt(1) + hex.charAt(1) |
| rgb[2] = hex.charAt(2) + hex.charAt(2); |
| } else { |
| rgb[0] = hex.substring(0, 2); |
| rgb[1] = hex.substring(2, 4); |
| rgb[2] = hex.substring(4); |
| } |
| for(var i = 0; i < rgb.length; i++) { |
| rgb[i] = hexNum.indexOf(rgb[i].charAt(0)) * 16 + hexNum.indexOf(rgb[i].charAt(1)); |
| } |
| return rgb; |
| } |
| |
| dojo.graphics.color.rgb2hex = function(r, g, b) { |
| if(dojo.lang.isArray(r)) { |
| g = r[1] || 0; |
| b = r[2] || 0; |
| r = r[0] || 0; |
| } |
| return ["#", |
| dojo.string.pad(r.toString(16), 2), |
| dojo.string.pad(g.toString(16), 2), |
| dojo.string.pad(b.toString(16), 2)].join(""); |
| } |
| |
| dojo.graphics.color.rgb2hsv = function(r, g, b){ |
| |
| if (dojo.lang.isArray(r)) { |
| b = r[2] || 0; |
| g = r[1] || 0; |
| r = r[0] || 0; |
| } |
| |
| // r,g,b, each 0 to 255, to HSV. |
| // h = 0.0 to 360.0 (corresponding to 0..360.0 degrees around hexcone) |
| // s = 0.0 (shade of gray) to 1.0 (pure color) |
| // v = 0.0 (black) to 1.0 {white) |
| // |
| // Based on C Code in "Computer Graphics -- Principles and Practice," |
| // Foley et al, 1996, p. 592. |
| // |
| // our calculatuions are based on 'regular' values (0-360, 0-1, 0-1) |
| // but we return bytes values (0-255, 0-255, 0-255) |
| |
| var h = null; |
| var s = null; |
| var v = null; |
| |
| var min = Math.min(r, g, b); |
| v = Math.max(r, g, b); |
| |
| var delta = v - min; |
| |
| // calculate saturation (0 if r, g and b are all 0) |
| |
| s = (v == 0) ? 0 : delta/v; |
| |
| if (s == 0){ |
| // achromatic: when saturation is, hue is undefined |
| h = 0; |
| }else{ |
| // chromatic |
| if (r == v){ |
| // between yellow and magenta |
| h = 60 * (g - b) / delta; |
| }else{ |
| if (g == v){ |
| // between cyan and yellow |
| h = 120 + 60 * (b - r) / delta; |
| }else{ |
| if (b == v){ |
| // between magenta and cyan |
| h = 240 + 60 * (r - g) / delta; |
| } |
| } |
| } |
| if (h < 0){ |
| h += 360; |
| } |
| } |
| |
| |
| h = (h == 0) ? 360 : Math.ceil((h / 360) * 255); |
| s = Math.ceil(s * 255); |
| |
| return [h, s, v]; |
| } |
| |
| dojo.graphics.color.hsv2rgb = function(h, s, v){ |
| |
| if (dojo.lang.isArray(h)) { |
| v = h[2] || 0; |
| s = h[1] || 0; |
| h = h[0] || 0; |
| } |
| |
| h = (h / 255) * 360; |
| if (h == 360){ h = 0;} |
| |
| s = s / 255; |
| v = v / 255; |
| |
| // Based on C Code in "Computer Graphics -- Principles and Practice," |
| // Foley et al, 1996, p. 593. |
| // |
| // H = 0.0 to 360.0 (corresponding to 0..360 degrees around hexcone) 0 for S = 0 |
| // S = 0.0 (shade of gray) to 1.0 (pure color) |
| // V = 0.0 (black) to 1.0 (white) |
| |
| var r = null; |
| var g = null; |
| var b = null; |
| |
| if (s == 0){ |
| // color is on black-and-white center line |
| // achromatic: shades of gray |
| r = v; |
| g = v; |
| b = v; |
| }else{ |
| // chromatic color |
| var hTemp = h / 60; // h is now IN [0,6] |
| var i = Math.floor(hTemp); // largest integer <= h |
| var f = hTemp - i; // fractional part of h |
| |
| var p = v * (1 - s); |
| var q = v * (1 - (s * f)); |
| var t = v * (1 - (s * (1 - f))); |
| |
| switch(i){ |
| case 0: r = v; g = t; b = p; break; |
| case 1: r = q; g = v; b = p; break; |
| case 2: r = p; g = v; b = t; break; |
| case 3: r = p; g = q; b = v; break; |
| case 4: r = t; g = p; b = v; break; |
| case 5: r = v; g = p; b = q; break; |
| } |
| } |
| |
| r = Math.ceil(r * 255); |
| g = Math.ceil(g * 255); |
| b = Math.ceil(b * 255); |
| |
| return [r, g, b]; |
| } |
| |
| dojo.graphics.color.rgb2hsl = function(r, g, b){ |
| |
| if (dojo.lang.isArray(r)) { |
| b = r[2] || 0; |
| g = r[1] || 0; |
| r = r[0] || 0; |
| } |
| |
| r /= 255; |
| g /= 255; |
| b /= 255; |
| |
| // |
| // based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/ |
| // |
| |
| var h = null; |
| var s = null; |
| var l = null; |
| |
| |
| var min = Math.min(r, g, b); |
| var max = Math.max(r, g, b); |
| var delta = max - min; |
| |
| l = (min + max) / 2; |
| |
| s = 0; |
| |
| if ((l > 0) && (l < 1)){ |
| s = delta / ((l < 0.5) ? (2 * l) : (2 - 2 * l)); |
| } |
| |
| h = 0; |
| |
| if (delta > 0) { |
| if ((max == r) && (max != g)){ |
| h += (g - b) / delta; |
| } |
| if ((max == g) && (max != b)){ |
| h += (2 + (b - r) / delta); |
| } |
| if ((max == b) && (max != r)){ |
| h += (4 + (r - g) / delta); |
| } |
| h *= 60; |
| } |
| |
| h = (h == 0) ? 360 : Math.ceil((h / 360) * 255); |
| s = Math.ceil(s * 255); |
| l = Math.ceil(l * 255); |
| |
| return [h, s, l]; |
| } |
| |
| dojo.graphics.color.hsl2rgb = function(h, s, l){ |
| |
| if (dojo.lang.isArray(h)) { |
| l = h[2] || 0; |
| s = h[1] || 0; |
| h = h[0] || 0; |
| } |
| |
| h = (h / 255) * 360; |
| if (h == 360){ h = 0;} |
| s = s / 255; |
| l = l / 255; |
| |
| // |
| // based on C code from http://astronomy.swin.edu.au/~pbourke/colour/hsl/ |
| // |
| |
| |
| while (h < 0){ h += 360; } |
| while (h > 360){ h -= 360; } |
| |
| if (h < 120){ |
| r = (120 - h) / 60; |
| g = h / 60; |
| b = 0; |
| }else if (h < 240){ |
| r = 0; |
| g = (240 - h) / 60; |
| b = (h - 120) / 60; |
| }else{ |
| r = (h - 240) / 60; |
| g = 0; |
| b = (360 - h) / 60; |
| } |
| |
| r = Math.min(r, 1); |
| g = Math.min(g, 1); |
| b = Math.min(b, 1); |
| |
| r = 2 * s * r + (1 - s); |
| g = 2 * s * g + (1 - s); |
| b = 2 * s * b + (1 - s); |
| |
| if (l < 0.5){ |
| r = l * r; |
| g = l * g; |
| b = l * b; |
| }else{ |
| r = (1 - l) * r + 2 * l - 1; |
| g = (1 - l) * g + 2 * l - 1; |
| b = (1 - l) * b + 2 * l - 1; |
| } |
| |
| r = Math.ceil(r * 255); |
| g = Math.ceil(g * 255); |
| b = Math.ceil(b * 255); |
| |
| return [r, g, b]; |
| } |
| |
| dojo.graphics.color.hsl2hex = function(h, s, l){ |
| var rgb = dojo.graphics.color.hsl2rgb(h, s, l); |
| return dojo.graphics.color.rgb2hex(rgb[0], rgb[1], rgb[2]); |
| } |
| |
| dojo.graphics.color.hex2hsl = function(hex){ |
| var rgb = dojo.graphics.color.hex2rgb(hex); |
| return dojo.graphics.color.rgb2hsl(rgb[0], rgb[1], rgb[2]); |
| } |