Toggle navigation
Sign Up
Log In
Explore
Works
Folders
Tools
Collections
Artists
Groups
Groups
Topics
Tasks
Tasks
Jobs
Teams
Jobs
Recommendation
More Effects...
JS
/** * Particle Wall * * This is a reproduction of Robert Penner's Particle Wall exercise * from his book titled "Robert Penner's Programming Macromedia Flash MX". * It was ported from Actionscript/Flash to Javascript/Canvas and has been * released with the permission of the author. * * Copyright (c) 2013 Michael Fields * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ (function ( window, $ ) { "use strict"; var document, stage, animation, gradient, Sphere, plane, button, form, rotation; document = window.document; /*************************************************** Stage: Canvas Object ****************************************************/ stage = {}; stage.el = $( stage ); stage.canvas = window.document.getElementById( 'stage' ); stage.context = stage.canvas.getContext( '2d' ); /*************************************************** Animation: Object ****************************************************/ animation = { lastTime: 0, broadcaster: $( {} ), frame: undefined }; animation.init = function() { animation.start(); animation.listen( form, [ 'motion:pause', 'motion:play' ] ); }; animation.listen = function( element, actions ) { var i; for ( i = 0; i < actions.length; i++ ) { element.on( actions[i], animation.act.bind( animation ) ); } }; animation.act = function( e ) { switch ( e.type ) { case 'motion:pause' : animation.pause(); break; case 'motion:play' : animation.play(); break; } }; animation.start = function() { var currTime = new Date().getTime(), timeToCall = Math.max( 0, 16 - ( currTime - animation.lastTime ) ); animation.frame = window.setTimeout( animation.start, timeToCall ); animation.lastTime = currTime + timeToCall; animation.broadcaster.trigger( 'nextFrame' ); }; animation.play = function() { if ( ! animation.frame ) { animation.start(); } }; animation.pause = function() { if ( animation.frame ) { animation.frame = window.clearTimeout( animation.frame ); animation.frame = undefined; return true; } return false; }; /*************************************************** Gradient: Canvas Object ****************************************************/ gradient = ( function () { var g = document.createElement( 'canvas' ), gc = g.getContext( '2d' ), size = 100, h = size / 2, glow = gc.createRadialGradient( h / 1.4, h / 1.4, 1, h, h, h ); g.width = size; g.height = size; glow.addColorStop( 0, 'rgba( 255, 255, 255, 0.3 )' ); glow.addColorStop( 1, 'rgba( 255, 255 ,255, 0 )' ); gc.fillStyle = glow; gc.fillRect( 0, 0, size, size ); return g; } () ); /*************************************************** Sphere: Constructor ****************************************************/ Sphere = function( args ) { this.x = args.x; this.y = args.y; this.z = args.z; this.radius = ( undefined !== args.radius ) ? args.radius : 10; this.color = args.color; this.range = { min: 50, max: 255 }; }; Sphere.prototype.project = function ( p ) { p = 1100 / ( this.z + 300 ); return new this.constructor( { x: this.x * p, y: this.y * p, z: 0, radius: ( ( this.radius * 2 ) * p ) / 2, color: this.color } ); }; Sphere.prototype.rotateX = function ( angle ) { var y, z; angle = angle * ( Math.PI / 180 ); y = this.y * Math.cos( angle ) - this.z * Math.sin( angle ); z = this.y * Math.sin( angle ) + this.z * Math.cos( angle ); this.y = y; this.z = z; }; Sphere.prototype.rotateY = function( angle ) { var x, z; angle = angle * ( Math.PI / 180 ); x = this.x * Math.cos( angle ) - this.z * Math.sin( angle ); z = this.x * Math.sin( angle ) + this.z * Math.cos( angle ); this.x = x; this.z = z; }; Sphere.prototype.rotateZ = function ( angle ) { var x, y; angle = angle * ( Math.PI / 180 ); x = this.x * Math.cos( angle ) - this.y * Math.sin( angle ); y = this.x * Math.sin( angle ) + this.y * Math.cos( angle ); this.x = x; this.y = y; }; Sphere.prototype.draw = function() { var ctx = stage.context, p = this.project(), c = p.color; /* Draw the ball using only the projected values. */ ctx.beginPath(); ctx.moveTo( p.x, p.y ); ctx.arc( p.x, p.y, p.radius, 0, Math.PI * 2 ); ctx.closePath(); ctx.fillStyle = 'rgba( ' + c.r + ', ' + c.g + ', ' + c.b + ', ' + c.a + ' )'; ctx.fill(); ctx.drawImage( gradient, p.x - p.radius -1, p.y - p.radius -1, p.radius * 1.9, p.radius * 1.9 ); }; /*************************************************** Plane: Object ****************************************************/ plane = { spheres: [], size: 250, divisions: 5, colors: [ { r: 161, g: 98, b: 191, a: 1 }, // Purple { r: 115, g: 175, b: 255, a: 1 }, // Blue { r: 234, g: 222, b: 30, a: 1 }, // Yellow { r: 113, g: 233, b: 122, a: 1 }, // Green { r: 250, g: 75, b: 75, a: 1 } // Red ], rotate: { x: true, y: true, z: true } }; plane.init = function() { plane.create(); plane.draw(); animation.broadcaster.on( 'nextFrame', plane.draw ); form.on( 'motion:rotate', plane.changeRotation ); }; plane.create = function() { var i, j, c; for ( i = 0; i <= plane.divisions; i++ ) { for ( j = 0; j <= plane.divisions; j++ ) { c = Math.floor( Math.random() * plane.colors.length ); plane.spheres.push( new Sphere( { x: plane.size * ( i / plane.divisions ) - plane.size / 2, y: plane.size * ( j / plane.divisions ) - plane.size / 2, z: 0, color: plane.colors[c], radius: 12 } ) ); } } }; plane.draw = function() { var i = plane.spheres.length, ctx = stage.context; /* * Sort the Spheres by z axis. * * This is necessary because there is no z axis in canvas. * Instead the z axis needs to be achieved through the order * in which the spheres are drawn. Those further away are * drawn first and those closest are drawn last. */ plane.spheres.sort( function( a, b ) { if ( a.z === b.z ) { return 0; } if ( a.z > b.z ) { return 1; } return -1; } ); ctx.clearRect( 0, 0, stage.canvas.width, stage.canvas.height ); while ( i-- ) { ctx.save(); ctx.translate( stage.canvas.width / 2, stage.canvas.height / 2 ); if ( plane.rotate.x ) { plane.spheres[i].rotateX( 1 ); } if ( plane.rotate.y ) { plane.spheres[i].rotateY( 1 ); } if ( plane.rotate.z ) { plane.spheres[i].rotateZ( 1 ); } plane.spheres[i].draw(); ctx.restore(); } }; plane.changeRotation = function( event, axis, status ) { status = ( 'play' === status ) ? true : false; plane.rotate[axis] = status; }; /*************************************************** UI Form: jQuery Object. ****************************************************/ form = {}; form.init = function() { form = $( '#user' ); }; /*************************************************** UI Rotation: Rotation Controls. ****************************************************/ rotation = {}; rotation.init = function () { rotation.el = $( '#rotation' ); rotation.x = $( '#rotate-x' ); rotation.y = $( '#rotate-y' ); rotation.z = $( '#rotate-z' ); rotation.toggle = rotation.el.find( 'legend' ); rotation.value = rotation.isChecked(); }; rotation.bind = function() { rotation.x.on( 'change', rotation.transmit.bind( rotation ) ); rotation.y.on( 'change', rotation.transmit.bind( rotation ) ); rotation.z.on( 'change', rotation.transmit.bind( rotation ) ); rotation.toggle.on( 'click', rotation.peekaboo.bind( rotation ) ); }; rotation.isChecked = function() { var x, y, z; x = rotation.x.is( ':checked' ); y = rotation.y.is( ':checked' ); z = rotation.z.is( ':checked' ); return ( x || y || z ); }; rotation.transmit = function( e ) { var el, newValue, axis, action; el = $( e.target ); newValue = rotation.isChecked(); if ( newValue !== rotation.value ) { rotation.value = newValue; if ( el.is( ':checked' ) ) { rotation.el.trigger( 'rotation:true' ); form.trigger( 'motion:play' ); } else { rotation.el.trigger( 'rotation:false' ); form.trigger( 'motion:pause' ); } } switch( el.attr( 'id' ) ) { case 'rotate-x' : axis = 'x'; break; case 'rotate-y' : axis = 'y'; break; case 'rotate-z' : axis = 'z'; break; } action = ( el.is( ':checked' ) ) ? 'play' : 'pause'; form.trigger( 'motion:rotate', [axis, action] ); }; rotation.peekaboo = function() { if ( rotation.el.hasClass( 'visibility' ) ) { rotation.el.removeClass( 'visibility' ); } else { rotation.el.addClass( 'visibility' ); } }; /*************************************************** UI Element: Button. ****************************************************/ button = { states: [ 'play', 'pause', 'disabled' ] }; button.init = function() { button.el = $( '#toggle' ); button.el.on( 'click', button.click.bind( button ) ); button.state = button.getStateFromDOM(); }; button.bind = function() { rotation.el.on( 'motion:pause', button.transmit.bind( button ) ); rotation.el.on( 'motion:play', button.transmit.bind( button ) ); rotation.el.on( 'rotation:true', button.transmit.bind( button ) ); rotation.el.on( 'rotation:false', button.transmit.bind( button ) ); }; button.transmit = function( e ) { switch ( e.type ) { case 'motion:pause' : button.changeState( 'pause' ); form.trigger( 'motion:play' ); break; case 'motion:play' : button.changeState( 'play' ); form.trigger( 'motion:pause' ); break; case 'rotation:true' : button.changeState( 'play' ); button.el.trigger( 'button:pause' ); break; case 'rotation:false' : button.changeState( 'disabled' ); button.el.trigger( 'button:disabled' ); break; } }; button.getStateFromDOM = function() { var state = button.el.data( 'state' ); if ( -1 < button.states.indexOf( state ) ) { return state; } }; button.changeState = function( state ) { if ( -1 < button.states.indexOf( state ) ) { button.state = state; button.el.data( 'state', state ); switch ( state ) { case 'pause' : button.el .data( 'state', 'play' ) .val( 'Play' ) .removeClass( 'disabled' ); return 'pause'; case 'play' : button.el .data( 'state', 'pause' ) .val( 'Pause' ) .removeClass( 'disabled' ); return 'play'; case 'disabled' : button.el .data( 'state', 'disabled' ) .val( 'Disabled' ) .addClass( 'disabled' ); return 'disabled'; } } return false; }; button.click = function( e ) { var newState, oldState; oldState = button.el.data( 'state' ); newState = button.changeState( button.el.data( 'state' ) ); if ( 'disabled' === oldState && oldState === newState ) { e.preventDefault(); } switch ( newState ) { case 'pause' : form.trigger( 'motion:pause' ); break; case 'play' : form.trigger( 'motion:play' ); break; case 'disabled' : break; } }; /*************************************************** Set everything into motion. ****************************************************/ $( document ) .ready( form.init ) .ready( plane.init ) .ready( rotation.init ) .ready( button.init ) .ready( animation.init ) .ready( button.bind ) .ready( rotation.bind ); } ( window, jQuery ) );
CSS
body { background: #000; color: #555; font-family: Helvetica, Arial, sans-serif; line-height: 1.4; margin: 0; padding: 0; } canvas { background: transparent; display: block; margin: 1em auto; } #user { margin: 5em auto 1em; position: relative; } #rotation { border: 0; margin: 0 auto 1em; position: relative; top: -1.5em; z-index: 1; text-align: center; width: 7em; } #rotation legend { color: #555; cursor: pointer; opacity: 0.3; position: relative; top: 2em; text-transform: lowercase; -moz-transition: opacity 0.25s; -ms-transition: opacity 0.25s; -o-transition: opacity 0.25s; -webkit-transition: opacity 0.25s; transition: opacity 0.25s; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: moz-none; -ms-user-select: none; user-select: none; } #rotation legend:hover, #rotation.visibility legend { opacity: 1; } #rotation input { display: none; } #rotation label { display: block; opacity: 0; cursor: pointer; -moz-transition: opacity 0.25s; -ms-transition: opacity 0.25s; -o-transition: opacity 0.25s; -webkit-transition: opacity 0.25s; transition: opacity 0.25s; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: moz-none; -ms-user-select: none; user-select: none; white-space: pre; } #rotation.visibility label { opacity: 1; -moz-transition: opacity 1s; -ms-transition: opacity 1s; -o-transition: opacity 1s; -webkit-transition: opacity 1s; transition: opacity 1s; } #rotation label:first-of-type { margin-top: 2.5em; } #rotation label:after { content: ''; cursor: pointer; display: inline-block; font-size: 1.1em; position: relative; left: 0.5em; width: 0.75em; height: 0.75em; } #rotation input + label:after { color: #ccc; content: '\2714'; display: inline-block; line-height: 0.8; position: relative: -moz-transform: rotate( -10deg ); -ms-transform: rotate( -10deg ); -o-transform: rotate( -10deg ); -webkit-transform: rotate( -10deg ); transform: rotate( -10deg ); } #rotation input:checked + label:after { color: #555; } #toggle { background: rgb( 250, 75, 75 ); border: 1px solid rgb( 200, 75, 75 ); border-radius: 10px; color: rgb( 250, 250, 250 ); cursor: pointer; display: block; font-size: 1em; line-height: 2; margin: 0 auto; opacity: 0.3; position: relative; z-index: 2; text-transform: uppercase; -moz-transition: opacity 0.5s; -ms-transition: opacity 0.5s; -o-transition: opacity 0.5s; -webkit-transition: opacity 1s; transition: opacity 1s; width: 6em; } #toggle:hover { opacity: 1; } #toggle.disabled:hover { cursor: auto; opacity: 0.3; -moz-transition: none; -ms-transition: none; -o-transition: none; -webkit-transition: none; transition: none; } input[type="button"]:hover { } input[type="button"]:active, input[type="button"]:focus { }
HTML
Particle Wall
[Rotation]
x
y
z
Join Effecthub.com
Working with Global Gaming Artists and Developers!
Login
Sign Up
Or Login with Your Email Address:
Email
Password
Remember
Or Sign Up with Your Email Address:
Your Email
This field must contain a valid email
Set Password
Password should be at least 1 character
Stay informed via email