/*
* Copyright (c) 2014 Gwennael Buchet
*
* License/Terms of Use
*
* Permission is hereby granted, free of charge and for the term of intellectual property rights on the Software, to any
* person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify
* and propagate free of charge, anywhere in the world, all or part of the Software subject to the following mandatory conditions:
*
* • The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* Any failure to comply with the above shall automatically terminate the license and be construed as a breach of these
* Terms of Use causing significant harm to Gwennael Buchet.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Gwennael Buchet shall not be used in advertising or otherwise to promote
* the use or other dealings in this Software without prior written authorization from Gwennael Buchet.
*
* These Terms of Use are subject to French law.
*/
/**
* Some utils methods extending the Array prototype
*
* @class CGSGColor
* @module Util
* @static
* @author Gwennael Buchet (gwennael.buchet@gmail.com)
*/
var CGSGColor = {
/**
* Convert R, G and B value to an hexadecimal code
* @method rgb2hex
* @static
* @param {String} r red value. from 0 to 255.
* @param {String} g green value. from 0 to 255.
* @param {String} b blue value. from 0 to 255.
* @return {String} an hexadecimal value for the color, starting with a sharp (#)
*/
rgb2hex : function(r, g, b) {
return "#" + this._toHex(r) + this._toHex(g) + this._toHex(b);
},
/**
* Convert an hexadecimal code for color to R, G and B
* @method hex2rgb
* @static
* @param {String} hex an hexadecimal code, with or without the starting sharp (#)
* @return {Object} an object encapsulating r, g and b values (from 0 to 255)
*/
hex2rgb : function(hex) {
hex = this._withoutSharp(hex);
return {
r : parseInt(hex.substring(0, 2), 16),
g : parseInt(hex.substring(2, 4), 16),
b : parseInt(hex.substring(4, 6), 16)};
},
_withoutSharp : function(hex) {
return (hex.charAt(0) == "#") ? hex.substring(1, hex.length) : hex;
},
/**
* @method _toHex
* @param {String} n String or Number representation of a number between 0 and 255
* @return {String} Example "A6"
* @private
*/
_toHex : function(n) {
var m = parseInt(n, 10);
if (isNaN(m)) {
return "00";
}
m = Math.max(0, Math.min(m, 255));
return "0123456789ABCDEF".charAt((m - m % 16) / 16)
+ "0123456789ABCDEF".charAt(m % 16);
},
/**
* Convert a String to an {r,g, b} object.
* @method fromString
* @param rgb {String}
* @return {*}
* @example
* CGSGColor.fromString("rgb(121, 333, 444)"); returns {r:121, b:333, c:444};
*/
fromString : function(rgb) {
var p1 = rgb.indexOf('(') + 1;
var p2 = rgb.lastIndexOf(')');
var cl = rgb.substring(p1, p2);
var cls = cl.split(",");
return {
r : parseInt(cls[0]),
g : parseInt(cls[1]),
b : parseInt(cls[2])
}
},
/**
* Linear interpolation between 2 colors
* @method lerp
* @static
* @param {String} colorFrom a hex color
* @param {String} colorTo a hex color
* @param {Number} weight
* @return {String} a heh value for the interpolated color
*/
lerp : function(colorFrom, colorTo, weight) {
var rgbColorFrom = this.hex2rgb(colorFrom);
var rgbColorTo = this.hex2rgb(colorTo);
var rgb = [];
rgb[0] = rgbColorFrom.r + (rgbColorTo.r - rgbColorFrom.r) * weight;
rgb[1] = rgbColorFrom.g + (rgbColorTo.g - rgbColorFrom.g) * weight;
rgb[2] = rgbColorFrom.b + (rgbColorTo.b - rgbColorFrom.b) * weight;
return this.rgb2hex(rgb[0], rgb[1], rgb[2]);
},
/**
*
* @method darkenHex
* @param {String} hex Hexadecimal value of a color (with or without the started '#'
* @param {Number} factor If >0 : lighten. If <0 : darken
* @return {String}
*/
darkenHex : function(hex, factor) {
var rgb = this.hex2rgb(hex);
rgb.r = this.multiplyComponent(rgb.r, factor);
rgb.g = this.multiplyComponent(rgb.g, factor);
rgb.b = this.multiplyComponent(rgb.b, factor);
return this.rgb2hex(rgb.r, rgb.g, rgb.b);
},
/**
*
* @method darkenRGB
* @param {Number} r Red value between 0 and 255
* @param {Number} g Green value between 0 and 255
* @param {Number} b Blue value between 0 and 255
* @param {Number} factor If >0 : lighten. If <0 : darken
* @return {Object} An {r, g, b} object
*/
darkenRGB : function(r, g, b, factor) {
return {
r : this.multiplyComponent(r, factor),
g : this.multiplyComponent(g, factor),
b : this.multiplyComponent(b, factor)
};
},
litRGB : function(r, g, b, factor) {
var hsl = this.rgb2hsl(r, g, b);
hsl.l *= factor;
return this.hsl2rgb(hsl.h, hsl.s, hsl.l);
},
/**
* @method multiplyComponent
* @param {Number} c color component between 0 and 25(
* @param {Number} factor
* @return {Number} The multiplied value, between 0 and 255
*/
multiplyComponent : function(c, factor) {
return Math.max(Math.min(255, c * factor), 0);
},
/**
* RGB to HSV converter.
* Adapted from http://en.wikipedia.org/wiki/HSV_color_space
* @method rgb2hsv
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @return {Object} An {h, s, v} object
*/
rgb2hsv : function(r, g, b) {
var min, max;
//normalize the 3 components
r /= 255;
g /= 255;
b /= 255;
min = Math.min(b, Math.min(r, g));
max = Math.max(b, Math.max(r, g));
//min == max ? so the 3 values are the same, we got a gray color.
//just return the lightness
if (max == min) {
return {h : 0, s : 0, v : min};
}
var d = (r == min) ? g - b : ((b == min) ? r - g : b - r);
var h = (r == min) ? 3 : ((b == min) ? 1 : 5);
var dM = max - min;
return {
h : 60 * (h - d / dM),
s : dM / max,
v : max
};
},
/**
* RGB to HSL converter.
* Adapted from http://en.wikipedia.org/wiki/HSL_color_space
* @method rgb2hsl
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @return {Object}
*/
rgb2hsl : function(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0;
}
else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return {h : h, s : s, l : l};
},
/**
* HSL to RGB converter.
* Adapted from http://en.wikipedia.org/wiki/HSL_color_space
* @method hsl2rgb
* @param {Number} h The hue
* @param {Number} s The saturation
* @param {Number} l the lightness
* @return {Object} A {r, g, b} object
*/
hsl2rgb : function(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l;
}
else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = this.hue2rgb(p, q, h + 1 / 3);
g = this.hue2rgb(p, q, h);
b = this.hue2rgb(p, q, h - 1 / 3);
}
return {r : r * 255, g : g * 255, b : b * 255};
},
/**
* @method hue2rgb
* @param p
* @param q
* @param t
* @return {*}
*/
hue2rgb : function(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
},
/**
* HSV to RGB converter.
* Adapted from http://en.wikipedia.org/wiki/HSV_color_space
* @method hsv2rgb
* @param {Number} h The hue
* @param {Number} s The saturation
* @param {Number} v the value
* @return {Object} A {r, g, b} object
*/
hsv2rgb : function(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
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;
}
return {r : r * 255, g : g * 255, b : b * 255};
}
};