github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/root/js/bootstrap-colorpicker.js (about) 1 /* ========================================================= 2 * bootstrap-colorpicker.js 3 * http://www.eyecon.ro/bootstrap-colorpicker 4 * ========================================================= 5 * Copyright 2012 Stefan Petre 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * ========================================================= */ 19 20 !function( $ ) { 21 22 // Color object 23 24 var Color = function(val) { 25 this.value = { 26 h: 1, 27 s: 1, 28 b: 1, 29 a: 1 30 }; 31 this.setColor(val); 32 }; 33 34 Color.prototype = { 35 constructor: Color, 36 37 //parse a string to HSB 38 setColor: function(val){ 39 val = val.toLowerCase(); 40 var that = this; 41 $.each( CPGlobal.stringParsers, function( i, parser ) { 42 var match = parser.re.exec( val ), 43 values = match && parser.parse( match ), 44 space = parser.space||'rgba'; 45 if ( values ) { 46 if (space === 'hsla') { 47 that.value = CPGlobal.RGBtoHSB.apply(null, CPGlobal.HSLtoRGB.apply(null, values)); 48 } else { 49 that.value = CPGlobal.RGBtoHSB.apply(null, values); 50 } 51 return false; 52 } 53 }); 54 }, 55 56 setHue: function(h) { 57 this.value.h = 1- h; 58 }, 59 60 setSaturation: function(s) { 61 this.value.s = s; 62 }, 63 64 setLightness: function(b) { 65 this.value.b = 1- b; 66 }, 67 68 setAlpha: function(a) { 69 this.value.a = parseInt((1 - a)*100, 10)/100; 70 }, 71 72 // HSBtoRGB from RaphaelJS 73 // https://github.com/DmitryBaranovskiy/raphael/ 74 toRGB: function(h, s, b, a) { 75 if (!h) { 76 h = this.value.h; 77 s = this.value.s; 78 b = this.value.b; 79 } 80 h *= 360; 81 var R, G, B, X, C; 82 h = (h % 360) / 60; 83 C = b * s; 84 X = C * (1 - Math.abs(h % 2 - 1)); 85 R = G = B = b - C; 86 87 h = ~~h; 88 R += [C, X, 0, 0, X, C][h]; 89 G += [X, C, C, X, 0, 0][h]; 90 B += [0, 0, X, C, C, X][h]; 91 return { 92 r: Math.round(R*255), 93 g: Math.round(G*255), 94 b: Math.round(B*255), 95 a: a||this.value.a 96 }; 97 }, 98 99 toHex: function(h, s, b, a){ 100 var rgb = this.toRGB(h, s, b, a); 101 return '#'+((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1); 102 }, 103 104 toHSL: function(h, s, b, a){ 105 if (!h) { 106 h = this.value.h; 107 s = this.value.s; 108 b = this.value.b; 109 } 110 var H = h, 111 L = (2 - s) * b, 112 S = s * b; 113 if (L > 0 && L <= 1) { 114 S /= L; 115 } else { 116 S /= 2 - L; 117 } 118 L /= 2; 119 if (S > 1) { 120 S = 1; 121 } 122 return { 123 h: H, 124 s: S, 125 l: L, 126 a: a||this.value.a 127 }; 128 } 129 }; 130 131 // Picker object 132 133 var Colorpicker = function(element, options){ 134 this.element = $(element); 135 var format = options.format||this.element.data('color-format')||'hex'; 136 this.format = CPGlobal.translateFormats[format]; 137 this.isInput = this.element.is('input'); 138 this.component = this.element.is('.color') ? this.element.find('.add-on') : false; 139 140 this.picker = $(CPGlobal.template) 141 .appendTo('body') 142 .on('mousedown', $.proxy(this.mousedown, this)); 143 144 if (this.isInput) { 145 this.element.on({ 146 'focus': $.proxy(this.show, this), 147 'keyup': $.proxy(this.update, this) 148 }); 149 } else if (this.component){ 150 this.component.on({ 151 'click': $.proxy(this.show, this) 152 }); 153 } else { 154 this.element.on({ 155 'click': $.proxy(this.show, this) 156 }); 157 } 158 if (format === 'rgba' || format === 'hsla') { 159 this.picker.addClass('alpha'); 160 this.alpha = this.picker.find('.colorpicker-alpha')[0].style; 161 } 162 163 if (this.component){ 164 this.picker.find('.colorpicker-color').hide(); 165 this.preview = this.element.find('i')[0].style; 166 } else { 167 this.preview = this.picker.find('div:last')[0].style; 168 } 169 170 this.base = this.picker.find('div:first')[0].style; 171 this.update(); 172 }; 173 174 Colorpicker.prototype = { 175 constructor: Colorpicker, 176 177 show: function(e) { 178 this.picker.show(); 179 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 180 this.place(); 181 $(window).on('resize', $.proxy(this.place, this)); 182 if (!this.isInput) { 183 if (e) { 184 e.stopPropagation(); 185 e.preventDefault(); 186 } 187 } 188 $(document).on({ 189 'mousedown': $.proxy(this.hide, this) 190 }); 191 this.element.trigger({ 192 type: 'show', 193 color: this.color 194 }); 195 }, 196 197 update: function(){ 198 this.color = new Color(this.isInput ? this.element.prop('value') : this.element.data('color')); 199 this.picker.find('i') 200 .eq(0).css({left: this.color.value.s*100, top: 100 - this.color.value.b*100}).end() 201 .eq(1).css('top', 100 * (1 - this.color.value.h)).end() 202 .eq(2).css('top', 100 * (1 - this.color.value.a)); 203 this.previewColor(); 204 }, 205 206 setValue: function(newColor) { 207 this.color = new Color(newColor); 208 this.picker.find('i') 209 .eq(0).css({left: this.color.value.s*100, top: 100 - this.color.value.b*100}).end() 210 .eq(1).css('top', 100 * (1 - this.color.value.h)).end() 211 .eq(2).css('top', 100 * (1 - this.color.value.a)); 212 this.previewColor(); 213 this.element.trigger({ 214 type: 'changeColor', 215 color: this.color 216 }); 217 }, 218 219 hide: function(){ 220 this.picker.hide(); 221 $(window).off('resize', this.place); 222 if (!this.isInput) { 223 $(document).off({ 224 'mousedown': this.hide 225 }); 226 if (this.component){ 227 this.element.find('input').prop('value', this.format.call(this)); 228 } 229 this.element.data('color', this.format.call(this)); 230 } else { 231 this.element.prop('value', this.format.call(this)); 232 } 233 this.element.trigger({ 234 type: 'hide', 235 color: this.color 236 }); 237 }, 238 239 place: function(){ 240 var offset = this.component ? this.component.offset() : this.element.offset(); 241 this.picker.css({ 242 top: offset.top + this.height, 243 left: offset.left 244 }); 245 }, 246 247 //preview color change 248 previewColor: function(){ 249 try { 250 this.preview.backgroundColor = this.format.call(this); 251 } catch(e) { 252 this.preview.backgroundColor = this.color.toHex(); 253 } 254 //set the color for brightness/saturation slider 255 this.base.backgroundColor = this.color.toHex(this.color.value.h, 1, 1, 1); 256 //set te color for alpha slider 257 if (this.alpha) { 258 this.alpha.backgroundColor = this.color.toHex(); 259 } 260 }, 261 262 pointer: null, 263 264 slider: null, 265 266 mousedown: function(e){ 267 e.stopPropagation(); 268 e.preventDefault(); 269 270 var target = $(e.target); 271 272 //detect the slider and set the limits and callbacks 273 var zone = target.closest('div'); 274 if (!zone.is('.colorpicker')) { 275 if (zone.is('.colorpicker-saturation')) { 276 this.slider = $.extend({}, CPGlobal.sliders.saturation); 277 } 278 else if (zone.is('.colorpicker-hue')) { 279 this.slider = $.extend({}, CPGlobal.sliders.hue); 280 } 281 else if (zone.is('.colorpicker-alpha')) { 282 this.slider = $.extend({}, CPGlobal.sliders.alpha); 283 } else { 284 return false; 285 } 286 var offset = zone.offset(); 287 //reference to knob's style 288 this.slider.knob = zone.find('i')[0].style; 289 this.slider.left = e.pageX - offset.left; 290 this.slider.top = e.pageY - offset.top; 291 this.pointer = { 292 left: e.pageX, 293 top: e.pageY 294 }; 295 //trigger mousemove to move the knob to the current position 296 $(document).on({ 297 mousemove: $.proxy(this.mousemove, this), 298 mouseup: $.proxy(this.mouseup, this) 299 }).trigger('mousemove'); 300 } 301 return false; 302 }, 303 304 mousemove: function(e){ 305 e.stopPropagation(); 306 e.preventDefault(); 307 var left = Math.max( 308 0, 309 Math.min( 310 this.slider.maxLeft, 311 this.slider.left + ((e.pageX||this.pointer.left) - this.pointer.left) 312 ) 313 ); 314 var top = Math.max( 315 0, 316 Math.min( 317 this.slider.maxTop, 318 this.slider.top + ((e.pageY||this.pointer.top) - this.pointer.top) 319 ) 320 ); 321 this.slider.knob.left = left + 'px'; 322 this.slider.knob.top = top + 'px'; 323 if (this.slider.callLeft) { 324 this.color[this.slider.callLeft].call(this.color, left/100); 325 } 326 if (this.slider.callTop) { 327 this.color[this.slider.callTop].call(this.color, top/100); 328 } 329 this.previewColor(); 330 this.element.trigger({ 331 type: 'changeColor', 332 color: this.color 333 }); 334 return false; 335 }, 336 337 mouseup: function(e){ 338 e.stopPropagation(); 339 e.preventDefault(); 340 $(document).off({ 341 mousemove: this.mousemove, 342 mouseup: this.mouseup 343 }); 344 return false; 345 } 346 } 347 348 $.fn.colorpicker = function ( option ) { 349 return this.each(function () { 350 var $this = $(this), 351 data = $this.data('colorpicker'), 352 options = typeof option === 'object' && option; 353 if (!data) { 354 $this.data('colorpicker', (data = new Colorpicker(this, $.extend({}, $.fn.colorpicker.defaults,options)))); 355 } 356 if (typeof option === 'string') data[option](); 357 }); 358 }; 359 360 $.fn.colorpicker.defaults = { 361 }; 362 363 $.fn.colorpicker.Constructor = Colorpicker; 364 365 var CPGlobal = { 366 367 // translate a format from Color object to a string 368 translateFormats: { 369 'rgb': function(){ 370 var rgb = this.color.toRGB(); 371 return 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')'; 372 }, 373 374 'rgba': function(){ 375 var rgb = this.color.toRGB(); 376 return 'rgba('+rgb.r+','+rgb.g+','+rgb.b+','+rgb.a+')'; 377 }, 378 379 'hsl': function(){ 380 var hsl = this.color.toHSL(); 381 return 'hsl('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%)'; 382 }, 383 384 'hsla': function(){ 385 var hsl = this.color.toHSL(); 386 return 'hsla('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%,'+hsl.a+')'; 387 }, 388 389 'hex': function(){ 390 return this.color.toHex(); 391 } 392 }, 393 394 sliders: { 395 saturation: { 396 maxLeft: 100, 397 maxTop: 100, 398 callLeft: 'setSaturation', 399 callTop: 'setLightness' 400 }, 401 402 hue: { 403 maxLeft: 0, 404 maxTop: 100, 405 callLeft: false, 406 callTop: 'setHue' 407 }, 408 409 alpha: { 410 maxLeft: 0, 411 maxTop: 100, 412 callLeft: false, 413 callTop: 'setAlpha' 414 } 415 }, 416 417 // HSBtoRGB from RaphaelJS 418 // https://github.com/DmitryBaranovskiy/raphael/ 419 RGBtoHSB: function (r, g, b, a){ 420 r /= 255; 421 g /= 255; 422 b /= 255; 423 424 var H, S, V, C; 425 V = Math.max(r, g, b); 426 C = V - Math.min(r, g, b); 427 H = (C === 0 ? null : 428 V == r ? (g - b) / C : 429 V == g ? (b - r) / C + 2 : 430 (r - g) / C + 4 431 ); 432 H = ((H + 360) % 6) * 60 / 360; 433 S = C === 0 ? 0 : C / V; 434 return {h: H||1, s: S, b: V, a: a||1}; 435 }, 436 437 HueToRGB: function (p, q, h) { 438 if (h < 0) 439 h += 1; 440 else if (h > 1) 441 h -= 1; 442 443 if ((h * 6) < 1) 444 return p + (q - p) * h * 6; 445 else if ((h * 2) < 1) 446 return q; 447 else if ((h * 3) < 2) 448 return p + (q - p) * ((2 / 3) - h) * 6; 449 else 450 return p; 451 }, 452 453 HSLtoRGB: function (h, s, l, a) 454 { 455 if (s < 0) { 456 s = 0; 457 } 458 var q; 459 if (l <= 0.5) { 460 q = l * (1 + s); 461 } else { 462 q = l + s - (l * s); 463 } 464 465 var p = 2 * l - q; 466 467 var tr = h + (1 / 3); 468 var tg = h; 469 var tb = h - (1 / 3); 470 471 var r = Math.round(CPGlobal.HueToRGB(p, q, tr) * 255); 472 var g = Math.round(CPGlobal.HueToRGB(p, q, tg) * 255); 473 var b = Math.round(CPGlobal.HueToRGB(p, q, tb) * 255); 474 return [r, g, b, a||1]; 475 }, 476 477 // a set of RE's that can match strings and generate color tuples. 478 // from John Resig color plugin 479 // https://github.com/jquery/jquery-color/ 480 stringParsers: [ 481 { 482 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 483 parse: function( execResult ) { 484 return [ 485 execResult[ 1 ], 486 execResult[ 2 ], 487 execResult[ 3 ], 488 execResult[ 4 ] 489 ]; 490 } 491 }, { 492 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 493 parse: function( execResult ) { 494 return [ 495 2.55 * execResult[1], 496 2.55 * execResult[2], 497 2.55 * execResult[3], 498 execResult[ 4 ] 499 ]; 500 } 501 }, { 502 re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, 503 parse: function( execResult ) { 504 return [ 505 parseInt( execResult[ 1 ], 16 ), 506 parseInt( execResult[ 2 ], 16 ), 507 parseInt( execResult[ 3 ], 16 ) 508 ]; 509 } 510 }, { 511 re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, 512 parse: function( execResult ) { 513 return [ 514 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 515 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 516 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 517 ]; 518 } 519 }, { 520 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, 521 space: 'hsla', 522 parse: function( execResult ) { 523 return [ 524 execResult[1]/360, 525 execResult[2] / 100, 526 execResult[3] / 100, 527 execResult[4] 528 ]; 529 } 530 } 531 ], 532 template: '<div class="colorpicker dropdown-menu">'+ 533 '<div class="colorpicker-saturation"><i><b></b></i></div>'+ 534 '<div class="colorpicker-hue"><i></i></div>'+ 535 '<div class="colorpicker-alpha"><i></i></div>'+ 536 '<div class="colorpicker-color"><div /></div>'+ 537 '</div>' 538 }; 539 540 }( window.jQuery )