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