diff --git a/js/sketch.js b/js/sketch.js index 0862cdb..06717c1 100755 --- a/js/sketch.js +++ b/js/sketch.js @@ -2,630 +2,615 @@ /* Copyright (C) 2013 Justin Windle, http://soulwire.co.uk */ (function ( root, factory ) { + + if ( typeof exports === 'object' ) { - if ( typeof exports === 'object' ) { + // CommonJS like + module.exports = factory(root); - // CommonJS like - module.exports = factory(root, root.document); + } else if ( typeof define === 'function' && define.amd ) { - } else if ( typeof define === 'function' && define.amd ) { + // AMD + define( function() { return factory(root); }); - // AMD - define( function() { return factory( root, root.document ); }); + } else { - } else { + // Browser global + root.Sketch = factory(root); + } - // Browser global - root.Sketch = factory( root, root.document ); - } +}( this, function (win) { -}( typeof window !== "undefined" ? window : this, function ( window, document ) { + "use strict"; + /* + ---------------------------------------------------------------------- - "use strict"; + Config - /* - ---------------------------------------------------------------------- + ---------------------------------------------------------------------- + */ - Config + var MATH_PROPS = 'E LN10 LN2 LOG2E LOG10E PI SQRT1_2 SQRT2 abs acos asin atan ceil cos exp floor log round sin sqrt tan atan2 pow max min'.split( ' ' ); + var HAS_SKETCH = '__hasSketch'; + var M = Math; - ---------------------------------------------------------------------- - */ + var CANVAS = 'canvas'; + var WEBGL = 'webgl'; + var DOM = 'dom'; - var MATH_PROPS = 'E LN10 LN2 LOG2E LOG10E PI SQRT1_2 SQRT2 abs acos asin atan ceil cos exp floor log round sin sqrt tan atan2 pow max min'.split( ' ' ); - var HAS_SKETCH = '__hasSketch'; - var M = Math; + var instances = []; - var CANVAS = 'canvas'; - var WEBGL = 'webgl'; - var DOM = 'dom'; + var defaults = { + fullscreen: true, + autostart: true, + autoclear: true, + autopause: true, + container: false, + interval: 1, + globals: true, + retina: false, + type: CANVAS + }; - var doc = document; - var win = window; + var keyMap = { + + 8: 'BACKSPACE', + 9: 'TAB', + 13: 'ENTER', + 16: 'SHIFT', + 27: 'ESCAPE', + 32: 'SPACE', + 37: 'LEFT', + 38: 'UP', + 39: 'RIGHT', + 40: 'DOWN' + }; - var instances = []; + /* + ---------------------------------------------------------------------- - var defaults = { + Utilities - fullscreen: true, - autostart: true, - autoclear: true, - autopause: true, - container: doc.body, - interval: 1, - globals: true, - retina: false, - type: CANVAS - }; + ---------------------------------------------------------------------- + */ - var keyMap = { + function isArray( object ) { - 8: 'BACKSPACE', - 9: 'TAB', - 13: 'ENTER', - 16: 'SHIFT', - 27: 'ESCAPE', - 32: 'SPACE', - 37: 'LEFT', - 38: 'UP', - 39: 'RIGHT', - 40: 'DOWN' - }; + return Object.prototype.toString.call( object ) == '[object Array]'; + } - /* - ---------------------------------------------------------------------- + function isFunction( object ) { - Utilities + return typeof object == 'function'; + } - ---------------------------------------------------------------------- - */ + function isNumber( object ) { - function isArray( object ) { + return typeof object == 'number'; + } - return Object.prototype.toString.call( object ) == '[object Array]'; - } + function isString( object ) { - function isFunction( object ) { + return typeof object == 'string'; + } - return typeof object == 'function'; - } + function keyName( code ) { - function isNumber( object ) { + return keyMap[ code ] || String.fromCharCode( code ); + } - return typeof object == 'number'; - } + function extend( target, source, overwrite ) { - function isString( object ) { + for ( var key in source ) - return typeof object == 'string'; - } + if ( overwrite || !( key in target ) ) - function keyName( code ) { + target[ key ] = source[ key ]; - return keyMap[ code ] || String.fromCharCode( code ); - } + return target; + } - function extend( target, source, overwrite ) { + function proxy( method, context ) { - for ( var key in source ) + return function() { - if ( overwrite || !( key in target ) ) + method.apply( context, arguments ); + }; + } - target[ key ] = source[ key ]; + function clone( target ) { - return target; - } + var object = {}; - function proxy( method, context ) { + for ( var key in target ) { - return function() { + if ( isFunction( target[ key ] ) ) - method.apply( context, arguments ); - }; - } + object[ key ] = proxy( target[ key ], target ); - function clone( target ) { + else - var object = {}; + object[ key ] = target[ key ]; + } - for ( var key in target ) { - - if ( key === 'webkitMovementX' || key === 'webkitMovementY' ) - continue; + return object; + } - if ( isFunction( target[ key ] ) ) + /* + ---------------------------------------------------------------------- - object[ key ] = proxy( target[ key ], target ); + Constructor - else + ---------------------------------------------------------------------- + */ - object[ key ] = target[ key ]; - } + function constructor( context ) { - return object; - } + var request, handler, target, parent, bounds, index, suffix, clock, node, copy, type, key, val, min, max, w, h; - /* - ---------------------------------------------------------------------- + var counter = 0; + var touches = []; + var resized = false; + var setup = false; + var ratio = win.devicePixelRatio || 1; + var isDiv = context.type == DOM; + var is2D = context.type == CANVAS; - Constructor + var mouse = { + x: 0.0, y: 0.0, + ox: 0.0, oy: 0.0, + dx: 0.0, dy: 0.0 + }; - ---------------------------------------------------------------------- - */ + var eventMap = [ - function constructor( context ) { + context.element, - var request, handler, target, parent, bounds, index, suffix, clock, node, copy, type, key, val, min, max, w, h; + pointer, 'mousedown', 'touchstart', + pointer, 'mousemove', 'touchmove', + pointer, 'mouseup', 'touchend', + pointer, 'click', + pointer, 'mouseout', + pointer, 'mouseover', - var counter = 0; - var touches = []; - var resized = false; - var setup = false; - var ratio = win.devicePixelRatio || 1; - var isDiv = context.type == DOM; - var is2D = context.type == CANVAS; + win.document, - var mouse = { - x: 0.0, y: 0.0, - ox: 0.0, oy: 0.0, - dx: 0.0, dy: 0.0 - }; + keypress, 'keydown', 'keyup', - var eventMap = [ + win, - context.eventTarget || context.element, + active, 'focus', 'blur', + resize, 'resize' + ]; - pointer, 'mousedown', 'touchstart', - pointer, 'mousemove', 'touchmove', - pointer, 'mouseup', 'touchend', - pointer, 'click', - pointer, 'mouseout', - pointer, 'mouseover', + var keys = {}; for ( key in keyMap ) keys[ keyMap[ key ] ] = false; - doc, + function trigger( method ) { - keypress, 'keydown', 'keyup', + if ( isFunction( method ) ) - win, + method.apply( context, [].splice.call( arguments, 1 ) ); + } - active, 'focus', 'blur', - resize, 'resize' - ]; + function bind( on ) { - var keys = {}; for ( key in keyMap ) keys[ keyMap[ key ] ] = false; + for ( index = 0; index < eventMap.length; index++ ) { - function trigger( method ) { + node = eventMap[ index ]; - if ( isFunction( method ) ) + if ( isString( node ) ) - method.apply( context, [].splice.call( arguments, 1 ) ); - } + target[ ( on ? 'add' : 'remove' ) + 'EventListener' ].call( target, node, handler, false ); - function bind( on ) { + else if ( isFunction( node ) ) - for ( index = 0; index < eventMap.length; index++ ) { + handler = node; - node = eventMap[ index ]; + else target = node; + } + } - if ( isString( node ) ) + function update() { - target[ ( on ? 'add' : 'remove' ) + 'EventListener' ].call( target, node, handler, false ); + cAF( request ); + request = rAF( update ); - else if ( isFunction( node ) ) + if ( !setup ) { - handler = node; + trigger( context.setup ); + setup = isFunction( context.setup ); + } - else target = node; - } - } + if ( !resized ) { + trigger( context.resize ); + resized = isFunction( context.resize ); + } - function update() { + if ( context.running && !counter ) { - cAF( request ); - request = rAF( update ); + context.dt = ( clock = +new Date() ) - context.now; + context.millis += context.dt; + context.now = clock; - if ( !setup ) { + trigger( context.update ); - trigger( context.setup ); - setup = isFunction( context.setup ); - } + // Pre draw - if ( !resized ) { - trigger( context.resize ); - resized = isFunction( context.resize ); - } + if ( is2D ) { - if ( context.running && !counter ) { + if ( context.retina ) { - context.dt = ( clock = +new Date() ) - context.now; - context.millis += context.dt; - context.now = clock; + context.save(); + context.scale( ratio, ratio ); + } - trigger( context.update ); + if ( context.autoclear ) - // Pre draw + context.clear(); + } - if ( is2D ) { + // Draw - if ( context.retina ) { + trigger( context.draw ); + + // Post draw - context.save(); - - if (context.autoclear) { - context.scale( ratio, ratio ); - } - } + if ( is2D && context.retina ) - if ( context.autoclear ) + context.restore(); + } - context.clear(); + counter = ++counter % context.interval; } - // Draw + function resize() { - trigger( context.draw ); + target = isDiv ? context.style : context.canvas; + suffix = isDiv ? 'px' : ''; - // Post draw + w = context.width; + h = context.height; - if ( is2D && context.retina ) + if ( context.fullscreen ) { - context.restore(); - } + h = context.height = win.innerHeight; + w = context.width = win.innerWidth; + } - counter = ++counter % context.interval; - } + if ( context.retina && is2D && ratio ) { - function resize() { + target.style.height = h + 'px'; + target.style.width = w + 'px'; - target = isDiv ? context.style : context.canvas; - suffix = isDiv ? 'px' : ''; + w *= ratio; + h *= ratio; + } - w = context.width; - h = context.height; + if ( target.height !== h ) - if ( context.fullscreen ) { + target.height = h + suffix; - h = context.height = win.innerHeight; - w = context.width = win.innerWidth; - } + if ( target.width !== w ) - if ( context.retina && is2D && ratio ) { + target.width = w + suffix; - target.style.height = h + 'px'; - target.style.width = w + 'px'; + if ( setup ) trigger( context.resize ); + } - w *= ratio; - h *= ratio; - } + function align( touch, target ) { - if ( target.height !== h ) + bounds = target.getBoundingClientRect(); - target.height = h + suffix; + touch.x = touch.pageX - bounds.left - (win.scrollX || win.pageXOffset); + touch.y = touch.pageY - bounds.top - (win.scrollY || win.pageYOffset); - if ( target.width !== w ) + return touch; + } - target.width = w + suffix; + function augment( touch, target ) { - if ( is2D && !context.autoclear && context.retina ) + align( touch, context.element ); - context.scale( ratio, ratio ); + target = target || {}; - if ( setup ) trigger( context.resize ); - } + target.ox = target.x || touch.x; + target.oy = target.y || touch.y; - function align( touch, target ) { + target.x = touch.x; + target.y = touch.y; - bounds = target.getBoundingClientRect(); + target.dx = target.x - target.ox; + target.dy = target.y - target.oy; - touch.x = touch.pageX - bounds.left - (win.scrollX || win.pageXOffset); - touch.y = touch.pageY - bounds.top - (win.scrollY || win.pageYOffset); + return target; + } - return touch; - } + function process( event ) { - function augment( touch, target ) { + event.preventDefault(); - align( touch, context.element ); + copy = clone( event ); + copy.originalEvent = event; - target = target || {}; + if ( copy.touches ) { - target.ox = target.x || touch.x; - target.oy = target.y || touch.y; + touches.length = copy.touches.length; - target.x = touch.x; - target.y = touch.y; + for ( index = 0; index < copy.touches.length; index++ ) - target.dx = target.x - target.ox; - target.dy = target.y - target.oy; + touches[ index ] = augment( copy.touches[ index ], touches[ index ] ); - return target; - } + } else { - function process( event ) { + touches.length = 0; + touches[0] = augment( copy, mouse ); + } - event.preventDefault(); + extend( mouse, touches[0], true ); - copy = clone( event ); - copy.originalEvent = event; + return copy; + } - if ( copy.touches ) { + function pointer( event ) { - touches.length = copy.touches.length; + event = process( event ); - for ( index = 0; index < copy.touches.length; index++ ) + min = ( max = eventMap.indexOf( type = event.type ) ) - 1; - touches[ index ] = augment( copy.touches[ index ], touches[ index ] ); + context.dragging = - } else { + /down|start/.test( type ) ? true : - touches.length = 0; - touches[0] = augment( copy, mouse ); - } + /up|end/.test( type ) ? false : - extend( mouse, touches[0], true ); + context.dragging; - return copy; - } + while( min ) - function pointer( event ) { + isString( eventMap[ min ] ) ? - event = process( event ); + trigger( context[ eventMap[ min-- ] ], event ) : - min = ( max = eventMap.indexOf( type = event.type ) ) - 1; + isString( eventMap[ max ] ) ? - context.dragging = + trigger( context[ eventMap[ max++ ] ], event ) : - /down|start/.test( type ) ? true : + min = 0; + } - /up|end/.test( type ) ? false : + function keypress( event ) { - context.dragging; + key = event.keyCode; + val = event.type == 'keyup'; + keys[ key ] = keys[ keyName( key ) ] = !val; - while( min ) + trigger( context[ event.type ], event ); + } - isString( eventMap[ min ] ) ? + function active( event ) { - trigger( context[ eventMap[ min-- ] ], event ) : + if ( context.autopause ) - isString( eventMap[ max ] ) ? + ( event.type == 'blur' ? stop : start )(); - trigger( context[ eventMap[ max++ ] ], event ) : + trigger( context[ event.type ], event ); + } - min = 0; - } + // Public API - function keypress( event ) { + function start() { - key = event.keyCode; - val = event.type == 'keyup'; - keys[ key ] = keys[ keyName( key ) ] = !val; + context.now = +new Date(); + context.running = true; + } - trigger( context[ event.type ], event ); - } + function stop() { - function active( event ) { + context.running = false; + } - if ( context.autopause ) + function toggle() { - ( event.type == 'blur' ? stop : start )(); + ( context.running ? stop : start )(); + } - trigger( context[ event.type ], event ); - } + function clear() { - // Public API + if ( is2D ) - function start() { + context.clearRect( 0, 0, context.width, context.height ); + } - context.now = +new Date(); - context.running = true; - } + function destroy() { - function stop() { + parent = context.element.parentNode; + index = instances.indexOf( context ); - context.running = false; - } + if ( parent ) parent.removeChild( context.element ); + if ( ~index ) instances.splice( index, 1 ); - function toggle() { + bind( false ); + stop(); + } - ( context.running ? stop : start )(); - } + extend( context, { - function clear() { + touches: touches, + mouse: mouse, + keys: keys, + + dragging: false, + running: false, + millis: 0, + now: NaN, + dt: NaN, + + destroy: destroy, + toggle: toggle, + clear: clear, + start: start, + stop: stop + }); - if ( is2D ) + instances.push( context ); - context.clearRect( 0, 0, context.width * ratio, context.height * ratio ); + return ( context.autostart && start(), bind( true ), resize(), update(), context ); } - function destroy() { + /* + ---------------------------------------------------------------------- - parent = context.element.parentNode; - index = instances.indexOf( context ); + Global API - if ( parent ) parent.removeChild( context.element ); - if ( ~index ) instances.splice( index, 1 ); + ---------------------------------------------------------------------- + */ - bind( false ); - stop(); - } - - extend( context, { + var element, context, Sketch = { - touches: touches, - mouse: mouse, - keys: keys, + CANVAS: CANVAS, + WEB_GL: WEBGL, + WEBGL: WEBGL, + DOM: DOM, - dragging: false, - running: false, - millis: 0, - now: NaN, - dt: NaN, + instances: instances, - destroy: destroy, - toggle: toggle, - clear: clear, - start: start, - stop: stop - }); + install: function( context ) { - instances.push( context ); + if ( !context[ HAS_SKETCH ] ) { - return ( context.autostart && start(), bind( true ), resize(), update(), context ); - } + for ( var i = 0; i < MATH_PROPS.length; i++ ) - /* - ---------------------------------------------------------------------- + context[ MATH_PROPS[i] ] = M[ MATH_PROPS[i] ]; - Global API + extend( context, { - ---------------------------------------------------------------------- - */ + TWO_PI: M.PI * 2, + HALF_PI: M.PI / 2, + QUATER_PI: M.PI / 4, - var element, context, Sketch = { + random: function( min, max ) { - CANVAS: CANVAS, - WEB_GL: WEBGL, - WEBGL: WEBGL, - DOM: DOM, + if ( isArray( min ) ) - instances: instances, + return min[ ~~( M.random() * min.length ) ]; - install: function( context ) { + if ( !isNumber( max ) ) - if ( !context[ HAS_SKETCH ] ) { + max = min || 1, min = 0; - for ( var i = 0; i < MATH_PROPS.length; i++ ) + return min + M.random() * ( max - min ); + }, - context[ MATH_PROPS[i] ] = M[ MATH_PROPS[i] ]; + lerp: function( min, max, amount ) { - extend( context, { + return min + amount * ( max - min ); + }, - TWO_PI: M.PI * 2, - HALF_PI: M.PI / 2, - QUARTER_PI: M.PI / 4, + map: function( num, minA, maxA, minB, maxB ) { - random: function( min, max ) { + return ( num - minA ) / ( maxA - minA ) * ( maxB - minB ) + minB; + } + }); - if ( isArray( min ) ) + context[ HAS_SKETCH ] = true; + } + }, - return min[ ~~( M.random() * min.length ) ]; + create: function( options ) { - if ( !isNumber( max ) ) + options = extend( options || {}, defaults ); - max = min || 1, min = 0; + if ( options.globals ) Sketch.install( self ); - return min + M.random() * ( max - min ); - }, + element = options.element = options.element || win.document.createElement( options.type === DOM ? 'div' : 'canvas' ); - lerp: function( min, max, amount ) { + context = options.context = options.context || (function() { - return min + amount * ( max - min ); - }, + switch( options.type ) { - map: function( num, minA, maxA, minB, maxB ) { + case CANVAS: - return ( num - minA ) / ( maxA - minA ) * ( maxB - minB ) + minB; - } - }); + return element.getContext( '2d', options ); - context[ HAS_SKETCH ] = true; - } - }, + case WEBGL: - create: function( options ) { + return element.getContext( 'webgl', options ) || element.getContext( 'experimental-webgl', options ); - options = extend( options || {}, defaults ); + case DOM: - if ( options.globals ) Sketch.install( self ); + return element.canvas = element; + } - element = options.element = options.element || doc.createElement( options.type === DOM ? 'div' : 'canvas' ); + })(); - context = options.context = options.context || (function() { + ( options.container || win.document.body ).appendChild( element ); - switch( options.type ) { + return Sketch.augment( context, options ); + }, - case CANVAS: + augment: function( context, options ) { - return element.getContext( '2d', options ); + options = extend( options || {}, defaults ); - case WEBGL: + options.element = context.canvas || context; + options.element.className += ' sketch'; - return element.getContext( 'webgl', options ) || element.getContext( 'experimental-webgl', options ); + extend( context, options, true ); - case DOM: - - return element.canvas = element; + return constructor( context ); } + }; - })(); + /* + ---------------------------------------------------------------------- - ( options.container || doc.body ).appendChild( element ); + Shims - return Sketch.augment( context, options ); - }, + ---------------------------------------------------------------------- + */ - augment: function( context, options ) { + var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; + var scope = self; + var then = 0; - options = extend( options || {}, defaults ); + var a = 'AnimationFrame'; + var b = 'request' + a; + var c = 'cancel' + a; - options.element = context.canvas || context; - options.element.className += ' sketch'; + var rAF = scope[ b ]; + var cAF = scope[ c ]; - extend( context, options, true ); + for ( var i = 0; i < vendors.length && !rAF; i++ ) { - return constructor( context ); + rAF = scope[ vendors[ i ] + 'Request' + a ]; + cAF = scope[ vendors[ i ] + 'Cancel' + a ]; } - }; - - /* - ---------------------------------------------------------------------- - - Shims - ---------------------------------------------------------------------- - */ + scope[ b ] = rAF = rAF || function( callback ) { - var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; - var scope = self; - var then = 0; + var now = +new Date(); + var dt = M.max( 0, 16 - ( now - then ) ); + var id = setTimeout( function() { + callback( now + dt ); + }, dt ); - var a = 'AnimationFrame'; - var b = 'request' + a; - var c = 'cancel' + a; - - var rAF = scope[ b ]; - var cAF = scope[ c ]; - - for ( var i = 0; i < vendors.length && !rAF; i++ ) { - - rAF = scope[ vendors[ i ] + 'Request' + a ]; - cAF = scope[ vendors[ i ] + 'Cancel' + a ]; - } - - scope[ b ] = rAF = rAF || function( callback ) { - - var now = +new Date(); - var dt = M.max( 0, 16 - ( now - then ) ); - var id = setTimeout( function() { - callback( now + dt ); - }, dt ); - - then = now + dt; - return id; - }; + then = now + dt; + return id; + }; - scope[ c ] = cAF = cAF || function( id ) { - clearTimeout( id ); - }; + scope[ c ] = cAF = cAF || function( id ) { + clearTimeout( id ); + }; - /* - ---------------------------------------------------------------------- + /* + ---------------------------------------------------------------------- - Output + Output - ---------------------------------------------------------------------- - */ + ---------------------------------------------------------------------- + */ - return Sketch; + return Sketch; }));