I've been playing around with logic to create a color picker. Hope you all like it!
Forked from Lewi Hussey's Pen Bubble color picker.
A Pen by Cezar Sá Espinola on CodePen.
I've been playing around with logic to create a color picker. Hope you all like it!
Forked from Lewi Hussey's Pen Bubble color picker.
A Pen by Cezar Sá Espinola on CodePen.
| <div class="color-picker"></div> | |
| <div class="camera"></div> | |
| <div class="camera-area"></div> |
| var camera = (function() { | |
| var config = { | |
| el: null, | |
| video: null, | |
| canvas: null | |
| }; | |
| var onColorCallback = null; | |
| navigator.getUserMedia = (navigator.getUserMedia || | |
| navigator.webkitGetUserMedia || | |
| navigator.mozGetUserMedia); | |
| window.webkitURL = (window.URL || window.webkitURL); | |
| var init = function(sel) { | |
| config.el = $(sel); | |
| bindEvents(); | |
| }; | |
| var bindEvents = function() { | |
| $('body').on('click', '.camera', enableCamera); | |
| }; | |
| var enableCamera = function() { | |
| if (!config.video) { | |
| config.video = $('<video autoplay></video>') | |
| config.canvas = $('<canvas id="canvas" width=200 height=200></canvas>')[0]; | |
| config.ctx = config.canvas.getContext("2d"); | |
| config.el.append(config.video); | |
| config.el.append(config.canvas); | |
| } | |
| if (config.playing) { | |
| config.playing = false; | |
| config.video[0].pause(); | |
| config.video[0].src = ""; | |
| config.video.css('display', 'none'); | |
| if (config.timeout) { | |
| clearTimeout(config.timeout); | |
| } | |
| return; | |
| } | |
| var videoSpec = {video: { facingMode: "environment" }}; | |
| navigator.getUserMedia(videoSpec, function(mediaStream) { | |
| config.video.css('display', 'block'); | |
| config.video[0].src = window.webkitURL.createObjectURL(mediaStream); | |
| config.video[0].play(); | |
| config.playing = true; | |
| config.timeout = setTimeout(snap, 1000); | |
| }, function(error) { | |
| console.log("error getting media: " + error) | |
| }); | |
| }; | |
| var snap = function() { | |
| var video = config.video[0]; | |
| var ctx = config.ctx; | |
| var sz = video.videoWidth / 4; | |
| config.canvas.width = config.canvas.height = sz; | |
| ctx.drawImage(video, (video.videoWidth / 2) - (sz / 2), (video.videoHeight / 2) - (sz / 2), sz, sz, 0, 0, config.canvas.width, config.canvas.height); | |
| var data = ctx.getImageData(0, 0, config.canvas.width, config.canvas.height), | |
| dataLen = data.data.length, | |
| r = 0, g = 0, b = 0, count = 0; | |
| for (var i = 0; i < dataLen; i += 4) { | |
| r += data.data[i]; | |
| g += data.data[i+1]; | |
| b += data.data[i+2]; | |
| count++; | |
| } | |
| r = ~~(r / count); | |
| g = ~~(g / count); | |
| b = ~~(b / count); | |
| if (onColorCallback) { | |
| onColorCallback([r, g, b]) | |
| } | |
| config.timeout = setTimeout(snap, 200); | |
| }; | |
| var setCallback = function(cb) { | |
| onColorCallback = cb; | |
| } | |
| return { | |
| init: init, | |
| setCallback: setCallback | |
| }; | |
| }()); | |
| camera.init('.camera-area'); | |
| var colorPicker = (function() { | |
| var config = { | |
| baseColors: [ | |
| [46, 204, 113], | |
| [52, 152, 219], | |
| [155, 89, 182], | |
| [52, 73, 94], | |
| [241, 196, 15], | |
| [230, 126, 34], | |
| [231, 76, 60], | |
| [180, 180, 180] | |
| ], | |
| lightModifier: 20, | |
| darkModifier: 0, | |
| transitionDuration: 200, | |
| transitionDelay: 25, | |
| variationTotal: 10, | |
| cachedVariations: [] | |
| }; | |
| var state = { | |
| activeColor: [0, 0, 0] | |
| }; | |
| var onColorCallback = null; | |
| function init() { | |
| createColorPicker(function() { | |
| appendBaseColors(); | |
| }); | |
| cacheVariations(); | |
| addEventListeners(); | |
| } | |
| function cacheVariations() { | |
| for (var i = 0; i < config.baseColors.length; i++) { | |
| var color = config.baseColors[i]; | |
| var variations = []; | |
| for (var j = 0; j < config.variationTotal; j++) { | |
| var newColor = []; | |
| for (var x = 0; x < color.length; x++) { | |
| var modifiedColor = (Number(color[x]) - 100) + (config.lightModifier * j); | |
| if (modifiedColor <= 0) { | |
| modifiedColor = 0; | |
| } else if (modifiedColor >= 255) { | |
| modifiedColor = 255; | |
| } | |
| newColor.push(modifiedColor); | |
| } | |
| variations.push(newColor); | |
| } | |
| config.cachedVariations[i] = variations; | |
| } | |
| } | |
| function setActiveBaseColor(el) { | |
| $('.color.active').removeClass('active'); | |
| el.addClass('active'); | |
| } | |
| function setActiveColor(el) { | |
| $('.color-var.active').removeClass('active'); | |
| el.addClass('active'); | |
| state.activeColor = el.data('color').split(','); | |
| if (onColorCallback) { | |
| onColorCallback(state.activeColor); | |
| } | |
| } | |
| function addEventListeners() { | |
| $('body').on('click', '.color', function() { | |
| var colorIdx = $(this).index(); | |
| setActiveBaseColor($(this)); | |
| hideVariations(function() { | |
| createVariations(colorIdx, function() { | |
| setDelays(function() { | |
| showVariations(); | |
| }); | |
| }); | |
| }); | |
| }); | |
| $('body').on('click', '.color-var', function() { | |
| setActiveColor($(this)); | |
| setBackgroundColor(); | |
| }); | |
| } | |
| function createColorPicker(callback) { | |
| $('.color-picker').append('<div class="base-colors"></div>'); | |
| $('.color-picker').append('<div class="varied-colors"></div>'); | |
| callback(); | |
| } | |
| function appendBaseColors() { | |
| for (i = 0; i < config.baseColors.length; i++) { | |
| $('.base-colors').append('<div class="color" data-color="' + config.baseColors[i].join() + '" style="background-color: rgb(' + config.baseColors[i].join() + ');"></div>'); | |
| } | |
| }; | |
| function setBackgroundColor() { | |
| $('body').css({ | |
| 'background-color': 'rgb(' + state.activeColor + ')' | |
| }); | |
| } | |
| function createVariations(colorIdx, callback) { | |
| $('.varied-colors').html(''); | |
| var variations = config.cachedVariations[colorIdx]; | |
| for (var i = 0; i < variations.length; i++) { | |
| var newColor = variations[i]; | |
| var extraClass = ""; | |
| if (newColor[0] > 220 && newColor[1] > 220 && newColor[2] > 220) { | |
| extraClass = "light"; | |
| } | |
| $('.varied-colors').append('<div data-color="' + newColor + '" class="color-var ' + extraClass + '" style="background-color: rgb(' + newColor + ');"></div>'); | |
| } | |
| callback(); | |
| } | |
| function setDelays(callback) { | |
| $('.color-var').each(function(x) { | |
| $(this).css({ | |
| 'transition': 'transform ' + (config.transitionDuration / 1000) + 's ' + ((config.transitionDelay / 1000) * x) + 's' | |
| }); | |
| }); | |
| callback(); | |
| } | |
| function showVariations() { | |
| setTimeout(function() { | |
| $('.color-var').addClass('visible'); | |
| }, (config.transitionDelay * config.variationTotal)); | |
| } | |
| function hideVariations(callback) { | |
| $('.color-var').removeClass('visible').removeClass('active'); | |
| setTimeout(function() { | |
| callback(); | |
| }, (config.transitionDelay * config.variationTotal)); | |
| } | |
| function setCallback(cb) { | |
| onColorCallback = cb; | |
| } | |
| function setColor(color) { | |
| for (var i = 0; i < config.baseColors.length; i++) { | |
| for (var j = 0; j < config.cachedVariations[i].length; j++) { | |
| var curColor = config.cachedVariations[i][j]; | |
| if (curColor[0] == color[0] && curColor[1] == color[1] && curColor[2] == color[2]) { | |
| $('.color').eq(i).trigger('click'); | |
| setTimeout(function() { | |
| $('.color-var').eq(j).trigger('click'); | |
| }, 500); | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| return { | |
| init: init, | |
| setCallback: setCallback, | |
| setColor: setColor | |
| }; | |
| }()); | |
| colorPicker.init(); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> |
| * { | |
| box-sizing: border-box; | |
| padding: 0; | |
| margin: 0; | |
| } | |
| body { | |
| width: 100%; | |
| height: 100vh; | |
| -webkit-transition: all 1s; | |
| transition: all 1s; | |
| } | |
| .color-picker { | |
| width: 50%; | |
| height: 100vh; | |
| background-color: white; | |
| overflow: hidden; | |
| } | |
| .base-colors, | |
| .varied-colors { | |
| overflow: hidden; | |
| float: left; | |
| } | |
| .varied-colors { | |
| padding-left: 10px; | |
| } | |
| .color, | |
| .color-var { | |
| border-radius: 50%; | |
| cursor: pointer; | |
| } | |
| .color { | |
| -webkit-transition: all .2s; | |
| transition: all .2s; | |
| width: 9vh; | |
| height: 9vh; | |
| margin: 2.5vh; | |
| } | |
| .color.active { | |
| -webkit-transform: scale(1.3, 1.3); | |
| transform: scale(1.3, 1.3); | |
| } | |
| .color-var { | |
| -webkit-transform: scale(0, 0); | |
| transform: scale(0, 0); | |
| width: 8vh; | |
| height: 8vh; | |
| margin: 1.8vh; | |
| } | |
| .color-var.visible { | |
| -webkit-transform: scale(1, 1); | |
| transform: scale(1, 1); | |
| } | |
| .color-var.active { | |
| -webkit-transform: scale(1.3, 1.3); | |
| transform: scale(1.3, 1.3); | |
| } | |
| .color-var.light { | |
| border: 1px solid #ccc; | |
| } | |
| footer { | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| width: 100%; | |
| padding: 20px; | |
| color: white; | |
| text-align: center; | |
| } | |
| footer a { | |
| color: white; | |
| text-decoration: none; | |
| } | |
| .camera { | |
| width: 30px; | |
| height: 30px; | |
| background: #333; | |
| position: absolute; | |
| right: 10px; | |
| bottom: 10px; | |
| border-radius: 50%; | |
| border: 1px solid #fff; | |
| } | |
| .camera-area canvas { | |
| display: none; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| } | |
| .camera-area video { | |
| display: none; | |
| position: absolute; | |
| width: 90vw; | |
| height: 80vh; | |
| top: 10vh; | |
| left: 5vw; | |
| } |