Skip to content

Instantly share code, notes, and snippets.

@cezarsa
Last active May 28, 2016 03:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cezarsa/ff05cf13d9dfcc10fe846d3d64464c2e to your computer and use it in GitHub Desktop.
Save cezarsa/ff05cf13d9dfcc10fe846d3d64464c2e to your computer and use it in GitHub Desktop.
Bubble color picker
<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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment