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 /* Creates a colour specified in the RGB colour space, with an optional alpha
231  * component. The parameters are:
232  *
233  * r - the red component, clipped to the range [0,255]
234  * g - the green component, clipped to the range [0,255]
235  * b - the blue component, clipped to the range [0,255]
236  * a - the alpha component, clipped to the range [0,1] - this parameter is
237  *     optional and defaults to 1
238  */
239 Roo.lib.RGBColour = function (r, g, b, a){
240
241   // store the alpha component after clipping it if necessary
242   var alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
243
244   // store the RGB components after clipping them if necessary
245   var rgb =
246       {
247         'r' : Math.max(0, Math.min(255, r)),
248         'g' : Math.max(0, Math.min(255, g)),
249         'b' : Math.max(0, Math.min(255, b))
250       };
251
252   // initialise the HSV and HSL components to null
253   var hsv = null;
254   var hsl = null;
255
256   /* Returns the HSV or HSL hue component of this RGBColour. The hue is in the
257    * range [0,360). The parameters are:
258    *
259    * maximum - the maximum of the RGB component values
260    * range   - the range of the RGB component values
261    */
262   function getHue(maximum, range){
263
264     // check whether the range is zero
265     if (range == 0){
266
267       // set the hue to zero (any hue is acceptable as the colour is grey)
268       var hue = 0;
269
270     }else{
271
272       // determine which of the components has the highest value and set the hue
273       switch (maximum){
274
275         // red has the highest value
276         case rgb.r:
277           var hue = (rgb.g - rgb.b) / range * 60;
278           if (hue < 0) hue += 360;
279           break;
280
281         // green has the highest value
282         case rgb.g:
283           var hue = (rgb.b - rgb.r) / range * 60 + 120;
284           break;
285
286         // blue has the highest value
287         case rgb.b:
288           var hue = (rgb.r - rgb.g) / range * 60 + 240;
289           break;
290
291       }
292
293     }
294
295     // return the hue
296     return hue;
297
298   }
299
300   /* Calculates and stores the HSV components of this RGBColour so that they can
301    * be returned be the getHSV function.
302    */
303   function calculateHSV(){
304
305     // get the maximum and range of the RGB component values
306     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
307     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
308
309     // store the HSV components
310     hsv =
311         {
312           'h' : getHue(maximum, range),
313           's' : (maximum == 0 ? 0 : 100 * range / maximum),
314           'v' : maximum / 2.55
315         };
316
317   }
318
319   /* Calculates and stores the HSL components of this RGBColour so that they can
320    * be returned be the getHSL function.
321    */
322   function calculateHSL(){
323
324     // get the maximum and range of the RGB component values
325     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
326     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
327
328     // determine the lightness in the range [0,1]
329     var l = maximum / 255 - range / 510;
330
331     // store the HSL components
332     hsl =
333         {
334           'h' : getHue(maximum, range),
335           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
336           'l' : 100 * l
337         };
338
339   }
340
341   /* Returns the RGB and alpha components of this RGBColour as an object with r,
342    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
343    * the range [0,1].
344    */
345   this.getRGB = function(){
346
347     // return the RGB components
348     return {
349       'r' : rgb.r,
350       'g' : rgb.g,
351       'b' : rgb.b,
352       'a' : alpha
353     };
354
355   };
356
357   /* Returns the HSV and alpha components of this RGBColour as an object with h,
358    * s, v, and a properties. h is in the range [0,360), s and v are in the range
359    * [0,100], and a is in the range [0,1].
360    */
361   this.getHSV = function(){
362
363     // calculate the HSV components if necessary
364     if (hsv == null) calculateHSV();
365
366     // return the HSV components
367     return {
368       'h' : hsv.h,
369       's' : hsv.s,
370       'v' : hsv.v,
371       'a' : alpha
372     };
373
374   };
375
376   /* Returns the HSL and alpha components of this RGBColour as an object with h,
377    * s, l, and a properties. h is in the range [0,360), s and l are in the range
378    * [0,100], and a is in the range [0,1].
379    */
380   this.getHSL = function(){
381
382     // calculate the HSV components if necessary
383     if (hsl == null) calculateHSL();
384
385     // return the HSL components
386     return {
387       'h' : hsl.h,
388       's' : hsl.s,
389       'l' : hsl.l,
390       'a' : alpha
391     };
392
393   };
394
395 }
396 Roo.lib.RGBColour.prototype = new Roo.lib.Colour();
397
398
399 /* Creates a colour specified in the HSV colour space, with an optional alpha
400  * component. The parameters are:
401  *
402  * h - the hue component, wrapped to the range [0,360)
403  * s - the saturation component, clipped to the range [0,100]
404  * v - the value component, clipped to the range [0,100]
405  * a - the alpha component, clipped to the range [0,1] - this parameter is
406  *     optional and defaults to 1
407  */
408 Roo.lib.HSVColour = function (h, s, v, a){
409
410   // store the alpha component after clipping it if necessary
411   var alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
412
413   // store the HSV components after clipping or wrapping them if necessary
414   var hsv =
415       {
416         'h' : (h % 360 + 360) % 360,
417         's' : Math.max(0, Math.min(100, s)),
418         'v' : Math.max(0, Math.min(100, v))
419       };
420
421   // initialise the RGB and HSL components to null
422   var rgb = null;
423   var hsl = null;
424
425   /* Calculates and stores the RGB components of this HSVColour so that they can
426    * be returned be the getRGB function.
427    */
428   function calculateRGB(){
429
430     // check whether the saturation is zero
431     if (hsv.s == 0){
432
433       // set the colour to the appropriate shade of grey
434       var r = hsv.v;
435       var g = hsv.v;
436       var b = hsv.v;
437
438     }else{
439
440       // set some temporary values
441       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
442       var p  = hsv.v * (1 - hsv.s / 100);
443       var q  = hsv.v * (1 - hsv.s / 100 * f);
444       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
445
446       // set the RGB colour components to their temporary values
447       switch (Math.floor(hsv.h / 60)){
448         case 0: var r = hsv.v; var g = t; var b = p; break;
449         case 1: var r = q; var g = hsv.v; var b = p; break;
450         case 2: var r = p; var g = hsv.v; var b = t; break;
451         case 3: var r = p; var g = q; var b = hsv.v; break;
452         case 4: var r = t; var g = p; var b = hsv.v; break;
453         case 5: var r = hsv.v; var g = p; var b = q; break;
454       }
455
456     }
457
458     // store the RGB components
459     rgb =
460         {
461           'r' : r * 2.55,
462           'g' : g * 2.55,
463           'b' : b * 2.55
464         };
465
466   }
467
468   /* Calculates and stores the HSL components of this HSVColour so that they can
469    * be returned be the getHSL function.
470    */
471   function calculateHSL(){
472
473     // determine the lightness in the range [0,100]
474     var l = (2 - hsv.s / 100) * hsv.v / 2;
475
476     // store the HSL components
477     hsl =
478         {
479           'h' : hsv.h,
480           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
481           'l' : l
482         };
483
484     // correct a division-by-zero error
485     if (isNaN(hsl.s)) hsl.s = 0;
486
487   }
488
489   /* Returns the RGB and alpha components of this HSVColour as an object with r,
490    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
491    * the range [0,1].
492    */
493   this.getRGB = function(){
494
495     // calculate the RGB components if necessary
496     if (rgb == null) calculateRGB();
497
498     // return the RGB components
499     return {
500       'r' : rgb.r,
501       'g' : rgb.g,
502       'b' : rgb.b,
503       'a' : alpha
504     };
505
506   };
507
508   /* Returns the HSV and alpha components of this HSVColour as an object with h,
509    * s, v, and a properties. h is in the range [0,360), s and v are in the range
510    * [0,100], and a is in the range [0,1].
511    */
512   this.getHSV = function(){
513
514     // return the HSV components
515     return {
516       'h' : hsv.h,
517       's' : hsv.s,
518       'v' : hsv.v,
519       'a' : alpha
520     };
521
522   };
523
524   /* Returns the HSL and alpha components of this HSVColour as an object with h,
525    * s, l, and a properties. h is in the range [0,360), s and l are in the range
526    * [0,100], and a is in the range [0,1].
527    */
528   this.getHSL = function(){
529
530     // calculate the HSL components if necessary
531     if (hsl == null) calculateHSL();
532
533     // return the HSL components
534     return {
535       'h' : hsl.h,
536       's' : hsl.s,
537       'l' : hsl.l,
538       'a' : alpha
539     };
540
541   };
542
543 }
544 Roo.lib.HSVColour.prototype = new Roo.lib.Colour();
545
546
547 /* Creates a colour specified in the HSL colour space, with an optional alpha
548  * component. The parameters are:
549  *
550  * h - the hue component, wrapped to the range [0,360)
551  * s - the saturation component, clipped to the range [0,100]
552  * l - the lightness component, clipped to the range [0,100]
553  * a - the alpha component, clipped to the range [0,1] - this parameter is
554  *     optional and defaults to 1
555  */
556
557 Roo.lib.HSLColour = function(h, s, l, a){
558
559   // store the alpha component after clipping it if necessary
560   var alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
561
562   // store the HSL components after clipping or wrapping them if necessary
563   var hsl =
564       {
565         'h' : (h % 360 + 360) % 360,
566         's' : Math.max(0, Math.min(100, s)),
567         'l' : Math.max(0, Math.min(100, l))
568       };
569
570   // initialise the RGB and HSV components to null
571   var rgb = null;
572   var hsv = null;
573
574   /* Calculates and stores the RGB components of this HSLColour so that they can
575    * be returned be the getRGB function.
576    */
577   function calculateRGB(){
578
579     // check whether the saturation is zero
580     if (hsl.s == 0){
581
582       // store the RGB components representing the appropriate shade of grey
583       rgb =
584           {
585             'r' : hsl.l * 2.55,
586             'g' : hsl.l * 2.55,
587             'b' : hsl.l * 2.55
588           };
589
590     }else{
591
592       // set some temporary values
593       var p = hsl.l < 50
594             ? hsl.l * (1 + hsl.s / 100)
595             : hsl.l + hsl.s - hsl.l * hsl.s / 100;
596       var q = 2 * hsl.l - p;
597
598       // initialise the RGB components
599       rgb =
600           {
601             'r' : (h + 120) / 60 % 6,
602             'g' : h / 60,
603             'b' : (h + 240) / 60 % 6
604           };
605
606       // loop over the RGB components
607       for (var key in rgb){
608
609         // ensure that the property is not inherited from the root object
610         if (rgb.hasOwnProperty(key)){
611
612           // set the component to its value in the range [0,100]
613           if (rgb[key] < 1){
614             rgb[key] = q + (p - q) * rgb[key];
615           }else if (rgb[key] < 3){
616             rgb[key] = p;
617           }else if (rgb[key] < 4){
618             rgb[key] = q + (p - q) * (4 - rgb[key]);
619           }else{
620             rgb[key] = q;
621           }
622
623           // set the component to its value in the range [0,255]
624           rgb[key] *= 2.55;
625
626         }
627
628       }
629
630     }
631
632   }
633
634   /* Calculates and stores the HSV components of this HSLColour so that they can
635    * be returned be the getHSL function.
636    */
637   function calculateHSV(){
638
639     // set a temporary value
640     var t = hsl.s * (hsl.l < 50 ? hsl.l : 100 - hsl.l) / 100;
641
642     // store the HSV components
643     hsv =
644         {
645           'h' : hsl.h,
646           's' : 200 * t / (hsl.l + t),
647           'v' : t + hsl.l
648         };
649
650     // correct a division-by-zero error
651     if (isNaN(hsv.s)) hsv.s = 0;
652
653   }
654
655   /* Returns the RGB and alpha components of this HSLColour as an object with r,
656    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
657    * the range [0,1].
658    */
659   this.getRGB = function(){
660
661     // calculate the RGB components if necessary
662     if (rgb == null) calculateRGB();
663
664     // return the RGB components
665     return {
666       'r' : rgb.r,
667       'g' : rgb.g,
668       'b' : rgb.b,
669       'a' : alpha
670     };
671
672   };
673
674   /* Returns the HSV and alpha components of this HSLColour as an object with h,
675    * s, v, and a properties. h is in the range [0,360), s and v are in the range
676    * [0,100], and a is in the range [0,1].
677    */
678   this.getHSV = function(){
679
680     // calculate the HSV components if necessary
681     if (hsv == null) calculateHSV();
682
683     // return the HSV components
684     return {
685       'h' : hsv.h,
686       's' : hsv.s,
687       'v' : hsv.v,
688       'a' : alpha
689     };
690
691   };
692
693   /* Returns the HSL and alpha components of this HSLColour as an object with h,
694    * s, l, and a properties. h is in the range [0,360), s and l are in the range
695    * [0,100], and a is in the range [0,1].
696    */
697   this.getHSL = function(){
698
699     // return the HSL components
700     return {
701       'h' : hsl.h,
702       's' : hsl.s,
703       'l' : hsl.l,
704       'a' : alpha
705     };
706
707   };
708
709 }
710 Roo.lib.HSLColour.prototype = new Roo.lib.Colour();