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