CSS Exploration: Origami like plane creation.
A Pen by Mathias Paumgarten on CodePen.
<div id="container"></div> | |
<div id="tag" class="before"> | |
<h1>SPREAD</h1> | |
<p>Click anywhere to have the plane spread</p> | |
<ul> | |
<li><a href="https://github.com/MathiasPaumgarten/spread">Github</a></li> | |
</ul> | |
<span>by <a href="http://mathias-paumgarten.com">Mathias Paumgarten</a></span> | |
</div> |
/* | |
* The original code uses AMD and can be | |
* found here: | |
* https://github.com/MathiasPaumgarten/spread | |
*/ | |
var container = document.getElementById( "container" ); | |
var tag = document.getElementById( "tag" ); | |
var orientation = { | |
TOP: 0, | |
RIGHT: 1, | |
BOTTOM: 2, | |
LEFT: 3 | |
} | |
var options = { | |
tileSize: 80, | |
color: "#4fb0ca", | |
randomColor: true | |
} | |
var color = function() { | |
var values = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ]; | |
var color = "#", i = 7; | |
while ( --i ) color += values[ ~~( Math.random() * 16 ) ]; | |
return color; | |
} | |
var random = function( min, max ) { | |
return min + Math.random() * ( max - min ); | |
} | |
var Tile = function( x, y, color, onComplete ) { | |
var div, inlay, cover; | |
var neighbors = []; | |
var isShown = false; | |
function initUI() { | |
div = document.createElement( "div" ); | |
div.className = "tile"; | |
div.style.width = options.tileSize + "px"; | |
div.style.height = options.tileSize + "px"; | |
div.style.top = y * options.tileSize + "px"; | |
div.style.left = x * options.tileSize + "px"; | |
inlay = document.createElement( "div" ); | |
inlay.className = "inlay"; | |
inlay.style.backgroundColor = color; | |
cover = document.createElement( "div" ); | |
cover.className = "cover"; | |
div.appendChild( inlay ); | |
inlay.appendChild( cover ); | |
} | |
// ------ | |
// PUBLIC | |
// ------ | |
this.isShown = function() { | |
return isShown; | |
} | |
this.getElement = function() { | |
return div; | |
} | |
this.addNeighbor = function( direction, neighbor ) { | |
neighbors[ direction ] = neighbor; | |
} | |
this.fromTop = function() { | |
div.classList.add( "from-top" ); | |
show(); | |
} | |
this.fromBottom = function() { | |
div.classList.add( "from-bottom" ); | |
show(); | |
} | |
this.fromRight = function() { | |
div.classList.add( "from-right" ); | |
show(); | |
} | |
this.fromLeft = function() { | |
div.classList.add( "from-left" ); | |
show(); | |
} | |
function onTransitionEnd() { | |
for ( var i = 0; i < neighbors.length; i++ ) { | |
if ( neighbors[ i ] && ! neighbors[ i ].isShown() ) { | |
neighbors[ i ][ getFunctionName( i ) ](); | |
setTimeout( onTransitionEnd, random( 10, 200 ) ); | |
break; | |
} | |
} | |
} | |
// ------- | |
// PRIVATE | |
// ------- | |
function getFunctionName( index ) { | |
return [ "fromBottom", "fromLeft", "fromTop", "fromRight" ][ index ]; | |
} | |
function show() { | |
isShown = true; | |
setTimeout( function() { | |
inlay.classList.add( "show" ); | |
setTimeout( onTransitionEnd, random( 200, 300 ) ); | |
setTimeout( onComplete, 300 ); | |
}, 50 ); | |
} | |
initUI(); | |
} | |
var Controller = function( container, size, position ) { | |
var width = Math.ceil( size.width / options.tileSize ); | |
var height = Math.ceil( size.height / options.tileSize ); | |
var tiles = []; | |
var onComplete = null; | |
var completeCount = 0; | |
var tileColor = options.randomColor ? color() : options.color; | |
function init() { | |
fillScreen(); | |
snowball(); | |
} | |
// ------ | |
// PUBLIC | |
// ------ | |
this.onComplete = function( closure ) { | |
onComplete = closure | |
} | |
this.getColor = function() { | |
return tileColor; | |
} | |
// ------- | |
// PRIVATE | |
// ------- | |
function fillScreen() { | |
var tile; | |
var length = width * height; | |
for ( var y = 0; y < height; y++ ) { | |
for ( var x = 0; x < width; x++ ) { | |
tile = new Tile( x, y, tileColor, tileComplete ); | |
container.appendChild( tile.getElement() ); | |
tiles.push( tile ); | |
} | |
} | |
for ( var i = 0; i < length; i++ ) { | |
tile = tiles[ i ]; | |
row = ~~( i / width ); | |
col = i % width; | |
if ( col < width - 1 ) | |
tile.addNeighbor( orientation.RIGHT, tiles[ i + 1 ] ); | |
if ( col > 0 ) | |
tile.addNeighbor( orientation.LEFT, tiles[ i - 1 ] ); | |
if ( row > 0 ) | |
tile.addNeighbor( orientation.TOP, tiles[ i - width ] ); | |
if ( row < height - 1 ) | |
tile.addNeighbor( orientation.BOTTOM, tiles[ i + width ] ); | |
} | |
} | |
function snowball() { | |
var row = ~~( position.y / options.tileSize ); | |
var col = ~~( position.x / options.tileSize ); | |
tiles[ col + row * width ].fromTop(); | |
} | |
function tileComplete() { | |
completeCount++; | |
if ( completeCount === tiles.length && onComplete ) { | |
onComplete(); | |
} | |
} | |
init(); | |
} | |
function initListeners() { | |
document.addEventListener( "click", onClick, false ); | |
document.addEventListener( "touchstart", onTouchEnd, false ); | |
} | |
function onClick( event ) { | |
var div = document.createElement( "div" ); | |
var size = { | |
width: window.innerWidth, | |
height: window.innerHeight | |
} | |
var position = { | |
x: event.pageX, | |
y: event.pageY | |
} | |
var controller = new Controller( div, size, position ); | |
controller.onComplete( function() { | |
document.body.style.backgroundColor = controller.getColor(); | |
container.removeChild( div ); | |
} ); | |
container.appendChild( div ); | |
} | |
function onTouchEnd( event ) { | |
var touch = event.touches[ 0 ]; | |
event.pageX = touch.pageX; | |
event.pageY = touch.pageY; | |
onClick( event ); | |
} | |
function setTag() { | |
tag.className = "before in"; | |
setTimeout( function() { | |
tag.className = ""; | |
}, 300 ); | |
} | |
function start() { | |
var event = { | |
pageX: window.innerWidth / 2, | |
pageY: window.innerHeight / 2 | |
} | |
onClick( event ); | |
} | |
initListeners(); | |
setTag(); | |
setTimeout( start, 1000 ); |
CSS Exploration: Origami like plane creation.
A Pen by Mathias Paumgarten on CodePen.
@import "compass"; | |
@import url( http://fonts.googleapis.com/css?family=Quicksand ); | |
html, body { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
} | |
.tile { | |
position: absolute; | |
display: none; | |
@include perspective( 300px ); | |
@include transform-style( preserve-3d ); | |
&.from-top { | |
display: block; | |
@include perspective-origin( 50% 0 ); | |
.inlay { | |
@include transform-origin( 50%, 0, 0 ); | |
@include transform( rotateX( -90deg ) ); | |
} | |
} | |
&.from-bottom { | |
display: block; | |
@include perspective-origin( 50% 100% ); | |
.inlay { | |
@include transform-origin( 50%, 100%, 0 ); | |
@include transform( rotateX( 90deg ) ); | |
} | |
} | |
&.from-left { | |
display: block; | |
@include perspective-origin( 0 50% ); | |
.inlay { | |
@include transform-origin( 0, 50%, 0 ); | |
@include transform( rotateY( 90deg ) ); | |
} | |
} | |
&.from-right { | |
display: block; | |
@include perspective-origin( 100% 50% ); | |
.inlay { | |
@include transform-origin( 100%, 50%, 0 ); | |
@include transform( rotateY( -90deg ) ); | |
} | |
} | |
} | |
.inlay { | |
width: 100%; | |
height: 100%; | |
@include single-transition( all, 0.3s, ease-in-out ); | |
} | |
.cover { | |
width: 100%; | |
height: 100%; | |
background-color: rgba( 0, 0, 0, 0.4 ); | |
@include single-transition( background-color, 0.3s, ease-in-out ); | |
} | |
.tile .inlay.show { | |
@include transform( rotateX( 0 ) rotateY( 0 ) ); | |
.cover { | |
background-color: rgba( 0, 0, 0, 0 ); | |
} | |
} | |
#tag.before { | |
width: 0; | |
left: 0; | |
padding: 15px 0 0 0; | |
h1, p, ul, span { | |
opacity: 0; | |
@include transform( translate3d( -50px, 0, 0 ) ); | |
} | |
} | |
#tag.in { | |
width: 220px; | |
} | |
#tag { | |
@include single-transition( all, 0.3s, cubic-bezier( 0.8, 0, 0.2, 1 ) ); | |
position: fixed; | |
width: 180px; | |
height: 180px; | |
top: 20px; | |
left: 20px; | |
font-family: "Quicksand", sans-serif; | |
padding: 15px 0 0 20px; | |
background-color: #000; | |
color: #fff; | |
h1, p, ul, span { | |
opacity: 1; | |
@include transform( translate3d( 0, 0, 0 ) ); | |
} | |
h1 { | |
@include single-transition( all, 0.3s, ease-in-out, 0.3s ); | |
font-size: 30px; | |
font-weight: 400; | |
margin: 0; | |
} | |
p { | |
@include single-transition( all, 0.3s, ease-in-out, 0.4s ); | |
} | |
ul { | |
@include single-transition( all, 0.3s, ease-in-out, 0.6s ); | |
} | |
p , ul a { | |
font-size: 12px; | |
font-weight: 700; | |
} | |
a { | |
color: #fff; | |
text-decoration: none; | |
} | |
a:hover { | |
background-color: #333; | |
} | |
span { | |
@include single-transition( all, 0.3s, ease-in-out, 0.7s ); | |
display: inline-block; | |
margin-top: 40px; | |
font-size: 10px; | |
} | |
ul { | |
list-style: none; | |
margin: 0; | |
padding: 0; | |
} | |
} |