f819c797af0b9c32e220701a8d2a5df5546b7269
[roojs1] / Roo / lib / Color.js
1  
2
3 /**
4  * @class Roo.lib.Color
5  * @constructor
6  * An abstract Color implementation. Concrete Color implementations should use
7  * an instance of this function as their prototype, and implement the getRGB and
8  * getHSL functions. getRGB should return an object representing the RGB
9  * components of this Color, with the red, green, and blue components in the
10  * range [0,255] and the alpha component in the range [0,100]. getHSL should
11  * return an object representing the HSL components of this Color, with the hue
12  * component in the range [0,360), the saturation and lightness components in
13  * the range [0,100], and the alpha component in the range [0,1].
14  *
15  *
16  * Color.js
17  *
18  * Functions for Color handling and processing.
19  *
20  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
21  *
22  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
23  * rights to this program, with the intention of it becoming part of the public
24  * domain. Because this program is released into the public domain, it comes with
25  * no warranty either expressed or implied, to the extent permitted by law.
26  * 
27  * For more free and public domain JavaScript code by the same author, visit:
28  * http://www.safalra.com/web-design/javascript/
29  * 
30  */
31 Roo.lib.Color = function() { }
32
33
34 Roo.apply(Roo.lib.Color.prototype, {
35   
36   rgb : null,
37   hsv : null,
38   hsl : null,
39   
40   /**
41    * getIntegerRGB
42    * @return {Object} an object representing the RGBA components of this Color. The red,
43    * green, and blue components are converted to integers in the range [0,255].
44    * The alpha is a value in the range [0,1].
45    */
46   getIntegerRGB : function(){
47
48     // get the RGB components of this Color
49     var rgb = this.getRGB();
50
51     // return the integer components
52     return {
53       'r' : Math.round(rgb.r),
54       'g' : Math.round(rgb.g),
55       'b' : Math.round(rgb.b),
56       'a' : rgb.a
57     };
58
59   },
60
61   /**
62    * getPercentageRGB
63    * @return {Object} an object representing the RGBA components of this Color. The red,
64    * green, and blue components are converted to numbers in the range [0,100].
65    * The alpha is a value in the range [0,1].
66    */
67   getPercentageRGB : function(){
68
69     // get the RGB components of this Color
70     var rgb = this.getRGB();
71
72     // return the percentage components
73     return {
74       'r' : 100 * rgb.r / 255,
75       'g' : 100 * rgb.g / 255,
76       'b' : 100 * rgb.b / 255,
77       'a' : rgb.a
78     };
79
80   },
81
82   /**
83    * getCSSHexadecimalRGB
84    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
85    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
86    * are two-digit hexadecimal numbers.
87    */
88   getCSSHexadecimalRGB : function()
89   {
90
91     // get the integer RGB components
92     var rgb = this.getIntegerRGB();
93
94     // determine the hexadecimal equivalents
95     var r16 = rgb.r.toString(16);
96     var g16 = rgb.g.toString(16);
97     var b16 = rgb.b.toString(16);
98
99     // return the CSS RGB Color value
100     return '#'
101         + (r16.length == 2 ? r16 : '0' + r16)
102         + (g16.length == 2 ? g16 : '0' + g16)
103         + (b16.length == 2 ? b16 : '0' + b16);
104
105   },
106
107   /**
108    * getCSSIntegerRGB
109    * @return {String} a string representing this Color as a CSS integer RGB Color
110    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
111    * are integers in the range [0,255].
112    */
113   getCSSIntegerRGB : function(){
114
115     // get the integer RGB components
116     var rgb = this.getIntegerRGB();
117
118     // return the CSS RGB Color value
119     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
120
121   },
122
123   /**
124    * getCSSIntegerRGBA
125    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
126    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
127    * b are integers in the range [0,255] and a is in the range [0,1].
128    */
129   getCSSIntegerRGBA : function(){
130
131     // get the integer RGB components
132     var rgb = this.getIntegerRGB();
133
134     // return the CSS integer RGBA Color value
135     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
136
137   },
138
139   /**
140    * getCSSPercentageRGB
141    * @return {String} a string representing this Color as a CSS percentage RGB Color
142    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
143    * b are in the range [0,100].
144    */
145   getCSSPercentageRGB : function(){
146
147     // get the percentage RGB components
148     var rgb = this.getPercentageRGB();
149
150     // return the CSS RGB Color value
151     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
152
153   },
154
155   /**
156    * getCSSPercentageRGBA
157    * @return {String} a string representing this Color as a CSS percentage RGBA Color
158    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
159    * and b are in the range [0,100] and a is in the range [0,1].
160    */
161   getCSSPercentageRGBA : function(){
162
163     // get the percentage RGB components
164     var rgb = this.getPercentageRGB();
165
166     // return the CSS percentage RGBA Color value
167     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
168
169   },
170
171   /**
172    * getCSSHSL
173    * @return {String} a string representing this Color as a CSS HSL Color value - that
174    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
175    * s and l are in the range [0,100].
176    */
177   getCSSHSL : function(){
178
179     // get the HSL components
180     var hsl = this.getHSL();
181
182     // return the CSS HSL Color value
183     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
184
185   },
186
187   /**
188    * getCSSHSLA
189    * @return {String} a string representing this Color as a CSS HSLA Color value - that
190    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
191    * s and l are in the range [0,100], and a is in the range [0,1].
192    */
193   getCSSHSLA : function(){
194
195     // get the HSL components
196     var hsl = this.getHSL();
197
198     // return the CSS HSL Color value
199     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
200
201   },
202
203   /**
204    * Sets the Color of the specified node to this Color. This functions sets
205    * the CSS 'color' property for the node. The parameter is:
206    * 
207    * @param {DomElement} node - the node whose Color should be set
208    */
209   setNodeColor : function(node){
210
211     // set the Color of the node
212     node.style.color = this.getCSSHexadecimalRGB();
213
214   },
215
216   /**
217    * Sets the background Color of the specified node to this Color. This
218    * functions sets the CSS 'background-color' property for the node. The
219    * parameter is:
220    *
221    * @param {DomElement} node - the node whose background Color should be set
222    */
223   setNodeBackgroundColor : function(node){
224
225     // set the background Color of the node
226     node.style.backgroundColor = this.getCSSHexadecimalRGB();
227
228   },
229   // convert between formats..
230   toRGB: function()
231   {
232     var r = this.getIntegerRGB();
233     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
234     
235   },
236   toHSL : function()
237   {
238      var hsl = this.getHSL();
239   // return the CSS HSL Color value
240     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
241     
242   },
243   
244   toHSV : function()
245   {
246     var rgb = this.toRGB();
247     var hsv = rgb.getHSV();
248    // return the CSS HSL Color value
249     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
250     
251   },
252   
253   // modify  v = 0 ... 1 (eg. 0.5)
254   saturate : function(v)
255   {
256       var rgb = this.toRGB();
257       var hsv = rgb.getHSV();
258       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
259       
260   
261   },
262   
263    
264   /**
265    * getRGB
266    * @return {Object} the RGB and alpha components of this Color as an object with r,
267    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
268    * the range [0,1].
269    */
270   getRGB: function(){
271    
272     // return the RGB components
273     return {
274       'r' : this.rgb.r,
275       'g' : this.rgb.g,
276       'b' : this.rgb.b,
277       'a' : this.alpha
278     };
279
280   },
281
282   /**
283    * getHSV
284    * @return {Object} the HSV and alpha components of this Color as an object with h,
285    * s, v, and a properties. h is in the range [0,360), s and v are in the range
286    * [0,100], and a is in the range [0,1].
287    */
288   getHSV : function()
289   {
290     
291     // calculate the HSV components if necessary
292     if (this.hsv == null) this.calculateHSV();
293
294     // return the HSV components
295     return {
296       'h' : this.hsv.h,
297       's' : this.hsv.s,
298       'v' : this.hsv.v,
299       'a' : this.alpha
300     };
301
302   },
303
304   /**
305    * getHSL
306    * @return {Object} the HSL and alpha components of this Color as an object with h,
307    * s, l, and a properties. h is in the range [0,360), s and l are in the range
308    * [0,100], and a is in the range [0,1].
309    */
310   getHSL : function(){
311     
312      
313     // calculate the HSV components if necessary
314     if (this.hsl == null) this.calculateHSL();
315
316     // return the HSL components
317     return {
318       'h' : this.hsl.h,
319       's' : this.hsl.s,
320       'l' : this.hsl.l,
321       'a' : this.alpha
322     };
323
324   }
325   
326
327 });
328
329
330 /**
331  * @class Roo.lib.RGBColor
332  * @extends Roo.lib.Color
333  * Creates a Color specified in the RGB Color space, with an optional alpha
334  * component. The parameters are:
335  * @constructor
336  * 
337
338  * @param {Number} r - the red component, clipped to the range [0,255]
339  * @param {Number} g - the green component, clipped to the range [0,255]
340  * @param {Number} b - the blue component, clipped to the range [0,255]
341  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
342  *     optional and defaults to 1
343  */
344 Roo.lib.RGBColor = function (r, g, b, a){
345
346   // store the alpha component after clipping it if necessary
347   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
348
349   // store the RGB components after clipping them if necessary
350   this.rgb =
351       {
352         'r' : Math.max(0, Math.min(255, r)),
353         'g' : Math.max(0, Math.min(255, g)),
354         'b' : Math.max(0, Math.min(255, b))
355       };
356
357   // initialise the HSV and HSL components to null
358   
359
360   /* 
361    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
362    * range [0,360). The parameters are:
363    *
364    * maximum - the maximum of the RGB component values
365    * range   - the range of the RGB component values
366    */
367    
368
369 }
370 // this does an 'exteds'
371 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
372
373   
374     getHue  : function(maximum, range)
375     {
376       var rgb = this.rgb;
377        
378       // check whether the range is zero
379       if (range == 0){
380   
381         // set the hue to zero (any hue is acceptable as the Color is grey)
382         var hue = 0;
383   
384       }else{
385   
386         // determine which of the components has the highest value and set the hue
387         switch (maximum){
388   
389           // red has the highest value
390           case rgb.r:
391             var hue = (rgb.g - rgb.b) / range * 60;
392             if (hue < 0) hue += 360;
393             break;
394   
395           // green has the highest value
396           case rgb.g:
397             var hue = (rgb.b - rgb.r) / range * 60 + 120;
398             break;
399   
400           // blue has the highest value
401           case rgb.b:
402             var hue = (rgb.r - rgb.g) / range * 60 + 240;
403             break;
404   
405         }
406   
407       }
408   
409       // return the hue
410       return hue;
411   
412     },
413
414   /* //private Calculates and stores the HSV components of this RGBColor so that they can
415    * be returned be the getHSV function.
416    */
417    calculateHSV : function(){
418     var rgb = this.rgb;
419     // get the maximum and range of the RGB component values
420     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
421     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
422
423     // store the HSV components
424     this.hsv =
425         {
426           'h' : this.getHue(maximum, range),
427           's' : (maximum == 0 ? 0 : 100 * range / maximum),
428           'v' : maximum / 2.55
429         };
430
431   },
432
433   /* //private Calculates and stores the HSL components of this RGBColor so that they can
434    * be returned be the getHSL function.
435    */
436    calculateHSL : function(){
437     var rgb = this.rgb;
438     // get the maximum and range of the RGB component values
439     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
440     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
441
442     // determine the lightness in the range [0,1]
443     var l = maximum / 255 - range / 510;
444
445     // store the HSL components
446     this.hsl =
447         {
448           'h' : this.getHue(maximum, range),
449           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
450           'l' : 100 * l
451         };
452
453   }
454
455 });
456
457 /**
458  * @class Roo.lib.HSVColor
459  * @extends Roo.lib.Color
460  * Creates a Color specified in the HSV Color space, with an optional alpha
461  * component. The parameters are:
462  * @constructor
463  *
464  * @param {Number} h - the hue component, wrapped to the range [0,360)
465  * @param {Number} s - the saturation component, clipped to the range [0,100]
466  * @param {Number} v - the value component, clipped to the range [0,100]
467  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
468  *     optional and defaults to 1
469  */
470 Roo.lib.HSVColor = function (h, s, v, a){
471
472   // store the alpha component after clipping it if necessary
473   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
474
475   // store the HSV components after clipping or wrapping them if necessary
476   this.hsv =
477       {
478         'h' : (h % 360 + 360) % 360,
479         's' : Math.max(0, Math.min(100, s)),
480         'v' : Math.max(0, Math.min(100, v))
481       };
482
483   // initialise the RGB and HSL components to null
484   this.rgb = null;
485   this.hsl = null;
486 }
487
488 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
489   /* Calculates and stores the RGB components of this HSVColor so that they can
490    * be returned be the getRGB function.
491    */
492   calculateRGB: function ()
493   {
494     var hsv = this.hsv;
495     // check whether the saturation is zero
496     if (hsv.s == 0){
497
498       // set the Color to the appropriate shade of grey
499       var r = hsv.v;
500       var g = hsv.v;
501       var b = hsv.v;
502
503     }else{
504
505       // set some temporary values
506       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
507       var p  = hsv.v * (1 - hsv.s / 100);
508       var q  = hsv.v * (1 - hsv.s / 100 * f);
509       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
510
511       // set the RGB Color components to their temporary values
512       switch (Math.floor(hsv.h / 60)){
513         case 0: var r = hsv.v; var g = t; var b = p; break;
514         case 1: var r = q; var g = hsv.v; var b = p; break;
515         case 2: var r = p; var g = hsv.v; var b = t; break;
516         case 3: var r = p; var g = q; var b = hsv.v; break;
517         case 4: var r = t; var g = p; var b = hsv.v; break;
518         case 5: var r = hsv.v; var g = p; var b = q; break;
519       }
520
521     }
522
523     // store the RGB components
524     this.rgb =
525         {
526           'r' : r * 2.55,
527           'g' : g * 2.55,
528           'b' : b * 2.55
529         };
530
531   },
532
533   /* Calculates and stores the HSL components of this HSVColor so that they can
534    * be returned be the getHSL function.
535    */
536   calculateHSL : function (){
537
538     var hsv = this.hsv;
539     // determine the lightness in the range [0,100]
540     var l = (2 - hsv.s / 100) * hsv.v / 2;
541
542     // store the HSL components
543     this.hsl =
544         {
545           'h' : hsv.h,
546           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
547           'l' : l
548         };
549
550     // correct a division-by-zero error
551     if (isNaN(hsl.s)) hsl.s = 0;
552
553   } 
554  
555
556 });
557  
558
559 /**
560  * @class Roo.lib.HSLColor
561  * @extends Roo.lib.Color
562  *
563  * @constructor
564  * Creates a Color specified in the HSL Color space, with an optional alpha
565  * component. The parameters are:
566  *
567  * @param {Number} h - the hue component, wrapped to the range [0,360)
568  * @param {Number} s - the saturation component, clipped to the range [0,100]
569  * @param {Number} l - the lightness component, clipped to the range [0,100]
570  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
571  *     optional and defaults to 1
572  */
573
574 Roo.lib.HSLColor = function(h, s, l, a){
575
576   // store the alpha component after clipping it if necessary
577   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
578
579   // store the HSL components after clipping or wrapping them if necessary
580   this.hsl =
581       {
582         'h' : (h % 360 + 360) % 360,
583         's' : Math.max(0, Math.min(100, s)),
584         'l' : Math.max(0, Math.min(100, l))
585       };
586
587   // initialise the RGB and HSV components to null
588 }
589
590 Roo.extend(Roo.lib.HSL, Roo.lib.Color, {
591
592   /* Calculates and stores the RGB components of this HSLColor so that they can
593    * be returned be the getRGB function.
594    */
595   calculateRGB: function (){
596
597     // check whether the saturation is zero
598     if (this.hsl.s == 0){
599
600       // store the RGB components representing the appropriate shade of grey
601       this.rgb =
602           {
603             'r' : this.hsl.l * 2.55,
604             'g' : this.hsl.l * 2.55,
605             'b' : this.hsl.l * 2.55
606           };
607
608     }else{
609
610       // set some temporary values
611       var p = this.hsl.l < 50
612             ? this.hsl.l * (1 + hsl.s / 100)
613             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
614       var q = 2 * hsl.l - p;
615
616       // initialise the RGB components
617       this.rgb =
618           {
619             'r' : (h + 120) / 60 % 6,
620             'g' : h / 60,
621             'b' : (h + 240) / 60 % 6
622           };
623
624       // loop over the RGB components
625       for (var key in this.rgb){
626
627         // ensure that the property is not inherited from the root object
628         if (this.rgb.hasOwnProperty(key)){
629
630           // set the component to its value in the range [0,100]
631           if (this.rgb[key] < 1){
632             this.rgb[key] = q + (p - q) * this.rgb[key];
633           }else if (this.rgb[key] < 3){
634             this.rgb[key] = p;
635           }else if (this.rgb[key] < 4){
636             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
637           }else{
638             this.rgb[key] = q;
639           }
640
641           // set the component to its value in the range [0,255]
642           this.rgb[key] *= 2.55;
643
644         }
645
646       }
647
648     }
649
650   },
651
652   /* Calculates and stores the HSV components of this HSLColor so that they can
653    * be returned be the getHSL function.
654    */
655    calculateHSV : function(){
656
657     // set a temporary value
658     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
659
660     // store the HSV components
661     this.hsv =
662         {
663           'h' : this.hsl.h,
664           's' : 200 * t / (this.hsl.l + t),
665           'v' : t + this.hsl.l
666         };
667
668     // correct a division-by-zero error
669     if (isNaN(this.hsv.s)) this.hsv.s = 0;
670
671   }
672  
673
674 });