/*jshint undef: true, unused:true, browser:true */ /*global jQuery: true, tinycolor: false */ /*!========================================================================= * jQuery Color Picker Sliders * v3.1.0 * * An advanced responsive color selector with color swatches and support for * human perceived lightness. Works in all modern browsers and on touch devices. * * https://github.com/istvan-meszaros/css-colorpickersliders * http://www.virtuosoft.eu/code/css-colorpickersliders/ * * Copyright 2013 István Ujj-Mészáros * * Thanks for the contributors: * imaguiraga - https://github.com/imaguiraga * balmasich - https://github.com/balmasich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Requirements: * * TinyColor: https://github.com/bgrins/TinyColor * * Using color math algorithms from EasyRGB Web site: * http://www.easyrgb.com/index.php?X=MATH * ====================================================================== */ (function($) { "use strict"; $.fn.ColorPickerSliders = function(options) { return this.each(function(i, el) { var alreadyinitialized = false, settings, triggerelement = $(this), container, elements, swatches, MAXLIGHT = 101, // 101 needed for bright colors (maybe due to rounding errors) dragTarget = false, lastUpdateTime = 0, color = { tiny: null, hsla: null, rgba: null, cielch: null }, MAXVALIDCHROMA = 144; // maximum valid chroma value found convertible to rgb (blue) setTimeout(init,20); function init() { if (alreadyinitialized) { return; } alreadyinitialized = true; _initSettings(); _buildHtml(); _initElements(); if (triggerelement.is("input")) { color.tiny = tinycolor(triggerelement.val()); if (!color.tiny.format) { color.tiny = tinycolor(settings.color); } } else { color.tiny = tinycolor(settings.color); } color.hsla = color.tiny.toHsl(); color.rgba = color.tiny.toRgb(); color.cielch = $.fn.ColorPickerSliders.rgb2lch(color.rgba); _renderSwatches(); _bindEvents(); _updateAllElements(); } function updateColor(newcolor, disableinputupdate) { var updatedcolor = tinycolor(newcolor); if (updatedcolor.format) { container.removeClass("cp-unconvertible-cie-color"); color.tiny = updatedcolor; color.hsla = updatedcolor.toHsl(); color.rgba = updatedcolor.toRgb(); color.cielch = $.fn.ColorPickerSliders.rgb2lch(color.rgba); _updateAllElements(disableinputupdate); return true; } else { return false; } } function showPopup() { $('.cp-container.cp-popup').hide(); var viewportwidth = $(window).width(), offset = triggerelement.offset(), popuporiginalwidth; popuporiginalwidth = container.data('popup-original-width'); if (typeof popuporiginalwidth === "undefined") { popuporiginalwidth = container.outerWidth(); container.data('popup-original-width', popuporiginalwidth); } if (offset.left + popuporiginalwidth + 12 <= viewportwidth) { container.css('left', offset.left).width(popuporiginalwidth); } else if (popuporiginalwidth <= viewportwidth) { container.css('left', viewportwidth - popuporiginalwidth - 12).width(popuporiginalwidth); } else { container.css('left', 0).width(viewportwidth - 12); } container.css('top', offset.top + triggerelement.outerHeight()).show(); } function hidePopup() { container.hide(); } function _initSettings() { settings = $.extend({ color: 'hsl(342, 52%, 70%)', swatches: ['FFFFFF', 'C0C0C0', '808080', '000000', 'FF0000', '800000', 'FFFF00', '808000', '00FF00', '008000', '00FFFF', '008080', '0000FF', '000080', 'FF00FF', '800080'], customswatches: 'colorpickkersliders', // false or a grop name connectedinput: false, // can be a jquery object or a selector flat: false, disableautopopup: false, updateinterval: 30, // update interval of the sliders while in drag (ms) previewontriggerelement: true, previewcontrasttreshold: 15, previewformat: 'rgb', // rgb/hsl/hex erroneousciecolormarkers: true, invalidcolorsopacity: 1, // everything below 1 causes slightly slower responses finercierangeedges: true, // can be disabled for faster responses titleswatchesadd: "Add color to swatches", titleswatchesremove: "Remove color from swatches", titleswatchesreset: "Reset to default swatches", order: {}, labels: {}, onchange: function() { } }, options); if (options.hasOwnProperty('order')) { settings.order = $.extend({ opacity: false, hsl: false, rgb: false, cie: false, preview: false }, options.order); } else { settings.order = { opacity: 0, hsl: 1, rgb: 2, cie: 3, // cie sliders can increase response time of all sliders! preview: 4 }; } if (!options.hasOwnProperty('labels')) { options.labels = {}; } settings.labels = $.extend({ hslhue: 'Hue', hslsaturation: 'Saturation', hsllightness: 'Lightness', rgbred: 'RGB-Red', rgbgreen: 'RGB-Green', rgbblue: 'RGB-Blue', cielightness: 'CIE-Lightness', ciechroma: 'CIE-Chroma', ciehue: 'CIE-hue', opacity: 'Opacity', preview: 'Preview' }, options.labels); // force preview when browser doesn't support css gradients if ((!settings.order.hasOwnProperty('preview') || settings.order.preview === false) && !$.fn.ColorPickerSliders.gradientSupported()) { settings.order.preview = 10; } } function _buildHtml() { var sliders = [], color_picker_html = ''; if (settings.order.opacity !== false) { sliders[settings.order.opacity] = '
' + settings.labels.opacity + '
'; } if (settings.order.hsl !== false) { sliders[settings.order.hsl] = '
' + settings.labels.hslhue + '
' + settings.labels.hslsaturation + '
' + settings.labels.hsllightness + '
'; } if (settings.order.rgb !== false) { sliders[settings.order.rgb] = '
' + settings.labels.rgbred + '
' + settings.labels.rgbgreen + '
' + settings.labels.rgbblue + '
'; } if (settings.order.cie !== false) { sliders[settings.order.cie] = '
' + settings.labels.cielightness + '
' + settings.labels.ciechroma + '
' + settings.labels.ciehue + '
'; } if (settings.order.preview !== false) { sliders[settings.order.preview] = '
'; } color_picker_html += '
'; for (var i = 0; i < sliders.length; i++) { if (typeof sliders[i] === "undefined") { continue; } color_picker_html += sliders[i]; } color_picker_html += '
'; if (settings.swatches) { color_picker_html += '
'; } if (settings.flat) { if (triggerelement.is("input")) { container = $('
').insertAfter(triggerelement); } else { container = $('
'); triggerelement.append(container); } } else { container = $('
').appendTo('body'); } container.append(color_picker_html); if (settings.connectedinput instanceof jQuery) { settings.connectedinput.add(triggerelement); } else if (settings.connectedinput === false) { settings.connectedinput = triggerelement; } else { settings.connectedinput = $(settings.connectedinput).add(triggerelement); } if (!settings.flat) { container.addClass('cp-popup'); } var preview = settings.connectedinput.closest('.style-choice').find('.preview'); preview = preview.length ? preview : settings.connectedinput.closest('.section-stream').find('.preview') container.data('preview', preview); container.data('input', settings.connectedinput); container.data('prop', settings.connectedinput.attr('id')); } function _initElements() { elements = { connectedinput: false, actualswatch: false, swatchescontainer: $(".cp-swatches", container), swatches: $(".cp-swatches ul", container), swatches_add: $(".cp-swatches button.add", container), swatches_remove: $(".cp-swatches button.remove", container), swatches_reset: $(".cp-swatches button.reset", container), all_sliders: $(".cp-sliders, .cp-preview input", container), sliders: { hue: $(".cp-hslhue span", container), hue_marker: $(".cp-hslhue .cp-marker", container), saturation: $(".cp-hslsaturation span", container), saturation_marker: $(".cp-hslsaturation .cp-marker", container), lightness: $(".cp-hsllightness span", container), lightness_marker: $(".cp-hsllightness .cp-marker", container), opacity: $(".cp-opacity span", container), opacity_marker: $(".cp-opacity .cp-marker", container), red: $(".cp-rgbred span", container), red_marker: $(".cp-rgbred .cp-marker", container), green: $(".cp-rgbgreen span", container), green_marker: $(".cp-rgbgreen .cp-marker", container), blue: $(".cp-rgbblue span", container), blue_marker: $(".cp-rgbblue .cp-marker", container), cielightness: $(".cp-cielightness span", container), cielightness_marker: $(".cp-cielightness .cp-marker", container), ciechroma: $(".cp-ciechroma span", container), ciechroma_marker: $(".cp-ciechroma .cp-marker", container), ciehue: $(".cp-ciehue span", container), ciehue_marker: $(".cp-ciehue .cp-marker", container), preview: $(".cp-preview input", container) } }; if (settings.connectedinput) { if (settings.connectedinput instanceof jQuery) { elements.connectedinput = settings.connectedinput; } else { elements.connectedinput = $(settings.connectedinput); } } if (!settings.customswatches) { elements.swatches_add.hide(); elements.swatches_remove.hide(); elements.swatches_reset.hide(); } } function destroyColorPicker() { if (container instanceof jQuery) { hidePopup(); container.remove(); alreadyinitialized = false; } } function resetColorPicker() { init(); } function _bindEvents() { triggerelement.on('colorpickersliders.destroy', function() { destroyColorPicker(); }); triggerelement.on('colorpickersliders.reset', function() { resetColorPicker(); }); triggerelement.on('colorpickersliders.updateColor', function(e, newcolor) { updateColor(newcolor); }); triggerelement.on('colorpickersliders.showPopup', function() { showPopup(); }); triggerelement.on('colorpickersliders.hidePopup', function() { hidePopup(); }); $(document).on("colorpickersliders.changeswatches", function() { _renderSwatches(); }); if (!settings.flat && !settings.disableautopopup) { // we need tabindex defined to be focusable if (typeof triggerelement.attr("tabindex") === "undefined") { triggerelement.attr("tabindex", -1); } // buttons doesn't get focus in webkit browsers // https://bugs.webkit.org/show_bug.cgi?id=22261 // and only input and button are focusable on iPad // so it is safer to register click on any other than inputs if (!triggerelement.is("input")) { $(triggerelement).on("click", function(ev) { showPopup(); ev.stopPropagation(); }); $(document).on("click", function() { hidePopup(); }); } $(triggerelement).on("focus", function(ev) { showPopup(); ev.stopPropagation(); }); $(triggerelement).on("blur", function(ev) { hidePopup(); ev.stopPropagation(); }); container.on("touchstart mousedown", function(ev) { ev.preventDefault(); ev.stopPropagation(); return false; }); } container.on("contextmenu", function(ev) { ev.preventDefault(); return false; }); elements.swatches.on("click", "li span", function(ev) { var color = $(this).css("background-color"); updateColor(color); ev.preventDefault(); }); elements.swatches_add.on("click", function(ev) { _addCurrentColorToSwatches(); ev.preventDefault(); }); elements.swatches_remove.on("click", function(ev) { _removeActualColorFromSwatches(); ev.preventDefault(); }); elements.swatches_reset.on("click", function(ev) { _resetSwatches(); ev.preventDefault(); }); elements.sliders.hue.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "hue"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('hsla', 'h', 3.6 * percent); _updateAllElements(); }); elements.sliders.saturation.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "saturation"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('hsla', 's', percent / 100); _updateAllElements(); }); elements.sliders.lightness.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "lightness"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('hsla', 'l', percent / 100); _updateAllElements(); }); elements.sliders.opacity.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "opacity"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('hsla', 'a', percent / 100); _updateAllElements(); }); elements.sliders.red.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "red"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('rgba', 'r', 2.55 * percent); _updateAllElements(); }); elements.sliders.green.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "green"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('rgba', 'g', 2.55 * percent); _updateAllElements(); }); elements.sliders.blue.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "blue"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('rgba', 'b', 2.55 * percent); _updateAllElements(); }); elements.sliders.cielightness.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "cielightness"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('cielch', 'l', (MAXLIGHT / 100) * percent); _updateAllElements(); }); elements.sliders.ciechroma.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "ciechroma"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('cielch', 'c', (MAXVALIDCHROMA / 100) * percent); _updateAllElements(); }); elements.sliders.ciehue.parent().on("touchstart mousedown", function(ev) { ev.preventDefault(); if (ev.which > 1) { return; } dragTarget = "ciehue"; var percent = _updateMarkerPosition(dragTarget, ev); _updateColorsProperty('cielch', 'h', 3.6 * percent); _updateAllElements(); }); elements.sliders.preview.on("click", function() { this.select(); }); $(document).on("touchmove mousemove", function(ev) { if (!dragTarget) { return; } var percent = _updateMarkerPosition(dragTarget, ev); switch (dragTarget) { case "hue": _updateColorsProperty('hsla', 'h', 3.6 * percent); break; case "saturation": _updateColorsProperty('hsla', 's', percent / 100); break; case "lightness": _updateColorsProperty('hsla', 'l', percent / 100); break; case "opacity": _updateColorsProperty('hsla', 'a', percent / 100); break; case "red": _updateColorsProperty('rgba', 'r', 2.55 * percent); break; case "green": _updateColorsProperty('rgba', 'g', 2.55 * percent); break; case "blue": _updateColorsProperty('rgba', 'b', 2.55 * percent); break; case "cielightness": _updateColorsProperty('cielch', 'l', (MAXLIGHT / 100) * percent); break; case "ciechroma": _updateColorsProperty('cielch', 'c', (MAXVALIDCHROMA / 100) * percent); break; case "ciehue": _updateColorsProperty('cielch', 'h', 3.6 * percent); break; } _updateAllElements(); ev.preventDefault(); }); $(document).on("touchend mouseup", function(ev) { if (ev.which > 1) { return; } if (dragTarget) { dragTarget = false; ev.preventDefault(); } }); if (elements.connectedinput) { elements.connectedinput.on('keyup change', function() { var $input = $(this); updateColor($input.val(), true); }); } } function _parseCustomSwatches() { swatches = []; for (var i = 0; i < settings.swatches.length; i++) { var color = tinycolor(settings.swatches[i]); if (color.format) { swatches.push(color.toRgbString()); } } } function _renderSwatches() { if (!settings.swatches) { return; } if (settings.customswatches) { var customswatches = false; try { customswatches = JSON.parse(localStorage.getItem("swatches-" + settings.customswatches)); } catch (err) { } if (customswatches) { swatches = customswatches; } else { _parseCustomSwatches(); } } else { _parseCustomSwatches(); } if (swatches instanceof Array) { elements.swatches.html(""); for (var i = 0; i < swatches.length; i++) { var color = tinycolor(swatches[i]); if (color.format) { elements.swatches.append($("
  • ").append($("").css("background-color", color.toRgbString()))); } } } _findActualColorsSwatch(); } function _findActualColorsSwatch() { var found = false; $("span", elements.swatches).filter(function() { var swatchcolor = $(this).css('background-color'); swatchcolor = tinycolor(swatchcolor); swatchcolor.alpha = Math.round(swatchcolor.alpha * 100) / 100; if (swatchcolor.toRgbString() === color.tiny.toRgbString()) { found = true; var currentswatch = $(this).parent(); if (!currentswatch.is(elements.actualswatch)) { if (elements.actualswatch) { elements.actualswatch.removeClass("actual"); } elements.actualswatch = currentswatch; currentswatch.addClass("actual"); } } }); if (!found) { if (elements.actualswatch) { elements.actualswatch.removeClass("actual"); elements.actualswatch = false; } } if (elements.actualswatch) { elements.swatches_add.prop("disabled", true); elements.swatches_remove.prop("disabled", false); } else { elements.swatches_add.prop("disabled", false); elements.swatches_remove.prop("disabled", true); } } function _storeSwatches() { localStorage.setItem("swatches-" + settings.customswatches, JSON.stringify(swatches)); } function _addCurrentColorToSwatches() { swatches.unshift(color.tiny.toRgbString()); _storeSwatches(); $(document).trigger("colorpickersliders.changeswatches"); } function _removeActualColorFromSwatches() { var index = swatches.indexOf(color.tiny.toRgbString()); if (index !== -1) { swatches.splice(index, 1); _storeSwatches(); $(document).trigger("colorpickersliders.changeswatches"); } } function _resetSwatches() { if (confirm("Do you really want to reset the swatches? All customizations will be lost!")) { _parseCustomSwatches(); _storeSwatches(); $(document).trigger("colorpickersliders.changeswatches"); } } function _updateColorsProperty(format, property, value) { switch (format) { case 'hsla': color.hsla[property] = value; color.tiny = tinycolor({h: color.hsla.h, s: color.hsla.s, l: color.hsla.l, a: color.hsla.a}); color.rgba = color.tiny.toRgb(); color.cielch = $.fn.ColorPickerSliders.rgb2lch(color.rgba); container.removeClass("cp-unconvertible-cie-color"); break; case 'rgba': color.rgba[property] = value; color.tiny = tinycolor({r: color.rgba.r, g: color.rgba.g, b: color.rgba.b, a: color.hsla.a}); color.hsla = color.tiny.toHsl(); color.cielch = $.fn.ColorPickerSliders.rgb2lch(color.rgba); container.removeClass("cp-unconvertible-cie-color"); break; case 'cielch': color.cielch[property] = value; color.rgba = $.fn.ColorPickerSliders.lch2rgb(color.cielch); color.tiny = tinycolor(color.rgba); color.hsla = color.tiny.toHsl(); if (settings.erroneousciecolormarkers) { if (color.rgba.isok) { container.removeClass("cp-unconvertible-cie-color"); } else { container.addClass("cp-unconvertible-cie-color"); } } break; } } function _updateMarkerPosition(slidername, ev) { var percent = $.fn.ColorPickerSliders.calculateEventPositionPercentage(ev, elements.sliders[slidername]); elements.sliders[slidername + '_marker'].data("position", percent); return percent; } var updateAllElementsTimeout; function _updateAllElementsTimer(disableinputupdate) { updateAllElementsTimeout = setTimeout(function() { _updateAllElements(disableinputupdate); }, settings.updateinterval); } function _updateAllElements(disableinputupdate) { clearTimeout(updateAllElementsTimeout); $(document).trigger('colorpickersliders._updateAllElements'); if (Date.now() - lastUpdateTime < settings.updateinterval) { _updateAllElementsTimer(disableinputupdate); return; } //console.log('_updateAllElements') if (typeof disableinputupdate === "undefined") { disableinputupdate = false; } lastUpdateTime = Date.now(); if (settings.order.opacity !== false) { _renderOpacity(); } if (settings.order.hsl !== false) { _renderHue(); _renderSaturation(); _renderLightness(); } if (settings.order.rgb !== false) { _renderRed(); _renderGreen(); _renderBlue(); } if (settings.order.cie !== false) { _renderCieLightness(); _renderCieChroma(); _renderCieHue(); } if (settings.order.preview !== false) { _renderPreview(); } if (!disableinputupdate) { _updateConnectedInput(); } if ((100 - color.cielch.l) * color.cielch.a < settings.previewcontrasttreshold) { elements.all_sliders.css('color', '#000'); if (settings.previewontriggerelement) { triggerelement.css('background', color.tiny.toRgbString()).css('color', '#000'); } } else { elements.all_sliders.css('color', '#fff'); if (settings.previewontriggerelement) { triggerelement.css('background', color.tiny.toRgbString()).css('color', '#fff'); } } _findActualColorsSwatch(); settings.onchange(container, color); } function _updateConnectedInput() { if (elements.connectedinput) { elements.connectedinput.each(function(index, element) { var $element = $(element); switch ($element.data('color-format')) { case 'hex': $element.val(color.tiny.toHexString()); break; case 'hsl': $element.val(color.tiny.toHslString()); break; case 'rgb': /* falls through */ default: $element.val(color.tiny.toRgbString()); break; } }); } } function _renderHue() { $.fn.ColorPickerSliders.setGradient(elements.sliders.hue, $.fn.ColorPickerSliders.getScaledGradientStops(color.hsla, "h", 0, 360, 7)); elements.sliders.hue_marker.css("left", color.hsla.h / 360 * 100 + "%"); } function _renderSaturation() { $.fn.ColorPickerSliders.setGradient(elements.sliders.saturation, $.fn.ColorPickerSliders.getScaledGradientStops(color.hsla, "s", 0, 1, 2)); elements.sliders.saturation_marker.css("left", color.hsla.s * 100 + "%"); } function _renderLightness() { $.fn.ColorPickerSliders.setGradient(elements.sliders.lightness, $.fn.ColorPickerSliders.getScaledGradientStops(color.hsla, "l", 0, 1, 3)); elements.sliders.lightness_marker.css("left", color.hsla.l * 100 + "%"); } function _renderOpacity() { $.fn.ColorPickerSliders.setGradient(elements.sliders.opacity, $.fn.ColorPickerSliders.getScaledGradientStops(color.hsla, "a", 0, 1, 2)); elements.sliders.opacity_marker.css("left", color.hsla.a * 100 + "%"); } function _renderRed() { $.fn.ColorPickerSliders.setGradient(elements.sliders.red, $.fn.ColorPickerSliders.getScaledGradientStops(color.rgba, "r", 0, 255, 2)); elements.sliders.red_marker.css("left", color.rgba.r / 255 * 100 + "%"); } function _renderGreen() { $.fn.ColorPickerSliders.setGradient(elements.sliders.green, $.fn.ColorPickerSliders.getScaledGradientStops(color.rgba, "g", 0, 255, 2)); elements.sliders.green_marker.css("left", color.rgba.g / 255 * 100 + "%"); } function _renderBlue() { $.fn.ColorPickerSliders.setGradient(elements.sliders.blue, $.fn.ColorPickerSliders.getScaledGradientStops(color.rgba, "b", 0, 255, 2)); elements.sliders.blue_marker.css("left", color.rgba.b / 255 * 100 + "%"); } function _extendCieGradientStops(gradientstops, property) { if (settings.invalidcolorsopacity === 1 || !settings.finercierangeedges) { return gradientstops; } gradientstops.sort(function(a, b) { return a.position - b.position; }); var tmparray = []; for (var i = 1; i < gradientstops.length; i++) { if (gradientstops[i].isok !== gradientstops[i - 1].isok) { var steps = Math.round(gradientstops[i].position) - Math.round(gradientstops[i - 1].position), extendedgradientstops = $.fn.ColorPickerSliders.getScaledGradientStops(gradientstops[i].rawcolor, property, gradientstops[i - 1].rawcolor[property], gradientstops[i].rawcolor[property], steps, settings.invalidcolorsopacity, gradientstops[i - 1].position, gradientstops[i].position); for (var j = 0; j < extendedgradientstops.length; j++) { if (extendedgradientstops[j].isok !== gradientstops[i - 1].isok) { tmparray.push(extendedgradientstops[j]); if (j > 0) { tmparray.push(extendedgradientstops[j - 1]); } break; } } } } return $.merge(tmparray, gradientstops); } function _renderCieLightness() { var gradientstops = $.fn.ColorPickerSliders.getScaledGradientStops(color.cielch, "l", 0, 100, 10, settings.invalidcolorsopacity); gradientstops = _extendCieGradientStops(gradientstops, "l"); $.fn.ColorPickerSliders.setGradient(elements.sliders.cielightness, gradientstops); elements.sliders.cielightness_marker.css("left", color.cielch.l / MAXLIGHT * 100 + "%"); } function _renderCieChroma() { var gradientstops = $.fn.ColorPickerSliders.getScaledGradientStops(color.cielch, "c", 0, MAXVALIDCHROMA, 5, settings.invalidcolorsopacity); gradientstops = _extendCieGradientStops(gradientstops, "c"); $.fn.ColorPickerSliders.setGradient(elements.sliders.ciechroma, gradientstops); elements.sliders.ciechroma_marker.css("left", color.cielch.c / MAXVALIDCHROMA * 100 + "%"); } function _renderCieHue() { var gradientstops = $.fn.ColorPickerSliders.getScaledGradientStops(color.cielch, "h", 0, 360, 28, settings.invalidcolorsopacity); gradientstops = _extendCieGradientStops(gradientstops, "h"); $.fn.ColorPickerSliders.setGradient(elements.sliders.ciehue, gradientstops); elements.sliders.ciehue_marker.css("left", color.cielch.h / 360 * 100 + "%"); } function _renderPreview() { elements.sliders.preview.css("background", $.fn.ColorPickerSliders.csscolor(color.rgba)); var colorstring; switch (settings.previewformat) { case 'hex': colorstring = color.tiny.toHexString(); break; case 'hsl': colorstring = color.tiny.toHslString(); break; case 'rgb': /* falls through */ default: colorstring = color.tiny.toRgbString(); break; } elements.sliders.preview.val(colorstring); } }); }; $.fn.ColorPickerSliders.getEventCoordinates = function(ev) { if (typeof ev.pageX !== "undefined") { return { pageX: ev.originalEvent.pageX, pageY: ev.originalEvent.pageY }; } else if (typeof ev.originalEvent.touches !== "undefined") { return { pageX: ev.originalEvent.touches[0].pageX, pageY: ev.originalEvent.touches[0].pageY }; } }; $.fn.ColorPickerSliders.calculateEventPositionPercentage = function(ev, containerElement) { var c = $.fn.ColorPickerSliders.getEventCoordinates(ev); var xsize = containerElement.width(), offsetX = c.pageX - containerElement.offset().left; var percent = offsetX / xsize * 100; if (percent < 0) { percent = 0; } if (percent > 100) { percent = 100; } return percent; }; $.fn.ColorPickerSliders.gradientSupported = function() { var testelement = document.createElement('detectGradientSupport').style; testelement.backgroundImage = "linear-gradient(left top, #9f9, white)"; testelement.backgroundImage = "-o-linear-gradient(left top, #9f9, white)"; testelement.backgroundImage = "-moz-linear-gradient(left top, #9f9, white)"; testelement.backgroundImage = "-webkit-linear-gradient(left top, #9f9, white)"; testelement.backgroundImage = "-ms-linear-gradient(left top, #9f9, white)"; testelement.backgroundImage = "-webkit-gradient(linear, left top, right bottom, from(#9f9), to(white))"; if (testelement.backgroundImage.indexOf("gradient") === -1) { return false; } else { return true; } }; $.fn.ColorPickerSliders.getScaledGradientStops = function(color, scalableproperty, minvalue, maxvalue, steps, invalidcolorsopacity, minposition, maxposition) { if (typeof invalidcolorsopacity === "undefined") { invalidcolorsopacity = 1; } if (typeof minposition === "undefined") { minposition = 0; } if (typeof maxposition === "undefined") { maxposition = 100; } var gradientStops = [], diff = maxvalue - minvalue, isok = true; for (var i = 0; i < steps; ++i) { var currentstage = i / (steps - 1), modifiedcolor = $.fn.ColorPickerSliders.modifyColor(color, scalableproperty, currentstage * diff + minvalue), csscolor; if (invalidcolorsopacity < 1) { var stagergb = $.fn.ColorPickerSliders.lch2rgb(modifiedcolor, invalidcolorsopacity); isok = stagergb.isok; csscolor = $.fn.ColorPickerSliders.csscolor(stagergb, invalidcolorsopacity); } else { csscolor = $.fn.ColorPickerSliders.csscolor(modifiedcolor, invalidcolorsopacity); } gradientStops[i] = { color: csscolor, position: currentstage * (maxposition - minposition) + minposition, isok: isok, rawcolor: modifiedcolor }; } return gradientStops; }; $.fn.ColorPickerSliders.setGradient = function(element, gradientstops) { gradientstops.sort(function(a, b) { return a.position - b.position; }); var gradientstring = "", oldwebkitgradientstring = "", noprefix = "linear-gradient(to right", webkit = "-webkit-linear-gradient(left", oldwebkit = "-webkit-gradient(linear, left top, right top"; for (var i = 0; i < gradientstops.length; i++) { var el = gradientstops[i]; gradientstring += "," + el.color + " " + el.position + "%"; oldwebkitgradientstring += ",color-stop(" + el.position + "%," + el.color + ")"; } gradientstring += ")"; oldwebkitgradientstring += ")"; oldwebkit += oldwebkitgradientstring; webkit += gradientstring; noprefix += gradientstring; element.css("background", oldwebkit); element.css("background", webkit); element.css("background", noprefix); }; $.fn.ColorPickerSliders.isGoodRgb = function(rgb) { // the default acceptable values are out of 0..255 due to // rounding errors with yellow and blue colors (258, -1) var maxacceptable = 258; var minacceptable = -1; if (rgb.r > maxacceptable || rgb.g > maxacceptable || rgb.b > maxacceptable || rgb.r < minacceptable || rgb.g < minacceptable || rgb.b < minacceptable) { return false; } else { rgb.r = Math.min(255, rgb.r); rgb.g = Math.min(255, rgb.g); rgb.b = Math.min(255, rgb.b); rgb.r = Math.max(0, rgb.r); rgb.g = Math.max(0, rgb.g); rgb.b = Math.max(0, rgb.b); return true; } }; $.fn.ColorPickerSliders.rgb2lch = function(rgb) { var lch = $.fn.ColorPickerSliders.CIELab2CIELCH($.fn.ColorPickerSliders.XYZ2CIELab($.fn.ColorPickerSliders.rgb2XYZ(rgb))); if (rgb.hasOwnProperty('a')) { lch.a = rgb.a; } return lch; }; $.fn.ColorPickerSliders.lch2rgb = function(lch, invalidcolorsopacity) { if (typeof invalidcolorsopacity === "undefined") { invalidcolorsopacity = 1; } var rgb = $.fn.ColorPickerSliders.XYZ2rgb($.fn.ColorPickerSliders.CIELab2XYZ($.fn.ColorPickerSliders.CIELCH2CIELab(lch))); if ($.fn.ColorPickerSliders.isGoodRgb(rgb)) { if (lch.hasOwnProperty('a')) { rgb.a = lch.a; } rgb.isok = true; return rgb; } var tmp = $.extend({}, lch), lastbadchroma = tmp.c, lastgoodchroma = -1, loops = 0; do { ++loops; tmp.c = lastgoodchroma + ((lastbadchroma - lastgoodchroma) / 2); rgb = $.fn.ColorPickerSliders.XYZ2rgb($.fn.ColorPickerSliders.CIELab2XYZ($.fn.ColorPickerSliders.CIELCH2CIELab(tmp))); if ($.fn.ColorPickerSliders.isGoodRgb(rgb)) { lastgoodchroma = tmp.c; } else { lastbadchroma = tmp.c; } } while (Math.abs(lastbadchroma - lastgoodchroma) > 0.9 && loops < 100); if (lch.hasOwnProperty('a')) { rgb.a = lch.a; } rgb.r = Math.max(0, rgb.r); rgb.g = Math.max(0, rgb.g); rgb.b = Math.max(0, rgb.b); rgb.r = Math.min(255, rgb.r); rgb.g = Math.min(255, rgb.g); rgb.b = Math.min(255, rgb.b); if (invalidcolorsopacity < 1) { if (rgb.hasOwnProperty('a')) { rgb.a = rgb.a * invalidcolorsopacity; } else { rgb.a = invalidcolorsopacity; } } rgb.isok = false; return rgb; }; $.fn.ColorPickerSliders.modifyColor = function(color, property, value) { var modifiedcolor = $.extend({}, color); if (!color.hasOwnProperty(property)) { throw("Missing color property: " + property); } modifiedcolor[property] = value; return modifiedcolor; }; $.fn.ColorPickerSliders.csscolor = function(color, invalidcolorsopacity) { if (typeof invalidcolorsopacity === "undefined") { invalidcolorsopacity = 1; } var $return = false, tmpcolor = $.extend({}, color); if (tmpcolor.hasOwnProperty('c')) { // CIE-LCh tmpcolor = $.fn.ColorPickerSliders.lch2rgb(tmpcolor, invalidcolorsopacity); } if (tmpcolor.hasOwnProperty('h')) { // HSL $return = "hsla(" + tmpcolor.h + "," + tmpcolor.s * 100 + "%," + tmpcolor.l * 100 + "%," + tmpcolor.a + ")"; } if (tmpcolor.hasOwnProperty('r')) { // RGB if (tmpcolor.a < 1) { $return = "rgba(" + Math.round(tmpcolor.r) + "," + Math.round(tmpcolor.g) + "," + Math.round(tmpcolor.b) + "," + tmpcolor.a + ")"; } else { $return = "rgb(" + Math.round(tmpcolor.r) + "," + Math.round(tmpcolor.g) + "," + Math.round(tmpcolor.b) + ")"; } } return $return; }; $.fn.ColorPickerSliders.rgb2XYZ = function(rgb) { var XYZ = {}; var r = (rgb.r / 255); var g = (rgb.g / 255); var b = (rgb.b / 255); if (r > 0.04045) { r = Math.pow(((r + 0.055) / 1.055), 2.4); } else { r = r / 12.92; } if (g > 0.04045) { g = Math.pow(((g + 0.055) / 1.055), 2.4); } else { g = g / 12.92; } if (b > 0.04045) { b = Math.pow(((b + 0.055) / 1.055), 2.4); } else { b = b / 12.92; } r = r * 100; g = g * 100; b = b * 100; // Observer = 2°, Illuminant = D65 XYZ.x = r * 0.4124 + g * 0.3576 + b * 0.1805; XYZ.y = r * 0.2126 + g * 0.7152 + b * 0.0722; XYZ.z = r * 0.0193 + g * 0.1192 + b * 0.9505; return XYZ; }; $.fn.ColorPickerSliders.XYZ2CIELab = function(XYZ) { var CIELab = {}; // Observer = 2°, Illuminant = D65 var X = XYZ.x / 95.047; var Y = XYZ.y / 100.000; var Z = XYZ.z / 108.883; if (X > 0.008856) { X = Math.pow(X, 0.333333333); } else { X = 7.787 * X + 0.137931034; } if (Y > 0.008856) { Y = Math.pow(Y, 0.333333333); } else { Y = 7.787 * Y + 0.137931034; } if (Z > 0.008856) { Z = Math.pow(Z, 0.333333333); } else { Z = 7.787 * Z + 0.137931034; } CIELab.l = (116 * Y) - 16; CIELab.a = 500 * (X - Y); CIELab.b = 200 * (Y - Z); return CIELab; }; $.fn.ColorPickerSliders.CIELab2CIELCH = function(CIELab) { var CIELCH = {}; CIELCH.l = CIELab.l; CIELCH.c = Math.sqrt(Math.pow(CIELab.a, 2) + Math.pow(CIELab.b, 2)); CIELCH.h = Math.atan2(CIELab.b, CIELab.a); //Quadrant by signs if (CIELCH.h > 0) { CIELCH.h = (CIELCH.h / Math.PI) * 180; } else { CIELCH.h = 360 - (Math.abs(CIELCH.h) / Math.PI) * 180; } return CIELCH; }; $.fn.ColorPickerSliders.CIELCH2CIELab = function(CIELCH) { var CIELab = {}; CIELab.l = CIELCH.l; CIELab.a = Math.cos(CIELCH.h * 0.01745329251) * CIELCH.c; CIELab.b = Math.sin(CIELCH.h * 0.01745329251) * CIELCH.c; return CIELab; }; $.fn.ColorPickerSliders.CIELab2XYZ = function(CIELab) { var XYZ = {}; XYZ.y = (CIELab.l + 16) / 116; XYZ.x = CIELab.a / 500 + XYZ.y; XYZ.z = XYZ.y - CIELab.b / 200; if (Math.pow(XYZ.y, 3) > 0.008856) { XYZ.y = Math.pow(XYZ.y, 3); } else { XYZ.y = (XYZ.y - 0.137931034) / 7.787; } if (Math.pow(XYZ.x, 3) > 0.008856) { XYZ.x = Math.pow(XYZ.x, 3); } else { XYZ.x = (XYZ.x - 0.137931034) / 7.787; } if (Math.pow(XYZ.z, 3) > 0.008856) { XYZ.z = Math.pow(XYZ.z, 3); } else { XYZ.z = (XYZ.z - 0.137931034) / 7.787; } // Observer = 2°, Illuminant = D65 XYZ.x = 95.047 * XYZ.x; XYZ.y = 100.000 * XYZ.y; XYZ.z = 108.883 * XYZ.z; return XYZ; }; $.fn.ColorPickerSliders.XYZ2rgb = function(XYZ) { var rgb = {}; // Observer = 2°, Illuminant = D65 XYZ.x = XYZ.x / 100; // X from 0 to 95.047 XYZ.y = XYZ.y / 100; // Y from 0 to 100.000 XYZ.z = XYZ.z / 100; // Z from 0 to 108.883 rgb.r = XYZ.x * 3.2406 + XYZ.y * -1.5372 + XYZ.z * -0.4986; rgb.g = XYZ.x * -0.9689 + XYZ.y * 1.8758 + XYZ.z * 0.0415; rgb.b = XYZ.x * 0.0557 + XYZ.y * -0.2040 + XYZ.z * 1.0570; if (rgb.r > 0.0031308) { rgb.r = 1.055 * (Math.pow(rgb.r, 0.41666667)) - 0.055; } else { rgb.r = 12.92 * rgb.r; } if (rgb.g > 0.0031308) { rgb.g = 1.055 * (Math.pow(rgb.g, 0.41666667)) - 0.055; } else { rgb.g = 12.92 * rgb.g; } if (rgb.b > 0.0031308) { rgb.b = 1.055 * (Math.pow(rgb.b, 0.41666667)) - 0.055; } else { rgb.b = 12.92 * rgb.b; } rgb.r = Math.round(rgb.r * 255); rgb.g = Math.round(rgb.g * 255); rgb.b = Math.round(rgb.b * 255); return rgb; }; })(jQuery);