1 /**
  2  * @author Dennis Verhoeven
  3  * @package Banana.Util
  4  * @summary Color helper
  5  */
  6 
  7 /** @namespace Banana.Util.Color */
  8 goog.provide('Banana.Util.Color');
  9 
 10 
 11 /** 
 12  * Helper class for working with colors.
 13  * Easy shift from rgb to hsv and modify parameters.
 14  * 
 15  * two ways to create a color class instance
 16  * 
 17    var c1 = new Banana.Util.Color("#444444");
 18    
 19    var c2 = new Banana.Util.Color(255,255,56);
 20    
 21  * 
 22  * @param {mixed} p1 hex representation or int red part 
 23  * @param {int} p2 
 24  * @param {int} p3  
 25  * 
 26  * @constructor 
 27  * 
 28  */
 29 Banana.Util.Color = function(p1, p2, p3)
 30 {
 31 	var		r;		// Red, Green and Blue represent color in RGB space
 32 	var		g;		// Values are integers in range of 0..255
 33 	var		b;
 34 
 35 	var		h;		// Hue, Saturation and Value represent color in HSV space
 36 	var		s;		// Values are floats in range of 0..1
 37 	var		v;
 38 
 39 	/**
 40 	 * 
 41 	 * @constructs
 42 	 * @ignore
 43 	 */
 44 	var _init = function(obj)
 45 	{
 46 		if (typeof(p1)=='string')
 47 		{
 48 			obj.setValue(p1);
 49 		}
 50 		else if (typeof(p1)=='number')
 51 		{
 52 			obj.r=p1;
 53 			obj.g=p2;
 54 			obj.b=p3;
 55 			obj.computeHSV();
 56 		}
 57 		else
 58 		{
 59 			obj.r=0;
 60 			obj.g=0;
 61 			obj.b=0;
 62 			obj.computeHSV();
 63 		}
 64 	}	
 65 	
 66 	/**
 67 	 * red part
 68 	 * @return {int}
 69 	 */
 70 	this.getR = function()
 71 	{
 72 		return this.r;
 73 	}
 74 
 75 	/**
 76 	 * red part
 77 	 * @param {int} value
 78 	 */
 79 	this.setR = function(value)
 80 	{
 81 		this.r=value;
 82 		this.computeHSV();
 83 	}
 84 	
 85 	/**
 86 	 * green part
 87 	 * @return {int}
 88 	 */
 89 	this.getG = function ()
 90 	{
 91 		return this.g;
 92 	}
 93 
 94 	/**
 95 	 * green part
 96 	 * @param {int} value
 97 	 */
 98 	this.setG = function(value)
 99 	{
100 		this.g=value;
101 		this.computeHSV();
102 	}
103 
104 	/**
105 	 * blue part
106 	 * @return {int}
107 	 */
108 	this.getB = function()
109 	{
110 		return this.b;
111 	}
112 	
113 	/**
114 	 * blue part
115 	 * @param {int} value
116 	 */
117 	this.setB = function(value)
118 	{
119 		this.b=value;
120 		this.computeHSV();
121 	}
122 
123 	/**
124 	 * hue part
125 	 * @return {int}
126 	 */
127 	this.getH = function ()
128 	{
129 		return this.h;
130 	}
131 
132 	/**
133 	 * hue part
134 	 * @param {int} value
135 	 */
136 	this.setH = function(value)
137 	{
138 		this.h=value;
139 		this.computeRGB();
140 	}
141 
142 	/**
143 	 * saturation part
144 	 * @return {int}
145 	 */
146 	this.getS = function()
147 	{
148 		return this.s;
149 	}
150 
151 	/**
152 	 * saturation part
153 	 * @param {int} value
154 	 */
155 	this.setS = function(value)
156 	{
157 		this.s=value;
158 		this.computeRGB();
159 	}
160 
161 	/**
162 	 * value part
163 	 * @return {int}
164 	 */
165 	this.getV = function()
166 	{
167 		return this.v;
168 	}
169 
170 	/**
171 	 * value part
172 	 * @param {int} value
173 	 */
174 	this.setV = function(value)
175 	{
176 		this.v=value;
177 		this.computeRGB();
178 	}
179 	
180 	/**
181 	 * @ignore
182 	 * @param {int} value
183 	 * @returns {int}
184 	 */
185 	var dec2hex = function(value)
186 	{
187 		return (value<16 ? '0' : '') + value.toString(16);
188 	}
189 	
190 	/**
191 	 * @ignore
192 	 * @param {int} value
193 	 * @returns {int}
194 	 */
195 	var hex2dec = function(value)
196 	{
197 		return parseInt(value, 16);
198 	}
199 
200 	/**
201 	 * changes the current colorspace value
202 	 * @param {mixed} either #xxxxxx or xxx,xxx,xxx format
203 	 */
204 	this.setValue = function(value)
205 	{
206 		if (value.substr(0, 1)==='#')
207 		{
208 			this.r=hex2dec(value.substr(1, 2));
209 			this.g=hex2dec(value.substr(3, 2));
210 			this.b=hex2dec(value.substr(5, 2));
211 		}
212 		else
213 		{
214 		 	var digits = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(value);
215 		 	this.r=parseInt(digits[1]);
216     	this.g=parseInt(digits[2]);
217     	this.b=parseInt(digits[3]);
218 		}
219 
220 		this.computeHSV();
221 	}
222 	
223 	/**
224 	 * @return {String} in #xxxxxx format
225 	 */
226 	this.getValue = function()
227 	{
228 		return '#'+dec2hex(this.r)+dec2hex(this.g)+dec2hex(this.b);
229 	}
230 
231 	/**
232 	 * Computes the hsv values according the current r,g,b values
233 	 */
234 	this.computeHSV = function()
235 	{
236 		var	r = this.r / 255;
237 		var g = this.g / 255;
238 		var b = this.b / 255;
239 
240 		var min = Math.min(r, g, b);
241 		var max = Math.max(r, g, b);
242 		var delta = max - min;
243 
244 		var h = 0;
245 		var s = 0;
246 		var v = max;
247 
248 		if (max != 0)
249 		{
250 			s = delta / max;
251 		} 
252 		else 
253 		{
254 			s = 0;
255 			h = -1;
256 			
257 			this.h=h;
258 			this.s=s;
259 			this.v=v;
260 			
261 			return;
262 		}
263 
264 		if (delta)
265 		{
266 			if (r == max) 
267 			{
268 				h = (g - b) / delta;
269 			} 
270 			else if (g == max) 
271 			{
272 				h = 2 + (b - r) / delta;
273 			} 
274 			else 
275 			{
276 				h = 4 + (r - g) / delta;
277 			}
278 		} 
279 		else
280 		{
281 			h = 0;
282 		}
283 
284 		h *= 60;
285 
286 		if (h < 0) 
287 		{
288 			h += 360;
289 		}
290 
291 		this.h=h;
292 		this.s=s;
293 		this.v=v;
294 	}
295 
296 	/**
297 	 * Computes rgb values according the current h,s,v values
298 	 */
299 	this.computeRGB = function()
300 	{
301 		var h = this.h;
302 		var s = this.s;
303 		var v = this.v;
304 
305 		var i = 0;
306 		var f = 0;
307 		var p = 0;
308 		var q = 0;
309 		var t = 0;
310 		var b = 0;
311 		var g = 0;
312 
313 		if (s == 0)
314 		{
315 			r = g = b = v;
316 			
317 			this.r=Math.round(r * 255);
318 			this.g=Math.round(g * 255);
319 			this.b=Math.round(b * 255);
320 			
321 			return;
322 		}
323 
324 		h %= 360;
325 		h /= 60;
326 		i = Math.floor(h);
327 		f = h - i;
328 		p = v * (1 - s);
329 		q = v * (1 - s * f);
330 		t = v * (1 - s * (1 - f));
331 
332 		switch(i)
333 		{
334 			case 0:  r = v;  g = t;  b = p; break;
335 			case 1:  r = q;  g = v;  b = p; break;
336 			case 2:  r = p;  g = v;  b = t; break;
337 			case 3:  r = p;  g = q;  b = v; break;
338 			case 4:  r = t;  g = p;  b = v; break;
339 			default: r = v;  g = p;  b = q; break;
340 		}
341 
342 		this.r=Math.round(r * 255);
343 		this.g=Math.round(g * 255);
344 		this.b=Math.round(b * 255);
345 	}
346 		
347 	_init(this);
348 }