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 )