web/drupal/misc/farbtastic/farbtastic.js
branchdrupal
changeset 74 0ff3ba646492
equal deleted inserted replaced
73:fcf75e232c5b 74:0ff3ba646492
       
     1 // $Id: farbtastic.js,v 1.4.2.1 2008/06/25 09:34:17 goba Exp $
       
     2 // Farbtastic 1.2
       
     3 
       
     4 jQuery.fn.farbtastic = function (callback) {
       
     5   $.farbtastic(this, callback);
       
     6   return this;
       
     7 };
       
     8 
       
     9 jQuery.farbtastic = function (container, callback) {
       
    10   var container = $(container).get(0);
       
    11   return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));
       
    12 };
       
    13 
       
    14 jQuery._farbtastic = function (container, callback) {
       
    15   // Store farbtastic object
       
    16   var fb = this;
       
    17 
       
    18   // Insert markup
       
    19   $(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
       
    20   var e = $('.farbtastic', container);
       
    21   fb.wheel = $('.wheel', container).get(0);
       
    22   // Dimensions
       
    23   fb.radius = 84;
       
    24   fb.square = 100;
       
    25   fb.width = 194;
       
    26 
       
    27   // Fix background PNGs in IE6
       
    28   if (navigator.appVersion.match(/MSIE [0-6]\./)) {
       
    29     $('*', e).each(function () {
       
    30       if (this.currentStyle.backgroundImage != 'none') {
       
    31         var image = this.currentStyle.backgroundImage;
       
    32         image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
       
    33         $(this).css({
       
    34           'backgroundImage': 'none',
       
    35           'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
       
    36         });
       
    37       }
       
    38     });
       
    39   }
       
    40 
       
    41   /**
       
    42    * Link to the given element(s) or callback.
       
    43    */
       
    44   fb.linkTo = function (callback) {
       
    45     // Unbind previous nodes
       
    46     if (typeof fb.callback == 'object') {
       
    47       $(fb.callback).unbind('keyup', fb.updateValue);
       
    48     }
       
    49 
       
    50     // Reset color
       
    51     fb.color = null;
       
    52 
       
    53     // Bind callback or elements
       
    54     if (typeof callback == 'function') {
       
    55       fb.callback = callback;
       
    56     }
       
    57     else if (typeof callback == 'object' || typeof callback == 'string') {
       
    58       fb.callback = $(callback);
       
    59       fb.callback.bind('keyup', fb.updateValue);
       
    60       if (fb.callback.get(0).value) {
       
    61         fb.setColor(fb.callback.get(0).value);
       
    62       }
       
    63     }
       
    64     return this;
       
    65   };
       
    66   fb.updateValue = function (event) {
       
    67     if (this.value && this.value != fb.color) {
       
    68       fb.setColor(this.value);
       
    69     }
       
    70   };
       
    71 
       
    72   /**
       
    73    * Change color with HTML syntax #123456
       
    74    */
       
    75   fb.setColor = function (color) {
       
    76     var unpack = fb.unpack(color);
       
    77     if (fb.color != color && unpack) {
       
    78       fb.color = color;
       
    79       fb.rgb = unpack;
       
    80       fb.hsl = fb.RGBToHSL(fb.rgb);
       
    81       fb.updateDisplay();
       
    82     }
       
    83     return this;
       
    84   };
       
    85 
       
    86   /**
       
    87    * Change color with HSL triplet [0..1, 0..1, 0..1]
       
    88    */
       
    89   fb.setHSL = function (hsl) {
       
    90     fb.hsl = hsl;
       
    91     fb.rgb = fb.HSLToRGB(hsl);
       
    92     fb.color = fb.pack(fb.rgb);
       
    93     fb.updateDisplay();
       
    94     return this;
       
    95   };
       
    96 
       
    97   /////////////////////////////////////////////////////
       
    98 
       
    99   /**
       
   100    * Retrieve the coordinates of the given event relative to the center
       
   101    * of the widget.
       
   102    */
       
   103   fb.widgetCoords = function (event) {
       
   104     var x, y;
       
   105     var el = event.target || event.srcElement;
       
   106     var reference = fb.wheel;
       
   107     
       
   108     // If the offset from the relative element is undefined calculate it.
       
   109     if ( typeof event.offsetX == 'undefined' && typeof event.offsetY == 'undefined' ) {
       
   110       var offset = $(event.target).offset(false);
       
   111       event.offsetX = event.pageX - offset.left;
       
   112       event.offsetY = event.pageY - offset.top;
       
   113     }
       
   114     
       
   115     // Use offset coordinates and find common offsetParent
       
   116     var pos = { x: event.offsetX, y: event.offsetY };
       
   117 
       
   118     // Send the coordinates upwards through the offsetParent chain.
       
   119     var e = el;
       
   120     while (e) {
       
   121       e.mouseX = pos.x;
       
   122       e.mouseY = pos.y;
       
   123       pos.x += e.offsetLeft;
       
   124       pos.y += e.offsetTop;
       
   125       e = e.offsetParent;
       
   126     }
       
   127 
       
   128     // Look for the coordinates starting from the wheel widget.
       
   129     var e = reference;
       
   130     var offset = { x: 0, y: 0 };
       
   131     while (e) {
       
   132       if (typeof e.mouseX != 'undefined') {
       
   133         x = e.mouseX - offset.x;
       
   134         y = e.mouseY - offset.y;
       
   135         break;
       
   136       }
       
   137       offset.x += e.offsetLeft;
       
   138       offset.y += e.offsetTop;
       
   139       e = e.offsetParent;
       
   140     }
       
   141 
       
   142     // Reset stored coordinates
       
   143     e = el;
       
   144     while (e) {
       
   145       e.mouseX = undefined;
       
   146       e.mouseY = undefined;
       
   147       e = e.offsetParent;
       
   148     }
       
   149 
       
   150     // Subtract distance to middle
       
   151     return { x: x - fb.width / 2, y: y - fb.width / 2 };
       
   152   };
       
   153 
       
   154   /**
       
   155    * Mousedown handler
       
   156    */
       
   157   fb.mousedown = function (event) {
       
   158     // Capture mouse
       
   159     if (!document.dragging) {
       
   160       $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
       
   161       document.dragging = true;
       
   162     }
       
   163 
       
   164     // Check which area is being dragged
       
   165     var pos = fb.widgetCoords(event);
       
   166     fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
       
   167 
       
   168     // Process
       
   169     fb.mousemove(event);
       
   170     return false;
       
   171   };
       
   172 
       
   173   /**
       
   174    * Mousemove handler
       
   175    */
       
   176   fb.mousemove = function (event) {
       
   177     // Get coordinates relative to color picker center
       
   178     var pos = fb.widgetCoords(event);
       
   179 
       
   180     // Set new HSL parameters
       
   181     if (fb.circleDrag) {
       
   182       var hue = Math.atan2(pos.x, -pos.y) / 6.28;
       
   183       if (hue < 0) hue += 1;
       
   184       fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
       
   185     }
       
   186     else {
       
   187       var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
       
   188       var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
       
   189       fb.setHSL([fb.hsl[0], sat, lum]);
       
   190     }
       
   191     return false;
       
   192   };
       
   193 
       
   194   /**
       
   195    * Mouseup handler
       
   196    */
       
   197   fb.mouseup = function () {
       
   198     // Uncapture mouse
       
   199     $(document).unbind('mousemove', fb.mousemove);
       
   200     $(document).unbind('mouseup', fb.mouseup);
       
   201     document.dragging = false;
       
   202   };
       
   203 
       
   204   /**
       
   205    * Update the markers and styles
       
   206    */
       
   207   fb.updateDisplay = function () {
       
   208     // Markers
       
   209     var angle = fb.hsl[0] * 6.28;
       
   210     $('.h-marker', e).css({
       
   211       left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
       
   212       top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
       
   213     });
       
   214 
       
   215     $('.sl-marker', e).css({
       
   216       left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
       
   217       top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
       
   218     });
       
   219 
       
   220     // Saturation/Luminance gradient
       
   221     $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
       
   222 
       
   223     // Linked elements or callback
       
   224     if (typeof fb.callback == 'object') {
       
   225       // Set background/foreground color
       
   226       $(fb.callback).css({
       
   227         backgroundColor: fb.color,
       
   228         color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
       
   229       });
       
   230 
       
   231       // Change linked value
       
   232       $(fb.callback).each(function() {
       
   233         if (this.value && this.value != fb.color) {
       
   234           this.value = fb.color;
       
   235         }
       
   236       });
       
   237     }
       
   238     else if (typeof fb.callback == 'function') {
       
   239       fb.callback.call(fb, fb.color);
       
   240     }
       
   241   };
       
   242 
       
   243   /* Various color utility functions */
       
   244   fb.pack = function (rgb) {
       
   245     var r = Math.round(rgb[0] * 255);
       
   246     var g = Math.round(rgb[1] * 255);
       
   247     var b = Math.round(rgb[2] * 255);
       
   248     return '#' + (r < 16 ? '0' : '') + r.toString(16) +
       
   249            (g < 16 ? '0' : '') + g.toString(16) +
       
   250            (b < 16 ? '0' : '') + b.toString(16);
       
   251   };
       
   252 
       
   253   fb.unpack = function (color) {
       
   254     if (color.length == 7) {
       
   255       return [parseInt('0x' + color.substring(1, 3)) / 255,
       
   256         parseInt('0x' + color.substring(3, 5)) / 255,
       
   257         parseInt('0x' + color.substring(5, 7)) / 255];
       
   258     }
       
   259     else if (color.length == 4) {
       
   260       return [parseInt('0x' + color.substring(1, 2)) / 15,
       
   261         parseInt('0x' + color.substring(2, 3)) / 15,
       
   262         parseInt('0x' + color.substring(3, 4)) / 15];
       
   263     }
       
   264   };
       
   265 
       
   266   fb.HSLToRGB = function (hsl) {
       
   267     var m1, m2, r, g, b;
       
   268     var h = hsl[0], s = hsl[1], l = hsl[2];
       
   269     m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
       
   270     m1 = l * 2 - m2;
       
   271     return [this.hueToRGB(m1, m2, h+0.33333),
       
   272         this.hueToRGB(m1, m2, h),
       
   273         this.hueToRGB(m1, m2, h-0.33333)];
       
   274   };
       
   275 
       
   276   fb.hueToRGB = function (m1, m2, h) {
       
   277     h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
       
   278     if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
       
   279     if (h * 2 < 1) return m2;
       
   280     if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
       
   281     return m1;
       
   282   };
       
   283 
       
   284   fb.RGBToHSL = function (rgb) {
       
   285     var min, max, delta, h, s, l;
       
   286     var r = rgb[0], g = rgb[1], b = rgb[2];
       
   287     min = Math.min(r, Math.min(g, b));
       
   288     max = Math.max(r, Math.max(g, b));
       
   289     delta = max - min;
       
   290     l = (min + max) / 2;
       
   291     s = 0;
       
   292     if (l > 0 && l < 1) {
       
   293       s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
       
   294     }
       
   295     h = 0;
       
   296     if (delta > 0) {
       
   297       if (max == r && max != g) h += (g - b) / delta;
       
   298       if (max == g && max != b) h += (2 + (b - r) / delta);
       
   299       if (max == b && max != r) h += (4 + (r - g) / delta);
       
   300       h /= 6;
       
   301     }
       
   302     return [h, s, l];
       
   303   };
       
   304 
       
   305   // Install mousedown handler (the others are set on the document on-demand)
       
   306   $('*', e).mousedown(fb.mousedown);
       
   307 
       
   308     // Init color
       
   309   fb.setColor('#000000');
       
   310 
       
   311   // Set linked elements/callback
       
   312   if (callback) {
       
   313     fb.linkTo(callback);
       
   314   }
       
   315 };