1 (function() { 2 3 var fabric = this.fabric || (this.fabric = { }); 4 5 if (fabric.Color) { 6 fabric.warn('fabric.Color is already defined.'); 7 return; 8 } 9 10 /** 11 * The purpose of fabric.Color is to abstract and encapsulate common color operations; 12 * fabric.Color is a constructor and creates instances of fabric.Color objects. 13 * 14 * @class Color 15 * @memberOf fabric 16 * @param {String} color (optional) in hex or rgb(a) format 17 */ 18 function Color(color) { 19 if (!color) { 20 this.setSource([0, 0, 0, 1]); 21 } 22 else { 23 this._tryParsingColor(color); 24 } 25 } 26 27 fabric.Color = Color; 28 29 fabric.Color.prototype = /** @scope fabric.Color.prototype */ { 30 31 /** 32 * @private 33 * @method _tryParsingColor 34 */ 35 _tryParsingColor: function(color) { 36 var source = Color.sourceFromHex(color); 37 if (!source) { 38 source = Color.sourceFromRgb(color); 39 } 40 if (source) { 41 this.setSource(source); 42 } 43 }, 44 45 /** 46 * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1]) 47 * @method getSource 48 * @return {Array} 49 */ 50 getSource: function() { 51 return this._source; 52 }, 53 54 /** 55 * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1]) 56 * @method setSource 57 * @param {Array} source 58 */ 59 setSource: function(source) { 60 this._source = source; 61 }, 62 63 /** 64 * Returns color represenation in RGB format 65 * @method toRgb 66 * @return {String} ex: rgb(0-255,0-255,0-255) 67 */ 68 toRgb: function() { 69 var source = this.getSource(); 70 return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; 71 }, 72 73 /** 74 * Returns color represenation in RGBA format 75 * @method toRgba 76 * @return {String} ex: rgba(0-255,0-255,0-255,0-1) 77 */ 78 toRgba: function() { 79 var source = this.getSource(); 80 return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; 81 }, 82 83 /** 84 * Returns color represenation in HEX format 85 * @method toHex 86 * @return {String} ex: FF5555 87 */ 88 toHex: function() { 89 var source = this.getSource(); 90 91 var r = source[0].toString(16); 92 r = (r.length == 1) ? ('0' + r) : r; 93 94 var g = source[1].toString(16); 95 g = (g.length == 1) ? ('0' + g) : g; 96 97 var b = source[2].toString(16); 98 b = (b.length == 1) ? ('0' + b) : b; 99 100 return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); 101 }, 102 103 /** 104 * Gets value of alpha channel for this color 105 * @method getAlpha 106 * @return {Number} 0-1 107 */ 108 getAlpha: function() { 109 return this.getSource()[3]; 110 }, 111 112 /** 113 * Sets value of alpha channel for this color 114 * @method setAlpha 115 * @param {Number} 0-1 116 * @return {fabric.Color} thisArg 117 */ 118 setAlpha: function(alpha) { 119 var source = this.getSource(); 120 source[3] = alpha; 121 this.setSource(source); 122 return this; 123 }, 124 125 /** 126 * Transforms color to its grayscale representation 127 * @method toGrayscale 128 * @return {fabric.Color} thisArg 129 */ 130 toGrayscale: function() { 131 var source = this.getSource(), 132 average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), 133 currentAlpha = source[3]; 134 this.setSource([average, average, average, currentAlpha]); 135 return this; 136 }, 137 138 /** 139 * Transforms color to its black and white representation 140 * @method toGrayscale 141 * @return {fabric.Color} thisArg 142 */ 143 toBlackWhite: function(threshold) { 144 var source = this.getSource(), 145 average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 146 currentAlpha = source[3], 147 threshold = threshold || 127; 148 149 average = (Number(average) < Number(threshold)) ? 0 : 255; 150 this.setSource([average, average, average, currentAlpha]); 151 return this; 152 }, 153 154 /** 155 * Overlays color with another color 156 * @method overlayWith 157 * @param {String|fabric.Color} otherColor 158 * @return {fabric.Color} thisArg 159 */ 160 overlayWith: function(otherColor) { 161 if (!(otherColor instanceof Color)) { 162 otherColor = new Color(otherColor); 163 } 164 165 var result = [], 166 alpha = this.getAlpha(), 167 otherAlpha = 0.5, 168 source = this.getSource(), 169 otherSource = otherColor.getSource(); 170 171 for (var i = 0; i < 3; i++) { 172 result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); 173 } 174 175 result[4] = alpha; 176 this.setSource(result); 177 return this; 178 } 179 }; 180 181 /** 182 * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgb(255, 100, 10, 0.5), rgb(1,1,1)) 183 * @static 184 * @field 185 */ 186 fabric.Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/; 187 188 /** 189 * Regex matching color in HEX format (ex: #FF5555, 010155, aff) 190 * @static 191 * @field 192 */ 193 fabric.Color.reHex = /^#?([0-9a-f]{6}|[0-9a-f]{3})$/i; 194 195 /** 196 * Returns new color object, when given a color in RGB format 197 * @method fromRgb 198 * @param {String} color ex: rgb(0-255,0-255,0-255) 199 * @return {fabric.Color} 200 */ 201 fabric.Color.fromRgb = function(color) { 202 return Color.fromSource(Color.sourceFromRgb(color)); 203 }; 204 205 /** 206 * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format 207 * @method sourceFromRgb 208 * @param {String} color ex: rgb(0-255,0-255,0-255) 209 * @return {Array} source 210 */ 211 fabric.Color.sourceFromRgb = function(color) { 212 var match = color.match(Color.reRGBa); 213 if (match) { 214 return [ 215 parseInt(match[1], 10), 216 parseInt(match[2], 10), 217 parseInt(match[3], 10), 218 match[4] ? parseFloat(match[4]) : 1 219 ]; 220 } 221 }; 222 223 /** 224 * Returns new color object, when given a color in RGBA format 225 * @static 226 * @function 227 * @method fromRgba 228 * @param {String} color 229 * @return {fabric.Color} 230 */ 231 fabric.Color.fromRgba = Color.fromRgb; 232 233 /** 234 * Returns new color object, when given a color in HEX format 235 * @static 236 * @method fromHex 237 * @return {fabric.Color} 238 */ 239 fabric.Color.fromHex = function(color) { 240 return Color.fromSource(Color.sourceFromHex(color)); 241 }; 242 243 /** 244 * Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HEX format 245 * @static 246 * @method sourceFromHex 247 * @param {String} color ex: FF5555 248 * @return {Array} source 249 */ 250 fabric.Color.sourceFromHex = function(color) { 251 if (color.match(Color.reHex)) { 252 var value = color.slice(color.indexOf('#') + 1), 253 isShortNotation = (value.length === 3), 254 r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2), 255 g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4), 256 b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6); 257 258 return [ 259 parseInt(r, 16), 260 parseInt(g, 16), 261 parseInt(b, 16), 262 1 263 ]; 264 } 265 }; 266 267 /** 268 * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5]) 269 * @static 270 * @method fromSource 271 * @return {fabric.Color} 272 */ 273 fabric.Color.fromSource = function(source) { 274 var oColor = new Color(); 275 oColor.setSource(source); 276 return oColor; 277 }; 278 })();