Last active
August 29, 2015 14:10
-
-
Save ne-sachirou/48f02783837cf712286a to your computer and use it in GitHub Desktop.
Gassen Animation Demo (CSS+JavaScript) http://jsdo.it/ne_sachirou/7wwz
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
Gassen Animation Demo | |
https://gist.github.com/ne-sachirou/48f02783837cf712286a | |
Author : ne_Sachirou <utakata.c4se@gmail.com> | |
Date : 2014-2014 | |
License : GPLv3 or later http://www.gnu.org/licenses/gpl.html | |
Music: | |
1. hainezu (FuniSaya,Crain) "gad1" CC by-sa 2014 | |
2. hainezu (FuniSaya,Crain) "gad2" CC by-sa 2014 | |
3. hainezu (FuniSaya,Crain) "gad3" CC by-sa 2014 |
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
@charset "UTF-8"; | |
html, body { | |
height : 100%; | |
margin : 0; | |
overflow : hidden; | |
padding : 0; | |
position : relative; | |
width : 100%; | |
} | |
.obj { | |
box-shadow : 0 0 1px #aaa; | |
position : absolute; | |
transition-property : left top transform opacity; | |
transition-timing-function : linear linear linear ease-in-out; | |
} |
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="ja"> | |
<head> | |
<meta charset="UTF-8"/> | |
<title>Gassen Animation Demo</title> | |
<link rel="stylesheet" href="index.css"/> | |
<style> | |
</style> | |
</head> | |
<body> | |
<script src="index.js"></script> | |
<script> | |
window.addEventListener('DOMContentLoaded', function () { | |
new App().init(); | |
}); | |
</script> | |
</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
(function (global) { | |
'use strict'; | |
/** | |
* @param {number} min int | |
* @param {number} max int | |
* @return {number} int | |
*/ | |
function rand(min, max) { | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} | |
// {{{ App | |
/** | |
* @class | |
*/ | |
function App() { | |
if (App.instance) { return App.instance; } | |
this.start = 0; | |
this.scene = null; | |
App.instance = this; | |
} | |
/** @type {App} */ | |
App.instance = null; | |
App.prototype.init = function () { | |
this.start = Date.now(); | |
this.scene = new Scene(0); | |
requestAnimationFrame(this.animate); | |
}; | |
App.prototype.animate = function () { | |
var me = App.instance, | |
scene = me.scene, | |
ms = Date.now() - me.start; | |
if (scene.isEnded) { | |
scene.destruct(); | |
me.scene = new Scene(ms); | |
return requestAnimationFrame(me.animate); | |
} | |
scene.animate(ms); | |
requestAnimationFrame(me.animate); | |
}; | |
// }}} App | |
// {{{ Scene | |
/** | |
* @class | |
* @param {number} now Time ms of the app. | |
*/ | |
function Scene(now) { | |
var level, i = 0, iz = 0; | |
this.start = now; | |
this.isEnded = false; | |
this.bgm = new Bgm(); | |
this.bg = new Bg(); | |
this.objs = []; | |
for (i = 0, iz = Scene.OBJ_NUMBER; i < iz; ++i) { | |
level = Scene.OBJ_LEVEL_MAP[rand(0, Scene.OBJ_LEVEL_MAP.length - 1)]; | |
this.objs.push(new ObjFactory().createRandom(level)); | |
} | |
} | |
/** @const {number} */ | |
Scene.SCENE_SEC = 10; | |
/** @const {number} */ | |
Scene.OBJ_NUMBER = 12; | |
/** @const {number[]} */ | |
Scene.OBJ_LEVEL_MAP = [1, 1, 1, 2, 2, 3]; | |
Scene.prototype.destruct = function () { | |
var obj, | |
i = -1, | |
objs = this.objs; | |
this.isEnded = true; | |
while (obj = objs[++i]) { obj.destruct(); } | |
}; | |
/** | |
* @param {number} ms Time ms of the app. | |
*/ | |
Scene.prototype.animate = function (ms) { | |
var obj, | |
i = -1, | |
objs = this.objs; | |
if (this.start + Scene.SCENE_SEC * 1000 < ms) { | |
this.isEnded = true; | |
return; | |
} | |
ms = ms - this.start; | |
this.bgm.animate(ms); | |
this.bg.animate(ms); | |
while (obj = objs[++i]) { obj.animate(ms); } | |
}; | |
// }}} Scene | |
// {{{ Bgm | |
/** | |
* @class | |
*/ | |
function Bgm() { | |
this.player = BgmPlayer.init(); | |
this.player.play(); | |
} | |
/** @const {string[]} */ | |
Bgm.SRCS = ['gad1.ogg', 'gad2.ogg', 'gad3.ogg']; | |
/** | |
* @param {number} ms Time ms of the scene. | |
*/ | |
Bgm.prototype.animate = function (ms) { | |
}; | |
// }}} Bgm | |
// {{{ BgmPlayer | |
/** | |
* @class | |
*/ | |
function BgmPlayer() { | |
this.audios = []; | |
this.current = -1; | |
} | |
BgmPlayer.init = function () { | |
var player = new BgmPlayer(); | |
BgmPlayer.init = function () { return player; }; | |
Bgm.SRCS.forEach(function (src, i) { | |
var audio = new Audio(src); | |
audio.autoplay = false; | |
audio.loop = false; | |
audio.volume = 0.8; | |
audio.addEventListener('canplaythrough', function () { | |
player.audios.push(audio); | |
}); | |
audio.addEventListener('ended', function () { | |
var next; | |
if (player.audios.length === 1) { | |
player.current = 0; | |
} else { | |
next = rand(0, player.audios.length - 2); | |
if (next === player.current) { ++next; } | |
player.current = next; | |
} | |
player.audios[player.current].play(); | |
}); | |
}); | |
return player; | |
}; | |
BgmPlayer.prototype.play = function () { | |
var timer, | |
me = this; | |
if (this.current >= 0) { return; } | |
if (this.audios.length) { | |
this.current = 0; | |
this.audios[0].play(); | |
} else { | |
timer = setInterval(function () { | |
if (me.audios.length) { | |
clearInterval(timer); | |
me.play(); | |
} | |
}, 1000 / 6); | |
} | |
}; | |
// }}} BgmPlayer | |
// {{{ Bg | |
/** | |
* @class | |
*/ | |
function Bg() { | |
Bg.beforeColor = (Bg.beforeColor + 1) % Bg.COLORS.length; | |
document.body.style.background = Bg.COLORS[Bg.beforeColor]; | |
} | |
/** @type {number} */ | |
Bg.beforeColor = -1; | |
/** @const {string[]} */ | |
Bg.COLORS = ['#faa', '#afa', '#aaf', '#ffa', '#faf', '#aff']; | |
/** | |
* @param {number} ms Time ms of the scene. | |
*/ | |
Bg.prototype.animate = function (ms) { | |
}; | |
// }}} Bg | |
// {{{ ObjFactory | |
/** | |
* @class | |
*/ | |
function ObjFactory() { | |
} | |
/** | |
* @param {number} level Low=1 Middle=2 High=3 | |
* @return {Obj} | |
*/ | |
ObjFactory.prototype.createRandom = function (level) { | |
var color, size, startAt, fadeinMs, fadeoutMs, startXyz, turningXyz, endXyz, objClass, | |
halfScene = Scene.SCENE_SEC / 2 * 1000, | |
r = Obj.RADIUS, | |
displayHeight = window.innerHeight / 3.78, | |
displayWidth = window.innerWidth / 3.78; | |
if (level === void 0) { level = rand(1, 3); } | |
color = 'rgb(' + | |
rand(0, 255) + ',' + | |
rand(0, 255) + ',' + | |
rand(0, 255) + ')'; | |
size = rand(r, r * 2); | |
startAt = rand(0, halfScene); | |
fadeinMs = rand(halfScene - 3000, halfScene); | |
fadeoutMs = rand(halfScene - 3000, halfScene) | |
if (rand(0, 4)) { // Don't scale at fadein. | |
startXyz = [ | |
rand(0, 1) ? rand(-r * 2, -r) : rand(r, r * 2) + displayWidth, | |
rand(0, 1) ? rand(-r * 2, -r) : rand(r, r * 2) + displayHeight, | |
rand(0, r / 2) | |
]; | |
} else { // Scale at fadein. | |
startXyz = [ | |
rand(0, displayWidth), | |
rand(0, displayHeight), | |
r * 2 | |
]; | |
} | |
turningXyz = [ | |
rand(r, displayWidth - r), | |
rand(r, displayHeight - r), | |
0 | |
]; | |
if (rand(0, 4)) { // Don't scale at fadeout. | |
endXyz = [ | |
rand(0, 1) ? rand(-r * 2, -r) : rand(r, r) + displayWidth, | |
rand(0, 1) ? rand(-r * 2, -r) : rand(r, r) + displayHeight, | |
rand(0, r / 2) | |
]; | |
} else { // Scale at fadeout. | |
endXyz = [ | |
rand(0, displayWidth), | |
rand(0, displayHeight), | |
r * 2 | |
]; | |
} | |
objClass = [Obj, ObjLow, ObjMiddle, ObjHigh][level]; | |
return new objClass(color, size, startAt, fadeinMs, fadeoutMs, startXyz, turningXyz, endXyz); | |
}; | |
// }}} ObjFactory | |
// {{{ Obj | |
/** | |
* @class | |
* @param {string} color CSS color | |
* @param {number} size mm | |
* @param {number} startAt ms | |
* @param {number} fadeinMs | |
* @param {number} fadeoutMs | |
* @param {number[]} startXyz [x mm, y mm, z mm] Right-handed system | |
* @param {number[]} turningXyz [x mm, y mm, z mm] Right-handed system | |
* @param {number[]} endXyz [x mm, y mm, z mm] Right-handed system | |
*/ | |
function Obj(color, size, startAt, fadeinMs, fadeoutMs, startXyz, turningXyz, endXyz) { | |
this.size = size; | |
this.startAt = startAt; | |
this.fadeinMs = fadeinMs; | |
this.fadeoutMs = fadeoutMs; | |
this.startXyz = startXyz; | |
this.turningXyz = turningXyz; | |
this.endXyz = endXyz; | |
this.node = document.createElement('div'); | |
this.node.classList.add('obj'); | |
this.node.style.backgroundColor = color; | |
this.node.style.height = size + 'mm'; | |
this.node.style.width = size + 'mm'; | |
this.isStarted = false; | |
this.isEnded = false; | |
} | |
/** @const mm */ | |
Obj.RADIUS = 60; | |
Obj.prototype.destruct = function () { | |
this.isEnded = true; | |
if (this.node.parentNode) { | |
document.body.removeChild(this.node); | |
} | |
}; | |
/** | |
* @param {number} ms Time ms of the scene. | |
*/ | |
Obj.prototype.animate = function (ms) { | |
var me = this; | |
function turn(evt) { | |
me.node.removeEventListener(turn); | |
me.node.style.transitionDuration = me.fadeoutMs + 'ms'; | |
me.placeAt(me.endXyz[0], me.endXyz[1], me.endXyz[2], 720); | |
setTimeout(function() { | |
me.node.addEventListener('transitionend', function (evt) { | |
me.isEnded = true; | |
me.destruct(); | |
}); | |
}, 0); | |
} | |
if (this.isEnded || this.isStarted || ms < this.startAt) { return; } | |
this.isStarted = true; | |
this.placeAt(this.startXyz[0], this.startXyz[1], this.startXyz[2], 0); | |
document.body.appendChild(this.node); | |
this.node.addEventListener('transitionend', turn); | |
setTimeout(function () { | |
me.node.style.transitionDuration = me.fadeinMs + 'ms'; | |
me.placeAt(me.turningXyz[0], me.turningXyz[1], me.turningXyz[2], 360); | |
}, 0); | |
}; | |
/** | |
* @param {number} x mm | |
* @param {number} y mm | |
* @param {number} z mm | |
* @param {number} deg 0-360 | |
*/ | |
Obj.prototype.placeAt = function (x, y, z, deg) { | |
var size = this.size, | |
r2 = Obj.RADIUS * 2, | |
scale = (r2 - z) / r2, | |
style = this.node.style; | |
if (deg === void 0) { deg = scale * 360; } | |
style.left = (x - size / 2) + 'mm'; | |
style.top = (y - size / 2) + 'mm'; | |
style.transform = 'rotate(' + deg + 'deg) scale(' + scale + ')'; | |
style.opacity = Math.sin(scale); | |
}; | |
// }}} Obj | |
// {{{ ObjLow | |
/** | |
* @class | |
* @augments Obj | |
*/ | |
function ObjLow() { | |
Obj.apply(this, arguments); | |
this.node.style.borderRadius = (this.size / 2) + 'mm'; | |
} | |
ObjLow.prototype = Object.create(Obj.prototype); | |
ObjLow.prototype.constructor = ObjLow; | |
// }}} ObjLow | |
// {{{ ObjMiddle | |
/** | |
* @class | |
* @augments Obj | |
*/ | |
function ObjMiddle() { | |
Obj.apply(this, arguments); | |
this.node.style.borderRadius = (this.size / 5) + 'mm'; | |
} | |
ObjMiddle.prototype = Object.create(Obj.prototype); | |
ObjMiddle.prototype.constructor = ObjMiddle; | |
// }}} ObjMiddle | |
// {{{ ObjHigh | |
/** | |
* @class | |
* @augments Obj | |
*/ | |
function ObjHigh() { | |
Obj.apply(this, arguments); | |
} | |
ObjHigh.prototype = Object.create(Obj.prototype); | |
ObjHigh.prototype.constructor = ObjHigh; | |
// }}} ObjHigh | |
global['App'] = App; | |
}(this)); | |
// vim:et sw=2 ts=2 sts=2 ff=unix fdm=marker: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment