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