// License: LGPL-3.0-or-later /* colpick Color Picker Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed under the MIT and GPL licenses For usage and examples: colpick.com/plugin */ var colpick = function () { var tpl = '
#
R
G
B
H
S
B
', defaults = { showEvent: 'click', onShow: function () {}, onBeforeShow: function(){}, onHide: function () {}, onChange: function () {}, onSubmit: function () {}, colorScheme: 'light', color: '3289c7', livePreview: true, flat: false, layout: 'full', submit: 1, submitText: 'OK', height: 156 }, //Fill the inputs of the plugin fillRGBFields = function (hsb, cal) { var rgb = hsbToRgb(hsb); $(cal).data('colpick').fields .eq(1).val(rgb.r).end() .eq(2).val(rgb.g).end() .eq(3).val(rgb.b).end(); }, fillHSBFields = function (hsb, cal) { $(cal).data('colpick').fields .eq(4).val(Math.round(hsb.h)).end() .eq(5).val(Math.round(hsb.s)).end() .eq(6).val(Math.round(hsb.b)).end(); }, fillHexFields = function (hsb, cal) { $(cal).data('colpick').fields.eq(0).val(hsbToHex(hsb)); }, //Set the round selector position setSelector = function (hsb, cal) { $(cal).data('colpick').selector.css('backgroundColor', '#' + hsbToHex({h: hsb.h, s: 100, b: 100})); $(cal).data('colpick').selectorIndic.css({ left: parseInt($(cal).data('colpick').height * hsb.s/100, 10), top: parseInt($(cal).data('colpick').height * (100-hsb.b)/100, 10) }); }, //Set the hue selector position setHue = function (hsb, cal) { $(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h/360, 10)); }, //Set current and new colors setCurrentColor = function (hsb, cal) { $(cal).data('colpick').currentColor.css('backgroundColor', '#' + hsbToHex(hsb)); }, setNewColor = function (hsb, cal) { $(cal).data('colpick').newColor.css('backgroundColor', '#' + hsbToHex(hsb)); }, //Called when the new color is changed change = function (ev) { var cal = $(this).parent().parent(), col; if (this.parentNode.className.indexOf('_hex') > 0) { cal.data('colpick').color = col = hexToHsb(fixHex(this.value)); fillRGBFields(col, cal.get(0)); fillHSBFields(col, cal.get(0)); } else if (this.parentNode.className.indexOf('_hsb') > 0) { cal.data('colpick').color = col = fixHSB({ h: parseInt(cal.data('colpick').fields.eq(4).val(), 10), s: parseInt(cal.data('colpick').fields.eq(5).val(), 10), b: parseInt(cal.data('colpick').fields.eq(6).val(), 10) }); fillRGBFields(col, cal.get(0)); fillHexFields(col, cal.get(0)); } else { cal.data('colpick').color = col = rgbToHsb(fixRGB({ r: parseInt(cal.data('colpick').fields.eq(1).val(), 10), g: parseInt(cal.data('colpick').fields.eq(2).val(), 10), b: parseInt(cal.data('colpick').fields.eq(3).val(), 10) })); fillHexFields(col, cal.get(0)); fillHSBFields(col, cal.get(0)); } setSelector(col, cal.get(0)); setHue(col, cal.get(0)); setNewColor(col, cal.get(0)); cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); }, //Change style on blur and on focus of inputs blur = function (ev) { $(this).parent().removeClass('colpick_focus'); }, focus = function () { $(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus'); $(this).parent().addClass('colpick_focus'); }, //Increment/decrement arrows functions downIncrement = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var field = $(this).parent().find('input').focus(); var current = { el: $(this).parent().addClass('colpick_slider'), max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255), y: ev.pageY, field: field, val: parseInt(field.val(), 10), preview: $(this).parent().parent().data('colpick').livePreview }; $(document).mouseup(current, upIncrement); $(document).mousemove(current, moveIncrement); }, moveIncrement = function (ev) { ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val - ev.pageY + ev.data.y, 10)))); if (ev.data.preview) { change.apply(ev.data.field.get(0), [true]); } return false; }, upIncrement = function (ev) { change.apply(ev.data.field.get(0), [true]); ev.data.el.removeClass('colpick_slider').find('input').focus(); $(document).off('mouseup', upIncrement); $(document).off('mousemove', moveIncrement); return false; }, //Hue slider functions downHue = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var current = { cal: $(this).parent(), y: $(this).offset().top }; $(document).on('mouseup touchend',current,upHue); $(document).on('mousemove touchmove',current,moveHue); var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( current.cal.data('colpick') .fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10)) .get(0), [current.cal.data('colpick').livePreview] ); return false; }, moveHue = function (ev) { var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( ev.data.cal.data('colpick') .fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10)) .get(0), [ev.data.preview] ); return false; }, upHue = function (ev) { fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); $(document).off('mouseup touchend',upHue); $(document).off('mousemove touchmove',moveHue); return false; }, //Color selector functions downSelector = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var current = { cal: $(this).parent(), pos: $(this).offset() }; current.preview = current.cal.data('colpick').livePreview; $(document).on('mouseup touchend',current,upSelector); $(document).on('mousemove touchmove',current,moveSelector); if(ev.type == 'touchstart') { var pageX = ev.originalEvent.changedTouches[0].pageX; var pageY = ev.originalEvent.changedTouches[0].pageY; } else { var pageX = ev.pageX; var pageY = ev.pageY; } change.apply( current.cal.data('colpick').fields .eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end() .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) .get(0), [current.preview] ); return false; }, moveSelector = function (ev) { if(ev.type == 'touchmove') { var pageX = ev.originalEvent.changedTouches[0].pageX; var pageY = ev.originalEvent.changedTouches[0].pageY; } else { var pageX = ev.pageX; var pageY = ev.pageY; } change.apply( ev.data.cal.data('colpick').fields .eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end() .eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10)) .get(0), [ev.data.preview] ); return false; }, upSelector = function (ev) { fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); $(document).off('mouseup touchend',upSelector); $(document).off('mousemove touchmove',moveSelector); return false; }, //Submit button clickSubmit = function (ev) { var cal = $(this).parent(); var col = cal.data('colpick').color; cal.data('colpick').origColor = col; setCurrentColor(col, cal.get(0)); cal.data('colpick').onSubmit(col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el); }, //Show/hide the color picker show = function (ev) { // Prevent the trigger of any direct parent ev.stopPropagation(); var cal = $('#' + $(this).data('colpickId')); cal.data('colpick').onBeforeShow.apply(this, [cal.get(0)]); var pos = $(this).offset(); var top = pos.top + this.offsetHeight; var left = pos.left; var viewPort = getViewport(); var calW = cal.width(); if (left + calW > viewPort.l + viewPort.w) { left -= calW; } cal.css({left: left + 'px', top: top + 'px'}); if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) { cal.show(); } //Hide when user clicks outside $('html').mousedown({cal:cal}, hide); cal.mousedown(function(ev){ev.stopPropagation();}) }, hide = function (ev) { if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) { ev.data.cal.hide(); } $('html').off('mousedown', hide); }, getViewport = function () { var m = document.compatMode == 'CSS1Compat'; return { l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft), w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth) }; }, //Fix the values if the user enters a negative or high value fixHSB = function (hsb) { return { h: Math.min(360, Math.max(0, hsb.h)), s: Math.min(100, Math.max(0, hsb.s)), b: Math.min(100, Math.max(0, hsb.b)) }; }, fixRGB = function (rgb) { return { r: Math.min(255, Math.max(0, rgb.r)), g: Math.min(255, Math.max(0, rgb.g)), b: Math.min(255, Math.max(0, rgb.b)) }; }, fixHex = function (hex) { var len = 6 - hex.length; if (len > 0) { var o = []; for (var i=0; i').attr('style','height:8.333333%; filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+')";'); huebar.append(div); } } else { var stopList = stops.join(','); huebar.attr('style','background:-webkit-linear-gradient(top,'+stopList+'); background: -o-linear-gradient(top,'+stopList+'); background: -ms-linear-gradient(top,'+stopList+'); background:-moz-linear-gradient(top,'+stopList+'); -webkit-linear-gradient(top,'+stopList+'); background:linear-gradient(to bottom,'+stopList+'); '); } cal.find('div.colpick_hue').on('mousedown touchstart',downHue); options.newColor = cal.find('div.colpick_new_color'); options.currentColor = cal.find('div.colpick_current_color'); //Store options and fill with default color cal.data('colpick', options); fillRGBFields(options.color, cal.get(0)); fillHSBFields(options.color, cal.get(0)); fillHexFields(options.color, cal.get(0)); setHue(options.color, cal.get(0)); setSelector(options.color, cal.get(0)); setCurrentColor(options.color, cal.get(0)); setNewColor(options.color, cal.get(0)); //Append to body if flat=false, else show in place if (options.flat) { cal.appendTo(this).show(); cal.css({ position: 'relative', display: 'block' }); } else { cal.appendTo(document.body); $(this).on(options.showEvent, show); cal.css({ position:'absolute' }); } } }); }, //Shows the picker showPicker: function() { return this.each( function () { if ($(this).data('colpickId')) { show.apply(this); } }); }, //Hides the picker hidePicker: function() { return this.each( function () { if ($(this).data('colpickId')) { $('#' + $(this).data('colpickId')).hide(); } }); }, //Sets a color as new and current (default) setColor: function(col, setCurrent) { setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent; if (typeof col == 'string') { col = hexToHsb(col); } else if (col.r != undefined && col.g != undefined && col.b != undefined) { col = rgbToHsb(col); } else if (col.h != undefined && col.s != undefined && col.b != undefined) { col = fixHSB(col); } else { return this; } return this.each(function(){ if ($(this).data('colpickId')) { var cal = $('#' + $(this).data('colpickId')); cal.data('colpick').color = col; cal.data('colpick').origColor = col; fillRGBFields(col, cal.get(0)); fillHSBFields(col, cal.get(0)); fillHexFields(col, cal.get(0)); setHue(col, cal.get(0)); setSelector(col, cal.get(0)); setNewColor(col, cal.get(0)); cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); if(setCurrent) { setCurrentColor(col, cal.get(0)); } } }); } }; }(); //Color space convertions var hexToRgb = function (hex) { var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)}; }; var hexToHsb = function (hex) { return rgbToHsb(hexToRgb(hex)); }; var rgbToHsb = function (rgb) { var hsb = {h: 0, s: 0, b: 0}; var min = Math.min(rgb.r, rgb.g, rgb.b); var max = Math.max(rgb.r, rgb.g, rgb.b); var delta = max - min; hsb.b = max; hsb.s = max != 0 ? 255 * delta / max : 0; if (hsb.s != 0) { if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta; else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta; else hsb.h = 4 + (rgb.r - rgb.g) / delta; } else hsb.h = -1; hsb.h *= 60; if (hsb.h < 0) hsb.h += 360; hsb.s *= 100/255; hsb.b *= 100/255; return hsb; }; var hsbToRgb = function (hsb) { var rgb = {}; var h = hsb.h; var s = hsb.s*255/100; var v = hsb.b*255/100; if(s == 0) { rgb.r = rgb.g = rgb.b = v; } else { var t1 = v; var t2 = (255-s)*v/255; var t3 = (t1-t2)*(h%60)/60; if(h==360) h = 0; if(h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3} else if(h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3} else if(h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3} else if(h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3} else if(h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3} else if(h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3} else {rgb.r=0; rgb.g=0; rgb.b=0} } return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)}; }; var rgbToHex = function (rgb) { var hex = [ rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16) ]; $.each(hex, function (nr, val) { if (val.length == 1) { hex[nr] = '0' + val; } }); return hex.join(''); }; var hsbToHex = function (hsb) { return rgbToHex(hsbToRgb(hsb)); }; $.fn.extend({ colpick: colpick.init, colpickHide: colpick.hidePicker, colpickShow: colpick.showPicker, colpickSetColor: colpick.setColor }); $.extend({ colpick:{ rgbToHex: rgbToHex, rgbToHsb: rgbToHsb, hsbToHex: hsbToHex, hsbToRgb: hsbToRgb, hexToHsb: hexToHsb, hexToRgb: hexToRgb } });