github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/abplayer/demos/coverflow/coverflow.js (about) 1 /*jslint devel: true, bitwise: true, regexp: true, browser: true, confusion: true, unparam: true, eqeq: true, white: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */ 2 /*globals jQuery */ 3 4 /*! 5 * Coverflow 6 * 7 * Copyright (c) 2013 Martijn W. van der Lee 8 * Licensed under the MIT. 9 */ 10 /* Lightweight and flexible coverflow effect using CSS3 transforms. 11 * For modern browsers with some amount of graceful degradation. 12 * Optional support for jQuery.interpolate() plugin. 13 * Optional support for .reflect() plugins. 14 * 15 * Requires jQuery 1.7+ and jQueryUI 1.9+. 16 * Recommended jQuery 1.8+ and jQueryUI 1.9+. 17 */ 18 19 ;(function($, undefined) { 20 "use strict"; 21 22 var sign = function(number) { 23 return number < 0 ? -1 : 1; 24 }, 25 scl = function(number, fromMin, fromMax, toMin, toMax) { 26 return ((number - fromMin) * (toMax - toMin) / (fromMax - fromMin)) + toMin; 27 }; 28 29 $.widget("vanderlee.coverflow", { 30 options: { 31 animateComplete: undefined, 32 animateStep: undefined, 33 density: 1, 34 duration: 'normal', 35 easing: undefined, 36 index: 0, 37 innerAngle: -75, 38 innerCss: undefined, 39 innerOffset: 100 / 3, 40 innerScale: 0.75, 41 outerAngle: -30, 42 outerCss: undefined, 43 outerScale: 0.25, 44 selectedCss: undefined, 45 visible: 'density', // 'density', 'all', NNN (exact) 46 width: undefined, 47 48 change: undefined, // Whenever index is changed 49 confirm: undefined, // Whenever clicking on the current item 50 select: undefined // Whenever index is set (also on init) 51 }, 52 53 _create: function() { 54 var that = this; 55 56 // Internal event prefix 57 that.widgetEventPrefix = 'vanderlee-coverflow'; 58 59 that.hovering = false; 60 that.pagesize = 1; 61 that.currentIndex = that.options.index; 62 63 // Fix height 64 that.element.height(that._getCovers().first().height()); 65 66 // Hide all covers and set position to absolute 67 that._getCovers().hide().css('position', 'absolute'); 68 69 // Enable click-jump 70 that.element.on('click', '> *', function() { 71 var index = that._getCovers().index(this); 72 if (index === that.currentIndex) { 73 that._callback('confirm'); 74 } else { 75 that._setIndex(index, true); 76 } 77 }); 78 79 // Refresh on resize 80 $(window).resize(function() { 81 that.refresh(); 82 }); 83 84 // Mousewheel 85 that.element.on('mousewheel', function(event, delta) { 86 event.preventDefault(); 87 that._setIndex(that.options.index - delta, true); 88 }); 89 90 // Swipe 91 if ($.isFunction(that.element.swipe)) { 92 that.element.swipe({ 93 swipe: function(event, direction, distance, duration, fingerCount) { 94 var count = Math.round((direction === 'left' ? 1 : -1) * 1.25 * that.pagesize * distance / that.element.width()); 95 that._setIndex(that.options.index + count, true); 96 } 97 }); 98 } 99 100 // Keyboard 101 that.element.hover( 102 function() { that.hovering = true; } 103 , function() { that.hovering = false; } 104 ); 105 106 $(window).on('keydown', function(event) { 107 if (that.hovering) { 108 switch (event.which) { 109 case 36: // home 110 event.preventDefault(); 111 that._setIndex(0, true); 112 break; 113 114 case 35: // end 115 event.preventDefault(); 116 that._setIndex(that._getCovers().length - 1, true); 117 break; 118 119 case 38: // up 120 case 37: // left 121 event.preventDefault(); 122 that._setIndex(that.options.index - 1, true); 123 break; 124 125 case 40: // down 126 case 39: // right 127 event.preventDefault(); 128 that._setIndex(that.options.index + 1, true); 129 break; 130 131 case 33: // page up (towards home) 132 event.preventDefault(); 133 that._setIndex(that.options.index - that.pagesize, true); 134 break; 135 136 case 34: // page down (towards end) 137 event.preventDefault(); 138 that._setIndex(that.options.index + that.pagesize, true); 139 break; 140 } 141 } 142 }); 143 144 // Initialize 145 that._setIndex(that.options.index, false, true); 146 that.refresh(); 147 148 return that; 149 }, 150 151 /** 152 * Returns the currently selected cover 153 * @returns {jQuery} jQuery object 154 */ 155 cover: function() { 156 return $(this._getCovers()[this.options.index]); 157 }, 158 159 /** 160 * 161 * @returns {unresolved} 162 */ 163 _getCovers: function() { 164 return $('> *', this.element); 165 }, 166 167 _setIndex: function(index, animate, initial) { 168 var covers = this._getCovers(); 169 170 index = Math.max(0, Math.min(index, covers.length - 1)); 171 172 if (index !== this.options.index) { 173 this.refresh(); // pre-correct for reflection/mods 174 175 if (animate === true) { 176 this.currentIndex = this.options.index; 177 this.options.index = Math.round(index); 178 179 var that = this, 180 duration = typeof that.options.duration === "number" 181 ? that.options.duration 182 : jQuery.fx.speeds[that.options.duration] || jQuery.fx.speeds._default, 183 timeout = null, 184 step = that.options.index > that.currentIndex ? 1 : -1, 185 doStep = function() { 186 var steps = Math.abs(that.options.index - that.currentIndex), 187 time = duration / Math.max(1, steps) * 0.5; 188 if (that.options.index !== that.currentIndex) { 189 that.currentIndex += step; 190 that.refresh.call(that, time, that.currentIndex); 191 timeout = setTimeout(doStep, time); 192 } 193 that._callback('change'); 194 that._callback('select'); 195 }; 196 if (timeout) { 197 clearTimeout(timeout); 198 } 199 if (that.currentIndex !== this.options.index) { 200 doStep(); 201 } 202 } else { 203 this.currentIndex = this.options.index = Math.round(index); 204 this.refresh(this.options.duration); 205 this._callback('change'); 206 this._callback('select'); 207 } 208 } else if (initial === true) { 209 this.refresh(); 210 this._callback('select'); 211 } 212 }, 213 214 _callback: function(callback) { 215 this._trigger(callback, null, this._getCovers().get(this.currentIndex), this.currentIndex); 216 }, 217 218 index: function(index) { 219 if (index === undefined) { 220 return this.options.index; 221 } 222 this._setIndex(index, true); 223 }, 224 225 refresh: function(duration, index) { 226 var that = this, 227 target = index || that.options.index, 228 count = that._getCovers().length, 229 parentWidth = that.element.innerWidth(), 230 coverWidth = that.options.width || that._getCovers().first().outerWidth(), 231 visible = that.options.visible === 'density' ? Math.round(parentWidth * that.options.density / coverWidth) 232 : $.isNumeric(that.options.visible) ? that.options.visible 233 : count, 234 parentLeft = that.element.position().left - ((1 - that.options.outerScale) * coverWidth * 0.5), 235 space = (parentWidth - (that.options.outerScale * coverWidth)) * 0.5; 236 237 duration = duration || 0; 238 239 that.pagesize = visible; 240 241 that._getCovers().removeClass('current').each(function(index, cover) { 242 var position = index - target, 243 offset = position / visible, 244 isVisible = Math.abs(offset) <= 1, 245 sin = isVisible ? Math.sin(offset * Math.PI * 0.5) 246 : sign(offset), 247 cos = isVisible ? Math.cos(offset * Math.PI * 0.5) 248 : 0, 249 isMiddle = position === 0, 250 zIndex = count - Math.abs(position), 251 left = parentLeft + space + (isMiddle ? 0 : sign(sin) * scl(Math.abs(sin), 0, 1, that.options.innerOffset * that.options.density, space)), 252 scale = !isVisible? 0 253 : isMiddle ? 1 254 : scl(Math.abs(cos), 1, 0, that.options.innerScale, that.options.outerScale), 255 angle = isMiddle ? 0 256 : sign(sin) * scl(Math.abs(sin), 0, 1, that.options.innerAngle, that.options.outerAngle), 257 state = {}, 258 css = isMiddle ? that.options.selectedCss || {} 259 : ( $.interpolate && that.options.outerCss && !$.isEmptyObject(that.options.outerCss) ? ( 260 isVisible ? $.interpolate(that.options.innerCss || {}, that.options.outerCss, Math.abs(sin)) 261 : that.options.outerCss 262 ) : {} 263 ), 264 transform; 265 266 if (isVisible) { 267 $(cover).show(); 268 } 269 270 $(cover).stop().css({ 271 'z-index': zIndex 272 }).animate($.extend(css, { 273 'left': left, 274 '_sin': sin, 275 '_cos': cos, 276 '_scale': scale, 277 '_angle': angle // must be last! 278 }), { 279 'easing': that.options.easing, 280 'duration': isVisible ? duration : 0, 281 'step': function(now, fx) { 282 // Store state 283 state[fx.prop] = now; 284 285 // On last of the states, change all at once 286 if (fx.prop === '_angle') { 287 transform = 'scale(' + state._scale + ',' + state._scale + ') perspective('+(parentWidth * 0.5)+'px) rotateY(' + state._angle + 'deg)'; 288 $(this).css({ 289 '-webkit-transform': transform, 290 '-ms-transform': transform, 291 'transform': transform 292 }); 293 294 // Optional callback 295 that._trigger('animateStep', cover, [cover, offset, isVisible, isMiddle, state._sin, state._cos]); 296 } 297 }, 298 'complete': function() { 299 $(this)[isMiddle ? 'addClass' : 'removeClass']('current'); 300 $(this)[isVisible ? 'show' : 'hide'](); 301 302 // Optional callback 303 that._trigger('animateComplete', cover, [cover, offset, isVisible, isMiddle, sin, cos]); 304 } 305 }); 306 }); 307 } 308 }); 309 }(jQuery));