Hex Kaleidoscope #1
by Paige Saez
<div class='info'>
<div class='info'>
<hgroup class='about'>
<h1>Kaleidoscope</h1>
<h2>Canvas kaleidoscope implementation with drag & drop</h2>
<h3>Drop an image</h3>
</hgroup>
</div>
@charset "UTF-8";
@charset "UTF-8";
@import url(http://fonts.googleapis.com/css?family=Quantico);
html, body {
background: #ffffff;
}
/* Info */
@keyframes show-info {
0% {
transform: rotateY(120deg);
}
100% {
transform: rotateY(0deg);
}
}
.info {
transition: all 180ms ease-out;
transform-style: preserve-3d;
transform: perspective(800px);
font-family: "Quantico", sans-serif;
position: absolute;
font-size: 12px;
opacity: 0.8;
color: #fff;
width: 240px;
left: 0px;
top: 20px;
}
.info:hover {
box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.05);
opacity: 1;
}
.info h1, .info h2, .info h3 {
line-height: 1;
margin: 5px 0;
}
.info a {
transition: all 200ms ease-out;
border-bottom: 1px dotted rgba(255, 255, 255, 0.4);
text-decoration: none;
opacity: 0.6;
color: #fff;
}
.info a:hover {
opacity: 0.99;
}
.info .about,
.info .more {
transform-origin: 0% 50%;
transform: rotateY(120deg);
margin-bottom: 1px;
background: rgba(0, 0, 0, 0.8);
padding: 12px 15px 12px 20px;
}
.info .about {
animation: show-info 500ms cubic-bezier(0.23, 1, 0.32, 1) 600ms 1 normal forwards;
padding-bottom: 15px;
}
.info .about a {
opacity: 0.9;
}
.info .about h1 {
letter-spacing: -1px;
font-weight: 300;
font-size: 19px;
opacity: 0.95;
}
.info .about h2 {
font-weight: 300;
font-size: 13px;
opacity: 0.8;
}
.info .about h3 {
text-transform: uppercase;
margin-top: 10px;
font-size: 11px;
}
.info .about h3:before {
margin-right: 2px;
font-size: 14px;
content: "›";
}
.info .more {
animation: show-info 500ms cubic-bezier(0.23, 1, 0.32, 1) 500ms 1 normal forwards;
padding: 5px 15px 10px 20px;
}
.info .more a {
text-transform: uppercase;
margin-right: 10px;
font-size: 10px;
}
(function() {
(function() {
var DragDrop, Kaleidoscope, c, dragger, gui, i, image, kaleidoscope, len, onChange, onMouseMoved, options, ref, tr, tx, ty, update,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Kaleidoscope = (function() {
Kaleidoscope.prototype.HALF_PI = Math.PI / 2;
Kaleidoscope.prototype.TWO_PI = Math.PI * 2;
function Kaleidoscope(options1) {
var key, ref, ref1, val;
this.options = options1 != null ? options1 : {};
this.defaults = {
offsetRotation: 0.0,
offsetScale: 1.0,
offsetX: 0.0,
offsetY: 0.0,
radius: 500,
slices: 5,
zoom: 1.0
};
ref = this.defaults;
for (key in ref) {
val = ref[key];
this[key] = val;
}
ref1 = this.options;
for (key in ref1) {
val = ref1[key];
this[key] = val;
}
if (this.domElement == null) {
this.domElement = document.createElement('canvas');
}
if (this.context == null) {
this.context = this.domElement.getContext('2d');
}
if (this.image == null) {
this.image = document.createElement('img');
}
}
Kaleidoscope.prototype.draw = function() {
var cx, i, index, ref, results, scale, step;
this.domElement.width = this.domElement.height = this.radius * 2;
this.context.fillStyle = this.context.createPattern(this.image, 'repeat');
scale = this.zoom * (this.radius / Math.min(this.image.width, this.image.height));
step = this.TWO_PI / this.slices;
cx = this.image.width / 2;
results = [];
for (index = i = 0, ref = this.slices; 0 <= ref ? i <= ref : i >= ref; index = 0 <= ref ? ++i : --i) {
this.context.save();
this.context.translate(this.radius, this.radius);
this.context.rotate(index * step);
this.context.beginPath();
this.context.moveTo(-0.5, -0.5);
this.context.arc(0, 0, this.radius, step * -0.51, step * 0.51);
this.context.lineTo(0.5, 0.5);
this.context.closePath();
this.context.rotate(this.HALF_PI);
this.context.scale(scale, scale);
this.context.scale([-1, 1][index % 2], 1);
this.context.translate(this.offsetX - cx, this.offsetY);
this.context.rotate(this.offsetRotation);
this.context.scale(this.offsetScale, this.offsetScale);
this.context.fill();
results.push(this.context.restore());
}
return results;
};
return Kaleidoscope;
})();
DragDrop = (function() {
function DragDrop(callback, context, filter) {
var disable;
this.callback = callback;
this.context = context != null ? context : document;
this.filter = filter != null ? filter : /^image/i;
this.onDrop = bind(this.onDrop, this);
disable = function(event) {
event.stopPropagation();
return event.preventDefault();
};
this.context.addEventListener('dragleave', disable);
this.context.addEventListener('dragenter', disable);
this.context.addEventListener('dragover', disable);
this.context.addEventListener('drop', this.onDrop, false);
}
DragDrop.prototype.onDrop = function(event) {
var file, reader;
event.stopPropagation();
event.preventDefault();
file = event.dataTransfer.files[0];
if (this.filter.test(file.type)) {
reader = new FileReader;
reader.onload = (function(_this) {
return function(event) {
return typeof _this.callback === "function" ? _this.callback(event.target.result) : void 0;
};
})(this);
return reader.readAsDataURL(file);
}
};
return DragDrop;
})();
image = new Image;
image.onload = (function(_this) {
return function() {
return kaleidoscope.draw();
};
})(this);
image.src = 'https://40.media.tumblr.com/a5ec5aa4d800cbcf895ec473c06b57ec/tumblr_nnlc1jOBDr1qzgaw0o1_500.png';
kaleidoscope = new Kaleidoscope({
image: image,
slices: 10
});
kaleidoscope.domElement.style.position = 'absolute';
kaleidoscope.domElement.style.marginLeft = -kaleidoscope.radius + 'px';
kaleidoscope.domElement.style.marginTop = -kaleidoscope.radius + 'px';
kaleidoscope.domElement.style.left = '50%';
kaleidoscope.domElement.style.top = '50%';
document.body.appendChild(kaleidoscope.domElement);
dragger = new DragDrop(function(data) {
return kaleidoscope.image.src = data;
});
tx = kaleidoscope.offsetX;
ty = kaleidoscope.offsetY;
tr = kaleidoscope.offsetRotation;
onMouseMoved = (function(_this) {
return function(event) {
var cx, cy, dx, dy, hx, hy;
cx = window.innerWidth / 2;
cy = window.innerHeight / 2;
dx = event.pageX / window.innerWidth;
dy = event.pageY / window.innerHeight;
hx = dx - 0.5;
hy = dy - 0.5;
tx = hx * kaleidoscope.radius * -2;
ty = hy * kaleidoscope.radius * 2;
return tr = Math.atan2(hy, hx);
};
})(this);
window.addEventListener('mousemove', onMouseMoved, false);
options = {
interactive: true,
ease: 0.1
};
(update = (function(_this) {
return function() {
var delta, theta;
if (options.interactive) {
delta = tr - kaleidoscope.offsetRotation;
theta = Math.atan2(Math.sin(delta), Math.cos(delta));
kaleidoscope.offsetX += (tx - kaleidoscope.offsetX) * options.ease;
kaleidoscope.offsetY += (ty - kaleidoscope.offsetY) * options.ease;
kaleidoscope.offsetRotation += (theta - kaleidoscope.offsetRotation) * options.ease;
kaleidoscope.draw();
}
return setTimeout(update, 1000 / 60);
};
})(this))();
gui = new dat.GUI;
gui.add(kaleidoscope, 'zoom').min(0.25).max(2.0);
gui.add(kaleidoscope, 'slices').min(6).max(32).step(2);
gui.add(kaleidoscope, 'radius').min(200).max(500);
gui.add(kaleidoscope, 'offsetX').min(-kaleidoscope.radius).max(kaleidoscope.radius).listen();
gui.add(kaleidoscope, 'offsetY').min(-kaleidoscope.radius).max(kaleidoscope.radius).listen();
gui.add(kaleidoscope, 'offsetRotation').min(-Math.PI).max(Math.PI).listen();
gui.add(kaleidoscope, 'offsetScale').min(0.5).max(4.0);
gui.add(options, 'interactive').listen();
gui.close();
onChange = (function(_this) {
return function() {
kaleidoscope.domElement.style.marginLeft = -kaleidoscope.radius + 'px';
kaleidoscope.domElement.style.marginTop = -kaleidoscope.radius + 'px';
options.interactive = false;
return kaleidoscope.draw();
};
})(this);
ref = gui.__controllers;
for (i = 0, len = ref.length; i < len; i++) {
c = ref[i];
if (c.property !== 'interactive') {
c.onChange(onChange);
}
}
}).call(this);