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