source: extensions/pwgCumulus/js/farbtastic.js @ 5201

Last change on this file since 5201 was 5201, checked in by nikrou, 14 years ago

Initial version

File size: 9.4 KB
Line 
1// $Id: farbtastic.js,v 1.2 2007/01/08 22:53:01 unconed Exp $
2// Farbtastic 1.2
3
4jQuery.fn.farbtastic = function (callback) {
5  $.farbtastic(this, callback);
6  return this;
7};
8
9jQuery.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 (typeof event.offsetX != 'undefined') {
109        // Use offset coordinates and find common offsetParent
110        var pos = { x: event.offsetX, y: event.offsetY };
111
112        // Send the coordinates upwards through the offsetParent chain.
113        var e = el;
114        while (e) {
115          e.mouseX = pos.x;
116          e.mouseY = pos.y;
117          pos.x += e.offsetLeft;
118          pos.y += e.offsetTop;
119          e = e.offsetParent;
120        }
121
122        // Look for the coordinates starting from the wheel widget.
123        var e = reference;
124        var offset = { x: 0, y: 0 }
125        while (e) {
126          if (typeof e.mouseX != 'undefined') {
127            x = e.mouseX - offset.x;
128            y = e.mouseY - offset.y;
129            break;
130          }
131          offset.x += e.offsetLeft;
132          offset.y += e.offsetTop;
133          e = e.offsetParent;
134        }
135
136        // Reset stored coordinates
137        e = el;
138        while (e) {
139          e.mouseX = undefined;
140          e.mouseY = undefined;
141          e = e.offsetParent;
142        }
143      }
144      else {
145        // Use absolute coordinates
146        var pos = fb.absolutePosition(reference);
147        x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x;
148        y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y;
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    /**
244     * Get absolute position of element
245     */
246    fb.absolutePosition = function (el) {
247      var r = { x: el.offsetLeft, y: el.offsetTop };
248      // Resolve relative to offsetParent
249      if (el.offsetParent) {
250        var tmp = fb.absolutePosition(el.offsetParent);
251        r.x += tmp.x;
252        r.y += tmp.y;
253      }
254      return r;
255    };
256
257    /* Various color utility functions */
258    fb.pack = function (rgb) {
259      var r = Math.round(rgb[0] * 255);
260      var g = Math.round(rgb[1] * 255);
261      var b = Math.round(rgb[2] * 255);
262      return '#' + (r < 16 ? '0' : '') + r.toString(16) +
263      (g < 16 ? '0' : '') + g.toString(16) +
264      (b < 16 ? '0' : '') + b.toString(16);
265    }
266
267    fb.unpack = function (color) {
268      if (color.length == 7) {
269        return [parseInt('0x' + color.substring(1, 3)) / 255,
270                parseInt('0x' + color.substring(3, 5)) / 255,
271                parseInt('0x' + color.substring(5, 7)) / 255];
272      }
273      else if (color.length == 4) {
274        return [parseInt('0x' + color.substring(1, 2)) / 15,
275                parseInt('0x' + color.substring(2, 3)) / 15,
276                parseInt('0x' + color.substring(3, 4)) / 15];
277      }
278    }
279
280    fb.HSLToRGB = function (hsl) {
281      var m1, m2, r, g, b;
282      var h = hsl[0], s = hsl[1], l = hsl[2];
283      m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
284      m1 = l * 2 - m2;
285      return [this.hueToRGB(m1, m2, h+0.33333),
286              this.hueToRGB(m1, m2, h),
287              this.hueToRGB(m1, m2, h-0.33333)];
288    }
289
290    fb.hueToRGB = function (m1, m2, h) {
291      h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
292      if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
293      if (h * 2 < 1) return m2;
294      if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
295      return m1;
296    }
297
298    fb.RGBToHSL = function (rgb) {
299      var min, max, delta, h, s, l;
300      var r = rgb[0], g = rgb[1], b = rgb[2];
301      min = Math.min(r, Math.min(g, b));
302      max = Math.max(r, Math.max(g, b));
303      delta = max - min;
304      l = (min + max) / 2;
305      s = 0;
306      if (l > 0 && l < 1) {
307        s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
308      }
309      h = 0;
310      if (delta > 0) {
311        if (max == r && max != g) h += (g - b) / delta;
312        if (max == g && max != b) h += (2 + (b - r) / delta);
313        if (max == b && max != r) h += (4 + (r - g) / delta);
314        h /= 6;
315      }
316      return [h, s, l];
317    }
318
319    // Install mousedown handler (the others are set on the document on-demand)
320    $('*', e).mousedown(fb.mousedown);
321
322    // Init color
323    fb.setColor('#000000');
324
325    // Set linked elements/callback
326    if (callback) {
327      fb.linkTo(callback);
328    }
329  };
330
331$(function() {
332    var f = $.farbtastic('#picker');
333    var p = $('#picker').hide().css('opacity', 0.25);
334    var selected;
335    $('.colorwell')
336      .each(function () { f.linkTo(this); $(this).css('opacity', 0.75); })
337      .focus(function(e) {
338          p.slideDown();
339          if (selected) {
340            $(selected)
341              .css('opacity', 0.75).removeClass('colorwell-selected');
342          }
343          f.linkTo(this);
344          p.css('opacity', 1);
345          $(selected = this).css('opacity', 1).addClass('colorwell-selected');
346        });
347  });
Note: See TracBrowser for help on using the repository browser.