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 2015, 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 support = { transitions: Modernizr.csstransitions }, 27 // transition end event name 28 transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' }, 29 transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], 30 onEndTransition = function( el, callback ) { 31 var onEndCallbackFn = function( ev ) { 32 if( support.transitions ) { 33 if( ev.target != this ) return; 34 this.removeEventListener( transEndEventName, onEndCallbackFn ); 35 } 36 if( callback && typeof callback === 'function' ) { callback.call(this); } 37 }; 38 if( support.transitions ) { 39 el.addEventListener( transEndEventName, onEndCallbackFn ); 40 } 41 else { 42 onEndCallbackFn(); 43 } 44 }; 45 46 function ElastiStack( el, options ) { 47 this.container = el; 48 this.options = extend( {}, this.options ); 49 extend( this.options, options ); 50 this._init(); 51 } 52 53 function setTransformStyle( el, tval ) { 54 el.style.WebkitTransform = tval; 55 el.style.msTransform = tval; 56 el.style.transform = tval; 57 } 58 59 ElastiStack.prototype.options = { 60 // 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 61 distDragBack : 200, 62 // 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 63 distDragMax : 450, 64 // callback 65 onUpdateStack : function( current ) { return false; } 66 }; 67 68 ElastiStack.prototype._init = function() { 69 // items 70 this.items = [].slice.call( this.container.children ); 71 // total items 72 this.itemsCount = this.items.length; 73 // current item's index (the one on the top of the stack) 74 this.current = 0; 75 // set initial styles 76 this._setStackStyle(); 77 // return if no items or only one 78 if( this.itemsCount <= 1 ) return; 79 // add dragging capability 80 this._initDragg(); 81 // init drag events 82 this._initEvents(); 83 }; 84 85 ElastiStack.prototype._initEvents = function() { 86 var self = this; 87 this.draggie.on( 'dragStart', function( i, e, p ) { self._onDragStart( i, e, p ); } ); 88 this.draggie.on( 'dragMove', function( i, e, p ) { self._onDragMove( i, e, p ); } ); 89 this.draggie.on( 'dragEnd', function( i, e, p ) { self._onDragEnd( i, e, p ); } ); 90 }; 91 92 ElastiStack.prototype._setStackStyle = function() { 93 var item1 = this._firstItem(), item2 = this._secondItem(), item3 = this._thirdItem(); 94 95 if( item1 ) { 96 item1.style.opacity = 1; 97 item1.style.zIndex = 4; 98 setTransformStyle( item1, is3d ? 'translate3d(0,0,0)' : 'translate(0,0)' ); 99 } 100 101 if( item2 ) { 102 item2.style.opacity = 1; 103 item2.style.zIndex = 3; 104 setTransformStyle( item2, is3d ? 'translate3d(0,-18px, -75px)' : 'translate(0,0)' ); 105 } 106 107 if( item3 ) { 108 item3.style.opacity = 1; 109 item3.style.zIndex = 2; 110 setTransformStyle( item3, is3d ? 'translate3d(0,-35px, -170px)' : 'translate(0,0)' ); 111 } 112 }; 113 114 ElastiStack.prototype._reset = function() { 115 // reorder stack 116 this.current = this.current < this.itemsCount - 1 ? this.current + 1 : 0; 117 // new front items 118 var item1 = this._firstItem(), item2 = this._secondItem(), item3 = this._thirdItem(); 119 120 // reset transition timing function 121 classie.remove( item1, 'move-back' ); 122 if( item2 ) classie.remove( item2, 'move-back' ); 123 if( item3 ) classie.remove( item3, 'move-back' ); 124 125 var self = this; 126 setTimeout( function() { 127 // the upcoming one will animate.. 128 classie.add( self._lastItem(), 'animate' ); 129 // reset styles 130 self._setStackStyle(); 131 }, 25 ); 132 133 // add dragging capability 134 this._initDragg(); 135 136 // init drag events on new current item 137 this._initEvents(); 138 139 // callback 140 this.options.onUpdateStack( this.current ); 141 }; 142 143 ElastiStack.prototype._moveAway = function( instance ) { 144 var el = instance.element; 145 146 // disable drag 147 this._disableDragg(); 148 149 // add class "animate" 150 classie.add( el, 'animate' ); 151 152 // calculate how much to translate in the x and y axis 153 var tVal = this._getTranslateVal( instance ); 154 155 // apply it 156 setTransformStyle( el, is3d ? 'translate3d(' + tVal.x + 'px,' + tVal.y + 'px, 0px)' : 'translate(' + tVal.x + 'px,' + tVal.y + 'px)' ); 157 158 // item also fades out 159 el.style.opacity = 0; 160 161 // other items move back to stack 162 var item2 = this._secondItem(), item3 = this._thirdItem(); 163 164 if( item2 ) { 165 classie.add( item2, 'move-back' ); 166 classie.add( item2, 'animate' ); 167 setTransformStyle( item2, is3d ? 'translate3d(0,-18px, -75px)' : 'translate(0,0)' ); 168 } 169 if( item3 ) { 170 classie.add( item3, 'move-back' ); 171 classie.add( item3, 'animate' ); 172 setTransformStyle( item3, is3d ? 'translate3d(0,-35px, -170px)' : 'translate(0,0)' ); 173 } 174 175 // after transition ends.. 176 var self = this; 177 onEndTransition( el, function() { 178 // reset first item
179 setTransformStyle( el, is3d ? 'translate3d(0,0,-180px)' : 'translate(0,0,0)' ); 180 el.style.left = el.style.top = '0px'; 181 el.style.zIndex = -1; 182 classie.remove( el, 'animate' ); 183 184 self._reset(); 185 } ); 186 }; 187 188 ElastiStack.prototype._moveBack = function( instance ) { 189 var item2 = this._secondItem(), item3 = this._thirdItem(); 190 191 classie.add( instance.element, 'move-back' ); 192 classie.add( instance.element, 'animate' ); 193 setTransformStyle( instance.element, is3d ? 'translate3d(0,0,0)' : 'translate(0,0)' ); 194 instance.element.style.left = '0px'; 195 instance.element.style.top = '0px'; 196 197 if( item2 ) { 198 classie.add( item2, 'move-back' ); 199 classie.add( item2, 'animate' ); 200 setTransformStyle( item2, is3d ? 'translate3d(0,-18px, -75px)' : 'translate(0,0)' ); 201 } 202 if( item3 ) { 203 classie.add( item3, 'move-back' ); 204 classie.add( item3, 'animate' ); 205 setTransformStyle( item3, is3d ? 'translate3d(0,-35px, -170px)' : 'translate(0,0)' ); 206 } 207 }; 208 209 ElastiStack.prototype._onDragStart = function( instance, event, pointer ) { 210 // remove transition classes if any 211 var item2 = this._secondItem(), item3 = this._thirdItem(); 212 213 classie.remove( instance.element, 'move-back' ); 214 classie.remove( instance.element, 'animate' ); 215 216 if( item2 ) { 217 classie.remove( item2, 'move-back' ); 218 classie.remove( item2, 'animate' ); 219 } 220 if( item3 ) { 221 classie.remove( item3, 'move-back' ); 222 classie.remove( item3, 'animate' ); 223 } 224 }; 225 226 ElastiStack.prototype._onDragMove = function( instance, event, pointer ) { 227 if( this._outOfBounds( instance ) ) { 228 this._moveAway( instance ); 229 } 230 else { 231 // the second and third items also move 232 var item2 = this._secondItem(), item3 = this._thirdItem(); 233 if( item2 ) { 234 setTransformStyle( item2, is3d ? 'translate3d(' + ( instance.position.x * .6 ) + 'px,' + ( instance.position.y * .6 ) + 'px, -100px)' : 'translate(' + ( instance.position.x * .6 ) + 'px,' + ( instance.position.y * .6 ) + 'px)' ); 235 } 236 if( item3 ) { 237 setTransformStyle( item3, is3d ? 'translate3d(' + ( instance.position.x * .3 ) + 'px,' + ( instance.position.y * .3 ) + 'px, -200px)' : 'translate(' + ( instance.position.x * .3 ) + 'px,' + ( instance.position.y * .3 ) + 'px)' ); 238 } 239 } 240 }; 241 242 ElastiStack.prototype._onDragEnd = function( instance, event, pointer ) { 243 if( this._outOfBounds( instance ) ) return; 244 if( this._outOfSight(instance) ) { 245 this._moveAway( instance ); 246 } 247 else { 248 this._moveBack( instance ); 249 } 250 }; 251 252 ElastiStack.prototype._initDragg = function() { 253 this.draggie = new Draggabilly( this.items[ this.current ] ); 254 }; 255 256 ElastiStack.prototype._disableDragg = function() { 257 this.draggie.disable(); 258 }; 259 260 ElastiStack.prototype.nextItem = function( val ) { 261 if( this.isAnimating ) { 262 return false; 263 } 264 this.isAnimating = true; 265 266 var item1 = this._firstItem(), item2 = this._secondItem(), item3 = this._thirdItem(); 267 268 // first item get class animate 269 classie.add( item1, 'animate' ); 270 if( item2 ) { 271 classie.add( item2, 'animate' ); 272 } 273 if( item3 ) { 274 classie.add( item3, 'animate' ); 275 } 276 277 // now translate up and fade out (Z axis) 278 setTransformStyle( item1, is3d ? val.transform : 'translate(0,0)' ); 279 item1.style.opacity = 0; 280 item1.style.zIndex = 5; 281 282 var self = this; 283 284 onEndTransition( item1, function() { 285 classie.remove( item1, 'animate' ); 286 //classie.remove( this, 'move-back' ); 287 item1.style.zIndex = -1; 288 289 // reset first item 290 setTimeout( function() { 291 setTransformStyle( item1, is3d ? 'translate3d(0,0,-180px)' : 'translate(0,0,0)' ); 292 self.isAnimating = false; 293 }, 25 ); 294 } ); 295 296 // disable drag 297 this._disableDragg(); 298 this._reset(); 299 }; 300 301 // returns true if x or y is bigger than distDragMax 302 ElastiStack.prototype._outOfBounds = function( el ) { 303 return Math.abs( el.position.x ) > this.options.distDragMax || Math.abs( el.position.y ) > this.options.distDragMax; 304 }; 305 306 // returns true if x or y is bigger than distDragBack 307 ElastiStack.prototype._outOfSight = function( el ) { 308 return Math.abs( el.position.x ) > this.options.distDragBack || Math.abs( el.position.y ) > this.options.distDragBack; 309 }; 310 311 ElastiStack.prototype._getTranslateVal = function( el ) {
312 var h = Math.sqrt( Math.pow( el.position.x, 2 ) + Math.pow( el.position.y, 2 ) ), 313 a = Math.asin( Math.abs( el.position.y ) / h ) / ( Math.PI / 180 ), 314 hL = h + this.options.distDragBack, 315 dx = Math.cos( a * ( Math.PI / 180 ) ) * hL, 316 dy = Math.sin( a * ( Math.PI / 180 ) ) * hL, 317 tx = dx - Math.abs( el.position.x ), 318 ty = dy - Math.abs( el.position.y ); 319 320 return { 321 x : el.position.x > 0 ? tx : tx * -1, 322 y : el.position.y > 0 ? ty : ty * -1 323 } 324 }; 325 326 // returns the first item in the stack 327 ElastiStack.prototype._firstItem = function() { 328 return this.items[ this.current ]; 329 }; 330 331 // returns the second item in the stack 332 ElastiStack.prototype._secondItem = function() { 333 if( this.itemsCount >= 2 ) { 334 return this.current + 1 < this.itemsCount ? this.items[ this.current + 1 ] : this.items[ Math.abs( this.itemsCount - ( this.current + 1 ) ) ]; 335 } 336 }; 337 338 // returns the third item in the stack 339 ElastiStack.prototype._thirdItem = function() { 340 if( this.itemsCount >= 3 ) { 341 return this.current + 2 < this.itemsCount ? this.items[ this.current + 2 ] : this.items[ Math.abs( this.itemsCount - ( this.current + 2 ) ) ]; 342 } 343 }; 344 345 // returns the last item (of the first three) in the stack 346 ElastiStack.prototype._lastItem = function() { 347 if( this.itemsCount >= 3 ) { 348 return this._thirdItem(); 349 } 350 else { 351 return this._secondItem(); 352 } 353 }; 354 355 // add to global namespace 356 window.ElastiStack = ElastiStack; 357 358})( 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.