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