1/** 2 * elastiStack.js v1.0.0 3 * http://www.codrops.com 4 * 5 * Licensed under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7 * 8 * Copyright 2013, Codrops 9 * http://www.codrops.com 10 */ 11;( function( window ) { 12 13 'use strict'; 14 15 function extend( a, b ) { 16 for( var key in b ) { 17 if( b.hasOwnProperty( key ) ) { 18 a[key] = b[key]; 19 } 20 } 21 return a; 22 } 23 24 // support 25 var is3d = !!getStyleProperty( 'perspective' ), 26 supportTransitions = Modernizr.csstransitions, 27 // transition end event name 28 transEndEventNames = { 29 'WebkitTransition': 'webkitTransitionEnd', 30 'MozTransition': 'transitionend', 31 'OTransition': 'oTransitionEnd', 32 'msTransition': 'MSTransitionEnd', 33 'transition': 'transitionend' 34 }, 35 transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ]; 36 37 function ElastiStack( el, options ) { 38 this.container = el; 39 this.options = extend( {}, this.options ); 40 extend( this.options, options ); 41 this._init(); 42 } 43 44 function setTransformStyle( el, tval ) { 45 el.style.WebkitTransform = tval; 46 el.style.msTransform = tval; 47 el.style.transform = tval; 48 } 49 50 ElastiStack.prototype.options = { 51 // distDragBack: if the user stops dragging the image in a area that does not exceed [distDragBack]px for either x or y then the image goes back to the stack 52 distDragBack : 200, 53 // distDragMax: if the user drags the image in a area that exceeds [distDragMax]px for either x or y then the image moves away from the stack 54 distDragMax : 450, 55 // callback 56 onUpdateStack : function( current ) { return false; } 57 }; 58 59 ElastiStack.prototype._init = function() { 60 // items 61 this.items = [].slice.call( this.container.children ); 62 // total items 63 this.itemsCount = this.items.length; 64 // current item's index (the one on the top of the stack) 65 this.current = 0; 66 // set initial styles 67 this._setStackStyle(); 68 // return if no items or only one 69 if( this.itemsCount <= 1 ) return; 70 // add dragging capability 71 this._initDragg(); 72 // init drag events 73 this._initEvents(); 74 }; 75 76 ElastiStack.prototype._initEvents = function() { 77 var self = this; 78 this.draggie.on( 'dragStart', function( i, e, p ) { self._onDragStart( i, e, p ); } ); 79 this.draggie.on( 'dragMove', function( i, e, p ) { self._onDragMove( i, e, p ); } ); 80 this.draggie.on( 'dragEnd', function( i, e, p ) { self._onDragEnd( i, e, p ); } ); 81 }; 82 83 ElastiStack.prototype._setStackStyle = function() { 84 var item1 = this._firstItem(), item2 = this._secondItem(), item3 = this._thirdItem(); 85 86 if( item1 ) { 87 item1.style.opacity = 1; 88 item1.style.zIndex = 4; 89 setTransformStyle( item1, is3d ? 'translate3d(0,0,0)' : 'translate(0,0)' ); 90 } 91 92 if( item2 ) { 93 item2.style.opacity = 1; 94 item2.style.zIndex = 3; 95 setTransformStyle( item2, is3d ? 'translate3d(0,0,-60px)' : 'translate(0,0)' ); 96 } 97 98 if( item3 ) { 99 item3.style.opacity = 1; 100 item3.style.zIndex = 2; 101 setTransformStyle( item3, is3d ? 'translate3d(0,0,-120px)' : 'translate(0,0)' ); 102 } 103 }; 104 105 ElastiStack.prototype._moveAway = function( instance ) { 106 // disable drag 107 this._disableDragg(); 108 109 // add class "animate" 110 classie.add( instance.element, 'animate' ); 111 112 // calculate how much to translate in the x and y axis 113 var tVal = this._getTranslateVal( instance ); 114 115 // apply it 116 setTransformStyle( instance.element, is3d ? 'translate3d(' + tVal.x + 'px,' + tVal.y + 'px, 0px)' : 'translate(' + tVal.x + 'px,' + tVal.y + 'px)' ); 117 118 // item also fades out 119 instance.element.style.opacity = 0; 120 121 // other items move back to stack 122 var item2 = this._secondItem(), item3 = this._thirdItem(); 123 124 if( item2 ) { 125 classie.add( item2, 'move-back' ); 126 classie.add( item2, 'animate' ); 127 setTransformStyle( item2, is3d ? 'translate3d(0,0,-60px)' : 'translate(0,0)' ); 128 } 129 if( item3 ) { 130 classie.add( item3, 'move-back' ); 131 classie.add( item3, 'animate' ); 132 setTransformStyle( item3, is3d ? 'translate3d(0,0,-120px)' : 'translate(0,0)' ); 133 } 134 135 // after transition ends.. 136 var self = this, 137 onEndTransFn = function() { 138 instance.element.removeEventListener( transEndEventName, onEndTransFn ); 139 140 // reset first item
141 setTransformStyle( instance.element, is3d ? 'translate3d(0,0,-180px)' : 'translate(0,0,0)' ); 142 instance.element.style.left = instance.element.style.top = '0px'; 143 instance.element.style.zIndex = -1; 144 classie.remove( instance.element, 'animate' ); 145 146 // reorder stack 147 self.current = self.current < self.itemsCount - 1 ? self.current + 1 : 0; 148 // new front items 149 var item1 = self._firstItem(), 150 item2 = self._secondItem(), 151 item3 = self._thirdItem(); 152 153 // reset transition timing function 154 classie.remove( item1, 'move-back' ); 155 if( item2 ) classie.remove( item2, 'move-back' ); 156 if( item3 ) classie.remove( item3, 'move-back' ); 157 158 setTimeout( function() { 159 // the upcoming one will animate.. 160 classie.add( self._lastItem(), 'animate' ); 161 // reset style 162 self._setStackStyle(); 163 }, 25 ); 164 165 // add dragging capability 166 self._initDragg(); 167 168 // init drag events on new current item 169 self._initEvents(); 170 171 // callback 172 self.options.onUpdateStack( self.current ); 173 }; 174 175 if( supportTransitions ) { 176 instance.element.addEventListener( transEndEventName, onEndTransFn ); 177 } 178 else { 179 onEndTransFn.call(); 180 } 181 }; 182 183 ElastiStack.prototype._moveBack = function( instance ) { 184 var item2 = this._secondItem(), item3 = this._thirdItem(); 185 186 classie.add( instance.element, 'move-back' ); 187 classie.add( instance.element, 'animate' ); 188 setTransformStyle( instance.element, is3d ? 'translate3d(0,0,0)' : 'translate(0,0)' ); 189 instance.element.style.left = '0px'; 190 instance.element.style.top = '0px'; 191 192 if( item2 ) { 193 classie.add( item2, 'move-back' ); 194 classie.add( item2, 'animate' ); 195 setTransformStyle( item2, is3d ? 'translate3d(0,0,-60px)' : 'translate(0,0)' ); 196 } 197 if( item3 ) { 198 classie.add( item3, 'move-back' ); 199 classie.add( item3, 'animate' ); 200 setTransformStyle( item3, is3d ? 'translate3d(0,0,-120px)' : 'translate(0,0)' ); 201 } 202 }; 203 204 ElastiStack.prototype._onDragStart = function( instance, event, pointer ) { 205 // remove transition classes if any 206 var item2 = this._secondItem(), item3 = this._thirdItem(); 207 208 classie.remove( instance.element, 'move-back' ); 209 classie.remove( instance.element, 'animate' ); 210 211 if( item2 ) { 212 classie.remove( item2, 'move-back' ); 213 classie.remove( item2, 'animate' ); 214 } 215 if( item3 ) { 216 classie.remove( item3, 'move-back' ); 217 classie.remove( item3, 'animate' ); 218 } 219 }; 220 221 ElastiStack.prototype._onDragMove = function( instance, event, pointer ) { 222 if( this._outOfBounds( instance ) ) { 223 this._moveAway( instance ); 224 } 225 else { 226 // the second and third items also move 227 var item2 = this._secondItem(), item3 = this._thirdItem(); 228 if( item2 ) { 229 setTransformStyle( item2, is3d ? 'translate3d(' + ( instance.position.x * .6 ) + 'px,' + ( instance.position.y * .6 ) + 'px, -60px)' : 'translate(' + ( instance.position.x * .6 ) + 'px,' + ( instance.position.y * .6 ) + 'px)' ); 230 } 231 if( item3 ) { 232 setTransformStyle( item3, is3d ? 'translate3d(' + ( instance.position.x * .3 ) + 'px,' + ( instance.position.y * .3 ) + 'px, -120px)' : 'translate(' + ( instance.position.x * .3 ) + 'px,' + ( instance.position.y * .3 ) + 'px)' ); 233 } 234 } 235 }; 236 237 ElastiStack.prototype._onDragEnd = function( instance, event, pointer ) { 238 if( this._outOfBounds( instance ) ) return; 239 if( this._outOfSight(instance) ) { 240 this._moveAway( instance ); 241 } 242 else { 243 this._moveBack( instance ); 244 } 245 }; 246 247 ElastiStack.prototype._initDragg = function() { 248 this.draggie = new Draggabilly( this.items[ this.current ] ); 249 }; 250 251 ElastiStack.prototype._disableDragg = function() { 252 this.draggie.disable(); 253 }; 254 255 // returns true if x or y is bigger than distDragMax 256 ElastiStack.prototype._outOfBounds = function( el ) { 257 return Math.abs( el.position.x ) > this.options.distDragMax || Math.abs( el.position.y ) > this.options.distDragMax; 258 }; 259 260 // returns true if x or y is bigger than distDragBack 261 ElastiStack.prototype._outOfSight = function( el ) { 262 return Math.abs( el.position.x ) > this.options.distDragBack || Math.abs( el.position.y ) > this.options.distDragBack; 263 }; 264 265 ElastiStack.prototype._getTranslateVal = function( el ) {
266 var h = Math.sqrt( Math.pow( el.position.x, 2 ) + Math.pow( el.position.y, 2 ) ), 267 a = Math.asin( Math.abs( el.position.y ) / h ) / ( Math.PI / 180 ), 268 hL = h + this.options.distDragBack, 269 dx = Math.cos( a * ( Math.PI / 180 ) ) * hL, 270 dy = Math.sin( a * ( Math.PI / 180 ) ) * hL, 271 tx = dx - Math.abs( el.position.x ), 272 ty = dy - Math.abs( el.position.y ); 273 274 return { 275 x : el.position.x > 0 ? tx : tx * -1, 276 y : el.position.y > 0 ? ty : ty * -1 277 } 278 }; 279 280 // returns the first item in the stack 281 ElastiStack.prototype._firstItem = function() { 282 return this.items[ this.current ]; 283 }; 284 285 // returns the second item in the stack 286 ElastiStack.prototype._secondItem = function() { 287 if( this.itemsCount >= 2 ) { 288 return this.current + 1 < this.itemsCount ? this.items[ this.current + 1 ] : this.items[ Math.abs( this.itemsCount - ( this.current + 1 ) ) ]; 289 } 290 }; 291 292 // returns the third item in the stack 293 ElastiStack.prototype._thirdItem = function() { 294 if( this.itemsCount >= 3 ) { 295 return this.current + 2 < this.itemsCount ? this.items[ this.current + 2 ] : this.items[ Math.abs( this.itemsCount - ( this.current + 2 ) ) ]; 296 } 297 }; 298 299 // returns the last item (of the first three) in the stack 300 ElastiStack.prototype._lastItem = function() { 301 if( this.itemsCount >= 3 ) { 302 return this._thirdItem(); 303 } 304 else { 305 return this._secondItem(); 306 } 307 }; 308 309 // add to global namespace 310 window.ElastiStack = ElastiStack; 311 312})( window );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.