/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of "Scrivo" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: color.js 750 2013-07-23 01:48:11Z geert $
*/
"use strict";
/**
* @summary
* The SUI.color namespace contains a set of utility functions for working
* with color codes.
*
* @description
* Colors can be defined in different was. Popular methods use HSV
* or RGB color values. The latter can be represented in different ways in
* CSS: '#0010FF', '#01F' or 'rgb(0,16,255)'. In this namespace you'll find a
* set of functions for conversions between HTML/CSS color codes, RGB and HSV
* color values.
*
* @namespace
*/
SUI.color = {
/**
* Convert an HTML or CSS color code to a standard HTML color code
* (standardize color code).
* @param {String} c A HTML or CSS color code, the following formats
* are allowed: #FFF, #FFFFFF, rgb(255,255,255).
* @return {String} An HTML color code (#FFFFFF).
*/
colToCol: function(c) {
return SUI.color.rgbToCol(SUI.color.colToRgb(c));
},
/**
* Convert an HTML or CSS color code to an HSV color definition.
* @param {String} c A HTML or CSS color code to convert to an HSV color
* object, the following formats are allowed: #FFF, #FFFFFF and
* rgb(255,255,255).
* @return {Object} An HSV color object with the following members:
* h (hue: 0-360), s: (saturation: 0-1), v: (value: 0-1)
*/
colToHsv: function(c) {
return SUI.color.rgbToHsv(SUI.color.colToRgb(c));
},
/**
* Convert an HTML or CSS color code to RGB color fractions.
* @param {String} c A HTML or CSS color code to convert to a RGB color
* object, the following formats are allowed: #FFF, #FFFFFF and
* rgb(255,255,255).
* @return {Object} An RGB color object with the following members:
* r (red: 0-1), g (green: 0-1) and b (blue: 0-1).
*/
colToRgb: function(c) {
// assume base 16 (hexadecimal 0x00-0xFF)
var b = 16;
// see if c matches #F70 ...
var x = /^#(\w{1})(\w{1})(\w{1})$/.exec(c);
if (x) {
// ... yes: change F to FF ...
for (var i=1; i<=3; i++) {
x[i] = x[i]+""+x[i];
}
} else {
// ... no, see if c matches #FF7700 ...
var x = /^#(\w{2})(\w{2})(\w{2})$/.exec(c);
if (!x) {
// ... no, go for base 10 ...
b = 10;
// ... and see is c matches rrb(255, 127, 0) ...
x = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(c);
if (!x) {
// ... no: hopeless, return black
return {r: 0, g: 0, b: 0};
}
}
}
// parse and return the RGB values using the correct base
return {r: parseInt(x[1],b)/255, g: parseInt(x[2],b)/255,
b: parseInt(x[3],b)/255};
},
/**
* Convert a HSV color definition to an HTML color code.
* @param {Object} c An HSV color object with the following members:
* h (hue: 0-360), s: (saturation: 0-1), v: (value: 0-1) to convert to
* an HTML color code.
* @return {String} An HTML color code (#FFFFFF)
*/
hsvToCol: function(c) {
return SUI.color.rgbToCol(SUI.color.hsvToRgb(c));
},
/**
* Convert a HSV color definition RGB color fractions.
* @param {Object} c An HSV color object with the following members:
* h (hue: 0-360), s: (saturation: 0-1), v: (value: 0-1) to convert to
* an HSV color object.
* @return {Object} An object with the following members: r, g and b,
* each within a range of 0 to 1.
*/
hsvToRgb: function(c) {
// if the saturation is zero ...
if (c.s == 0) {
// ... return gray based on the color's value
return {r: c.v, g: c.v, b: c.v};
}
// find the sector (0-5)
c.h /= 60;
var sect = Math.floor(c.h);
// get the fraction of the hue in the sector
var f = c.h - sect;
// c.v _ q t _ t _ _ q t _ _ q
// p \ _ _ / / \ _ _ _ _ / \
// sect R 0 1 2 3 4 5 G 0 1 2 3 4 5 B 0 1 2 3 4 5
// value for the sector between high and low color sections
var q = c.v * (1 - c.s * f);
// values for the 2 sectors with the low color values
var p = c.v * (1 - c.s);
// value for the sector between low and high color sections
var t = c.v * (1 - c.s * (1 - f) );
// map the results to the right RGB components and return
switch (sect) {
case 1:
return {r: q, g: c.v, b: p};
case 2:
return {r: p, g: c.v, b: t};
case 3:
return {r: p, g: q, b: c.v};
case 4:
return {r: t, g: p, b: c.v};
case 5:
return {r: c.v, g: p, b: q};
default:
return {r: c.v, g: t, b: p};
}
},
/**
* Convert a RGB color fractions to an HTML color code.
* @param {Object} c An RGB color object with the following members:
* r (red: 0-1), g (green: 0-1) and b (blue: 0-1) to convert to an
* HTML color code.
* @return {String} An HTML color code (#FFFFFF).
*/
rgbToCol: function(c) {
// build a hexadecimal color value and 0x1000000 to it ...
var x = 0x1000000 + (c.r*255|0)*65536 + (c.g*255|0)*256 + (c.b*255|0);
// ... convert it to string, chop of the leading 1 and return it
return "#" + x.toString(16).substr(1);
},
/**
* Convert a RGB color fractions to an HTML color code.
* @param {Object} c An RGB color object with the following members:
* r (red: 0-1), g (green: 0-1) and b (blue: 0-1) to convert to an
* HSV color object.
* @return {Object} An HSV color object with the following members:
* h (hue: 0-360), s: (saturation: 0-1), v: (value: 0-1)
*/
rgbToHsv: function(c) {
// get the minimum value of the RGB components
var min = (c.r<c.g ? c.r : c.g)<c.b ? (c.r<c.g ? c.r : c.g) : c.b;
// get the maximum value of the RGB components
var max = (c.r>c.g ? c.r : c.g)>c.b ? (c.r>c.g ? c.r : c.g) : c.b;
// start with black
var r = {h: 0, s: 0, v: 0};
var chroma = max - min;
// the value is the max component
r.v = max;
if (!chroma || r.v == 0) {
// if there is no chroma (and guard against division by zero)
r.h = 360;
return r;
} else {
// the saturation is the chroma as fraction of the value
r.s = chroma/r.v;
}
// get the hue as a sector + fraction
if(c.r == max) {
r.h = (c.g - c.b) / chroma;
} else if(c.g == max) {
r.h = 2 + (c.b - c.r) / chroma;
} else {
r.h = 4 + (c.r - c.g) / chroma;
}
// convert the hue from sector to degrees
r.h *= 60;
if(r.h < 0) {
r.h += 360;
}
// return the result
return r;
}
};