123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- // animate
- ( function( window, factory ) {
- // universal module definition
- /* jshint strict: false */
- if ( typeof define == 'function' && define.amd ) {
- // AMD
- define( [
- 'fizzy-ui-utils/utils'
- ], function( utils ) {
- return factory( window, utils );
- });
- } else if ( typeof module == 'object' && module.exports ) {
- // CommonJS
- module.exports = factory(
- window,
- require('fizzy-ui-utils')
- );
- } else {
- // browser global
- window.Flickity = window.Flickity || {};
- window.Flickity.animatePrototype = factory(
- window,
- window.fizzyUIUtils
- );
- }
- }( window, function factory( window, utils ) {
- 'use strict';
- // -------------------------- animate -------------------------- //
- var proto = {};
- proto.startAnimation = function() {
- if ( this.isAnimating ) {
- return;
- }
- this.isAnimating = true;
- this.restingFrames = 0;
- this.animate();
- };
- proto.animate = function() {
- this.applyDragForce();
- this.applySelectedAttraction();
- var previousX = this.x;
- this.integratePhysics();
- this.positionSlider();
- this.settle( previousX );
- // animate next frame
- if ( this.isAnimating ) {
- var _this = this;
- requestAnimationFrame( function animateFrame() {
- _this.animate();
- });
- }
- };
- proto.positionSlider = function() {
- var x = this.x;
- // wrap position around
- if ( this.options.wrapAround && this.cells.length > 1 ) {
- x = utils.modulo( x, this.slideableWidth );
- x = x - this.slideableWidth;
- this.shiftWrapCells( x );
- }
- this.setTranslateX( x, this.isAnimating );
- this.dispatchScrollEvent();
- };
- proto.setTranslateX = function( x, is3d ) {
- x += this.cursorPosition;
- // reverse if right-to-left and using transform
- x = this.options.rightToLeft ? -x : x;
- var translateX = this.getPositionValue( x );
- // use 3D tranforms for hardware acceleration on iOS
- // but use 2D when settled, for better font-rendering
- this.slider.style.transform = is3d ?
- 'translate3d(' + translateX + ',0,0)' : 'translateX(' + translateX + ')';
- };
- proto.dispatchScrollEvent = function() {
- var firstSlide = this.slides[0];
- if ( !firstSlide ) {
- return;
- }
- var positionX = -this.x - firstSlide.target;
- var progress = positionX / this.slidesWidth;
- this.dispatchEvent( 'scroll', null, [ progress, positionX ] );
- };
- proto.positionSliderAtSelected = function() {
- if ( !this.cells.length ) {
- return;
- }
- this.x = -this.selectedSlide.target;
- this.velocity = 0; // stop wobble
- this.positionSlider();
- };
- proto.getPositionValue = function( position ) {
- if ( this.options.percentPosition ) {
- // percent position, round to 2 digits, like 12.34%
- return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
- } else {
- // pixel positioning
- return Math.round( position ) + 'px';
- }
- };
- proto.settle = function( previousX ) {
- // keep track of frames where x hasn't moved
- if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
- this.restingFrames++;
- }
- // stop animating if resting for 3 or more frames
- if ( this.restingFrames > 2 ) {
- this.isAnimating = false;
- delete this.isFreeScrolling;
- // render position with translateX when settled
- this.positionSlider();
- this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );
- }
- };
- proto.shiftWrapCells = function( x ) {
- // shift before cells
- var beforeGap = this.cursorPosition + x;
- this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
- // shift after cells
- var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
- this._shiftCells( this.afterShiftCells, afterGap, 1 );
- };
- proto._shiftCells = function( cells, gap, shift ) {
- for ( var i=0; i < cells.length; i++ ) {
- var cell = cells[i];
- var cellShift = gap > 0 ? shift : 0;
- cell.wrapShift( cellShift );
- gap -= cell.size.outerWidth;
- }
- };
- proto._unshiftCells = function( cells ) {
- if ( !cells || !cells.length ) {
- return;
- }
- for ( var i=0; i < cells.length; i++ ) {
- cells[i].wrapShift( 0 );
- }
- };
- // -------------------------- physics -------------------------- //
- proto.integratePhysics = function() {
- this.x += this.velocity;
- this.velocity *= this.getFrictionFactor();
- };
- proto.applyForce = function( force ) {
- this.velocity += force;
- };
- proto.getFrictionFactor = function() {
- return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
- };
- proto.getRestingPosition = function() {
- // my thanks to Steven Wittens, who simplified this math greatly
- return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
- };
- proto.applyDragForce = function() {
- if ( !this.isDraggable || !this.isPointerDown ) {
- return;
- }
- // change the position to drag position by applying force
- var dragVelocity = this.dragX - this.x;
- var dragForce = dragVelocity - this.velocity;
- this.applyForce( dragForce );
- };
- proto.applySelectedAttraction = function() {
- // do not attract if pointer down or no slides
- var dragDown = this.isDraggable && this.isPointerDown;
- if ( dragDown || this.isFreeScrolling || !this.slides.length ) {
- return;
- }
- var distance = this.selectedSlide.target * -1 - this.x;
- var force = distance * this.options.selectedAttraction;
- this.applyForce( force );
- };
- return proto;
- }));
|