source: trunk/plugins/SwiftThemeCreator/farbtastic/farbtastic.js @ 3283

Last change on this file since 3283 was 3283, checked in by plg, 15 years ago

complement to r3282, remove all $Id$ in source code.

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