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