      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 })();