Created
August 9, 2017 02:42
-
-
Save bbelluschi/6323083140d7645e9c353c68c8f2c8c2 to your computer and use it in GitHub Desktop.
3d_Cube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<link href="style.css" rel="stylesheet" type="text/css"> | |
<script src="index.js"></script> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Title</title> | |
</head> | |
<body> | |
<div id="wrapper"> | |
<div class="viewport"> | |
<div class="cube"> | |
<div class="side"> | |
<div class="cube-image">1</div> | |
</div> | |
<div class="side"> | |
<div class="cube-image">2</div> | |
</div> | |
<div class="side"> | |
<div class="cube-image">3</div> | |
</div> | |
<div class="side"> | |
<div class="cube-image">4</div> | |
</div> | |
<div class="side"> | |
<div class="cube-image">5</div> | |
</div> | |
<div class="side"> | |
<div class="cube-image active">6</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var events = new Events(); | |
events.add = function(obj) { | |
obj.events = { }; | |
} | |
events.implement = function(fn) { | |
fn.prototype = Object.create(Events.prototype); | |
} | |
function Events() { | |
this.events = { }; | |
} | |
Events.prototype.on = function(name, fn) { | |
var events = this.events[name]; | |
if (events == undefined) { | |
this.events[name] = [ fn ]; | |
this.emit('event:on', fn); | |
} else { | |
if (events.indexOf(fn) == -1) { | |
events.push(fn); | |
this.emit('event:on', fn); | |
} | |
} | |
return this; | |
} | |
Events.prototype.once = function(name, fn) { | |
var events = this.events[name]; | |
fn.once = true; | |
if (!events) { | |
this.events[name] = [ fn ]; | |
this.emit('event:once', fn); | |
} else { | |
if (events.indexOf(fn) == -1) { | |
events.push(fn); | |
this.emit('event:once', fn); | |
} | |
} | |
return this; | |
} | |
Events.prototype.emit = function(name, args) { | |
var events = this.events[name]; | |
if (events) { | |
var i = events.length; | |
while(i--) { | |
if (events[i]) { | |
events[i].call(this, args); | |
if (events[i].once) { | |
delete events[i]; | |
} | |
} | |
} | |
} | |
return this; | |
} | |
Events.prototype.unbind = function(name, fn) { | |
if (name) { | |
var events = this.events[name]; | |
if (events) { | |
if (fn) { | |
var i = events.indexOf(fn); | |
if (i != -1) { | |
delete events[i]; | |
} | |
} else { | |
delete this.events[name]; | |
} | |
} | |
} else { | |
delete this.events; | |
this.events = { }; | |
} | |
return this; | |
} | |
var userPrefix; | |
var prefix = (function () { | |
var styles = window.getComputedStyle(document.documentElement, ''), | |
pre = (Array.prototype.slice | |
.call(styles) | |
.join('') | |
.match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']) | |
)[1], | |
dom = ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1]; | |
userPrefix = { | |
dom: dom, | |
lowercase: pre, | |
css: '-' + pre + '-', | |
js: pre[0].toUpperCase() + pre.substr(1) | |
}; | |
})(); | |
function bindEvent(element, type, handler) { | |
if(element.addEventListener) { | |
element.addEventListener(type, handler, false); | |
} else { | |
element.attachEvent('on' + type, handler); | |
} | |
} | |
function Viewport(data) { | |
events.add(this); | |
var self = this; | |
this.element = data.element; | |
this.fps = data.fps; | |
this.sensivity = data.sensivity; | |
this.sensivityFade = data.sensivityFade; | |
this.touchSensivity = data.touchSensivity; | |
this.speed = data.speed; | |
this.lastX = 0; | |
this.lastY = 0; | |
this.mouseX = 0; | |
this.mouseY = 0; | |
this.distanceX = 0; | |
this.distanceY = 0; | |
this.positionX = 1122; | |
this.positionY = 136; | |
this.torqueX = 0; | |
this.torqueY = 0; | |
this.down = false; | |
this.upsideDown = false; | |
this.previousPositionX = 0; | |
this.previousPositionY = 0; | |
this.currentSide = 0; | |
this.calculatedSide = 0; | |
bindEvent(document, 'mousedown', function() { | |
self.down = true; | |
}); | |
bindEvent(document, 'mouseup', function() { | |
self.down = false; | |
}); | |
bindEvent(document, 'keyup', function() { | |
self.down = false; | |
}); | |
bindEvent(document, 'mousemove', function(e) { | |
self.mouseX = e.pageX; | |
self.mouseY = e.pageY; | |
}); | |
bindEvent(document, 'touchstart', function(e) { | |
self.down = true; | |
e.touches ? e = e.touches[0] : null; | |
self.mouseX = e.pageX / self.touchSensivity; | |
self.mouseY = e.pageY / self.touchSensivity; | |
self.lastX = self.mouseX; | |
self.lastY = self.mouseY; | |
}); | |
bindEvent(document, 'touchmove', function(e) { | |
if(e.preventDefault) { | |
e.preventDefault(); | |
} | |
if(e.touches.length == 1) { | |
e.touches ? e = e.touches[0] : null; | |
self.mouseX = e.pageX / self.touchSensivity; | |
self.mouseY = e.pageY / self.touchSensivity; | |
} | |
}); | |
bindEvent(document, 'touchend', function(e) { | |
self.down = false; | |
}); | |
setInterval(this.animate.bind(this), this.fps); | |
} | |
events.implement(Viewport); | |
Viewport.prototype.animate = function() { | |
this.distanceX = (this.mouseX - this.lastX); | |
this.distanceY = (this.mouseY - this.lastY); | |
this.lastX = this.mouseX; | |
this.lastY = this.mouseY; | |
if(this.down) { | |
this.torqueX = this.torqueX * this.sensivityFade + (this.distanceX * this.speed - this.torqueX) * this.sensivity; | |
this.torqueY = this.torqueY * this.sensivityFade + (this.distanceY * this.speed - this.torqueY) * this.sensivity; | |
} | |
if(Math.abs(this.torqueX) > 1.0 || Math.abs(this.torqueY) > 1.0) { | |
if(!this.down) { | |
this.torqueX *= this.sensivityFade; | |
this.torqueY *= this.sensivityFade; | |
} | |
this.positionY -= this.torqueY; | |
if(this.positionY > 360) { | |
this.positionY -= 360; | |
} else if(this.positionY < 0) { | |
this.positionY += 360; | |
} | |
if(this.positionY > 90 && this.positionY < 270) { | |
this.positionX -= this.torqueX; | |
if(!this.upsideDown) { | |
this.upsideDown = true; | |
this.emit('upsideDown', { upsideDown: this.upsideDown }); | |
} | |
} else { | |
this.positionX += this.torqueX; | |
if(this.upsideDown) { | |
this.upsideDown = false; | |
this.emit('upsideDown', { upsideDown: this.upsideDown }); | |
} | |
} | |
if(this.positionX > 360) { | |
this.positionX -= 360; | |
} else if(this.positionX < 0) { | |
this.positionX += 360; | |
} | |
if(!(this.positionY >= 46 && this.positionY <= 130) && !(this.positionY >= 220 && this.positionY <= 308)) { | |
if(this.upsideDown) { | |
if(this.positionX >= 42 && this.positionX <= 130) { | |
this.calculatedSide = 3; | |
} else if(this.positionX >= 131 && this.positionX <= 223) { | |
this.calculatedSide = 2; | |
} else if(this.positionX >= 224 && this.positionX <= 314) { | |
this.calculatedSide = 5; | |
} else { | |
this.calculatedSide = 4; | |
} | |
} else { | |
if(this.positionX >= 42 && this.positionX <= 130) { | |
this.calculatedSide = 5; | |
} else if(this.positionX >= 131 && this.positionX <= 223) { | |
this.calculatedSide = 4; | |
} else if(this.positionX >= 224 && this.positionX <= 314) { | |
this.calculatedSide = 3; | |
} else { | |
this.calculatedSide = 2; | |
} | |
} | |
} else { | |
if(this.positionY >= 46 && this.positionY <= 130) { | |
this.calculatedSide = 6; | |
} | |
if(this.positionY >= 220 && this.positionY <= 308) { | |
this.calculatedSide = 1; | |
} | |
} | |
if(this.calculatedSide !== this.currentSide) { | |
this.currentSide = this.calculatedSide; | |
this.emit('sideChange'); | |
} | |
} | |
this.element.style[userPrefix.js + 'Transform'] = 'rotateX(' + this.positionY + 'deg) rotateY(' + this.positionX + 'deg)'; | |
if(this.positionY != this.previousPositionY || this.positionX != this.previousPositionX) { | |
this.previousPositionY = this.positionY; | |
this.previousPositionX = this.positionX; | |
this.emit('rotate'); | |
} | |
} | |
var viewport = new Viewport({ | |
element: document.getElementsByClassName('cube')[0], | |
fps: 20, | |
sensivity: .1, | |
sensivityFade: .93, | |
speed: 2, | |
touchSensivity: 1.5 | |
}); | |
function Cube(data) { | |
var self = this; | |
this.element = data.element; | |
this.sides = this.element.getElementsByClassName('side'); | |
this.viewport = data.viewport; | |
this.viewport.on('rotate', function() { | |
self.rotateSides(); | |
}); | |
this.viewport.on('upsideDown', function(obj) { | |
self.upsideDown(obj); | |
}); | |
this.viewport.on('sideChange', function() { | |
self.sideChange(); | |
}); | |
} | |
Cube.prototype.rotateSides = function() { | |
var viewport = this.viewport; | |
if(viewport.positionY > 90 && viewport.positionY < 270) { | |
this.sides[0].getElementsByClassName('cube-image')[0].style[userPrefix.js + 'Transform'] = 'rotate(' + (viewport.positionX + viewport.torqueX) + 'deg)'; | |
this.sides[5].getElementsByClassName('cube-image')[0].style[userPrefix.js + 'Transform'] = 'rotate(' + -(viewport.positionX + 180 + viewport.torqueX) + 'deg)'; | |
} else { | |
this.sides[0].getElementsByClassName('cube-image')[0].style[userPrefix.js + 'Transform'] = 'rotate(' + (viewport.positionX - viewport.torqueX) + 'deg)'; | |
this.sides[5].getElementsByClassName('cube-image')[0].style[userPrefix.js + 'Transform'] = 'rotate(' + -(viewport.positionX + 180 - viewport.torqueX) + 'deg)'; | |
} | |
} | |
Cube.prototype.upsideDown = function(obj) { | |
var deg = (obj.upsideDown == true) ? '180deg' : '0deg'; | |
var i = 5; | |
while(i > 0 && --i) { | |
this.sides[i].getElementsByClassName('cube-image')[0].style[userPrefix.js + 'Transform'] = 'rotate(' + deg + ')'; | |
} | |
} | |
Cube.prototype.sideChange = function() { | |
for(var i = 0; i < this.sides.length; ++i) { | |
this.sides[i].getElementsByClassName('cube-image')[0].className = 'cube-image'; | |
} | |
this.sides[this.viewport.currentSide - 1].getElementsByClassName('cube-image')[0].className = 'cube-image active'; | |
} | |
new Cube({ | |
viewport: viewport, | |
element: document.getElementsByClassName('cube')[0] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*, *:before, *:after { | |
-moz-box-sizing: border-box; | |
-webkit-box-sizing: border-box; | |
box-sizing: border-box; } | |
body { | |
background: #1b1b1b; | |
font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; | |
font-weight: 300; } | |
#wrapper { | |
padding-top: 5%; } | |
.viewport { | |
-webkit-perspective: 800px; | |
-moz-perspective: 800px; | |
-ms-perspective: 800px; | |
-o-perspective: 800px; | |
perspective: 800px; | |
-webkit-perspective-origin: 50% 200px; | |
-moz-perspective-origin: 50% 200px; | |
-ms-perspective-origin: 50% 200px; | |
-o-perspective-origin: 50% 200px; | |
perspective-origin: 50% 200px; | |
-webkit-transform: scale(0.8, 0.8); | |
-moz-transform: scale(0.8, 0.8); | |
-ms-transform: scale(0.8, 0.8); | |
-o-transform: scale(0.8, 0.8); | |
transform: scale(0.8, 0.8); | |
-webkit-box-reflect: below 170px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, 0.1))); } | |
.cube { | |
position: relative; | |
margin: 0 auto; | |
height: 200px; | |
width: 200px; | |
-webkit-transform-style: preserve-3d; | |
-moz-transform-style: preserve-3d; | |
-ms-transform-style: preserve-3d; | |
-o-transform-style: preserve-3d; | |
transform-style: preserve-3d; | |
-webkit-transform: rotateX(136deg) rotateY(1122deg); | |
-moz-transform: rotateX(136deg) rotateY(1122deg); | |
-ms-transform: rotateX(136deg) rotateY(1122deg); | |
-o-transform: rotateX(136deg) rotateY(1122deg); | |
transform: rotateX(136deg) rotateY(1122deg); } | |
.cube > div { | |
overflow: hidden; | |
position: absolute; | |
opacity: 0.9; | |
height: 200px; | |
width: 200px; | |
background-image: url("http://jordizle.com/demo/376/3d-interactive-cube-with-rotating-sides-using-css3-and-javascript/assets/img/cube/blank.png"); | |
-webkit-touch-callout: none; | |
-moz-touch-callout: none; | |
-ms-touch-callout: none; | |
-o-touch-callout: none; | |
touch-callout: none; | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
-o-user-select: none; | |
user-select: none; } | |
.cube > div > div.cube-image { | |
width: 200px; | |
height: 200px; | |
-webkit-transform: rotate(180deg); | |
-moz-transform: rotate(180deg); | |
-ms-transform: rotate(180deg); | |
-o-transform: rotate(180deg); | |
transform: rotate(180deg); | |
line-height: 200px; | |
font-size: 80px; | |
text-align: center; | |
color: #1b9bd8; | |
-webkit-transition: color 600ms; | |
-moz-transition: color 600ms; | |
-ms-transition: color 600ms; | |
-o-transition: color 600ms; | |
transition: color 600ms; } | |
.cube > div > div.cube-image.active { | |
color: red; } | |
.cube > div:hover { | |
cursor: pointer; } | |
.cube > div:active { | |
cursor: pointer; } | |
.cube > div:first-child { | |
-webkit-transform: rotateX(90deg) translateZ(100px); | |
-moz-transform: rotateX(90deg) translateZ(100px); | |
-ms-transform: rotateX(90deg) translateZ(100px); | |
-o-transform: rotateX(90deg) translateZ(100px); | |
transform: rotateX(90deg) translateZ(100px); | |
outline: 1px solid transparent; } | |
.cube > div:nth-child(2) { | |
-webkit-transform: translateZ(100px); | |
-moz-transform: translateZ(100px); | |
-ms-transform: translateZ(100px); | |
-o-transform: translateZ(100px); | |
transform: translateZ(100px); | |
outline: 1px solid transparent; } | |
.cube > div:nth-child(3) { | |
-webkit-transform: rotateY(90deg) translateZ(100px); | |
-moz-transform: rotateY(90deg) translateZ(100px); | |
-ms-transform: rotateY(90deg) translateZ(100px); | |
-o-transform: rotateY(90deg) translateZ(100px); | |
transform: rotateY(90deg) translateZ(100px); | |
outline: 1px solid transparent; } | |
.cube > div:nth-child(4) { | |
-webkit-transform: rotateY(180deg) translateZ(100px); | |
-moz-transform: rotateY(180deg) translateZ(100px); | |
-ms-transform: rotateY(180deg) translateZ(100px); | |
-o-transform: rotateY(180deg) translateZ(100px); | |
transform: rotateY(180deg) translateZ(100px); | |
outline: 1px solid transparent; } | |
.cube > div:nth-child(5) { | |
-webkit-transform: rotateY(-90deg) translateZ(100px); | |
-moz-transform: rotateY(-90deg) translateZ(100px); | |
-ms-transform: rotateY(-90deg) translateZ(100px); | |
-o-transform: rotateY(-90deg) translateZ(100px); | |
transform: rotateY(-90deg) translateZ(100px); | |
outline: 1px solid transparent; } | |
.cube > div:nth-child(6) { | |
-webkit-transform: rotateX(-90deg) rotate(180deg) translateZ(100px); | |
-moz-transform: rotateX(-90deg) rotate(180deg) translateZ(100px); | |
-ms-transform: rotateX(-90deg) rotate(180deg) translateZ(100px); | |
-o-transform: rotateX(-90deg) rotate(180deg) translateZ(100px); | |
transform: rotateX(-90deg) rotate(180deg) translateZ(100px); | |
outline: 1px solid transparent; } | |
object { | |
opacity: 0.5; } | |
object:hover { | |
opacity: 1; } | |
@media (max-width: 640px) { | |
.viewport { | |
-webkit-transform: scale(0.6, 0.6); | |
-moz-transform: scale(0.6, 0.6); | |
-ms-transform: scale(0.6, 0.6); | |
-o-transform: scale(0.6, 0.6); | |
transform: scale(0.6, 0.6); } } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment