Permalink
Newer
100644
246 lines (207 sloc)
6.66 KB
1
( function( window, factory ) {
2
'use strict';
3
// universal module definition
4
5
if ( typeof define == 'function' && define.amd ) {
6
// AMD
7
define( [
8
'get-style-property/get-style-property',
10
], function( getStyleProperty, utils ) {
11
return factory( window, getStyleProperty, utils );
12
});
13
} else if ( typeof exports == 'object' ) {
14
// CommonJS
15
module.exports = factory(
16
window,
17
require('desandro-get-style-property'),
19
);
20
} else {
21
// browser global
22
window.Flickity = window.Flickity || {};
23
window.Flickity.animatePrototype = factory(
24
window,
25
window.getStyleProperty,
31
32
'use strict';
33
34
// -------------------------- requestAnimationFrame -------------------------- //
35
36
// https://gist.github.com/1866474
37
38
var lastTime = 0;
39
var prefixes = 'webkit moz ms o'.split(' ');
40
// get unprefixed rAF and cAF, if present
41
var requestAnimationFrame = window.requestAnimationFrame;
42
var cancelAnimationFrame = window.cancelAnimationFrame;
43
// loop through vendor prefixes and get prefixed rAF and cAF
44
var prefix;
45
for( var i = 0; i < prefixes.length; i++ ) {
46
if ( requestAnimationFrame && cancelAnimationFrame ) {
47
break;
48
}
49
prefix = prefixes[i];
50
requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
51
cancelAnimationFrame = cancelAnimationFrame || window[ prefix + 'CancelAnimationFrame' ] ||
52
window[ prefix + 'CancelRequestAnimationFrame' ];
53
}
54
55
// fallback to setTimeout and clearTimeout if either request/cancel is not supported
56
if ( !requestAnimationFrame || !cancelAnimationFrame ) {
57
requestAnimationFrame = function( callback ) {
58
var currTime = new Date().getTime();
59
var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
60
var id = window.setTimeout( function() {
61
callback( currTime + timeToCall );
62
}, timeToCall );
63
lastTime = currTime + timeToCall;
64
return id;
65
};
66
67
cancelAnimationFrame = function( id ) {
68
window.clearTimeout( id );
69
};
70
}
71
72
// -------------------------- animate -------------------------- //
73
74
var proto = {};
75
76
proto.startAnimation = function() {
77
if ( this.isAnimating ) {
78
return;
79
}
80
81
this.isAnimating = true;
82
this.restingFrames = 0;
83
this.animate();
84
};
85
86
proto.animate = function() {
87
this.applySelectedAttraction();
88
89
var previousX = this.x;
90
92
this.positionSlider();
93
this.settle( previousX );
94
// animate next frame
95
if ( this.isAnimating ) {
96
var _this = this;
97
requestAnimationFrame( function animateFrame() {
98
_this.animate();
99
});
100
}
101
102
/** /
103
// log animation frame rate
104
var now = new Date();
105
if ( this.then ) {
106
console.log( ~~( 1000 / (now-this.then)) + 'fps' )
107
}
108
this.then = now;
109
/**/
115
116
proto.positionSlider = function() {
117
var x = this.x;
118
// wrap position around
123
}
124
125
x = x + this.cursorPosition;
126
127
// reverse if right-to-left and using transform
128
x = this.options.rightToLeft && transformProperty ? -x : x;
129
130
var value = this.getPositionValue( x );
131
132
if ( transformProperty ) {
133
// use 3D tranforms for hardware acceleration on iOS
134
// but use 2D when settled, for better font-rendering
135
this.slider.style[ transformProperty ] = is3d && this.isAnimating ?
146
var selectedCell = this.cells[ this.selectedIndex ];
147
this.x = -selectedCell.target;
148
this.positionSlider();
149
};
150
151
proto.getPositionValue = function( position ) {
153
// percent position, round to 2 digits, like 12.34%
154
return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
158
}
159
};
160
161
proto.settle = function( previousX ) {
162
// keep track of frames where x hasn't moved
163
if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
164
this.restingFrames++;
165
}
166
// stop animating if resting for 3 or more frames
167
if ( this.restingFrames > 2 ) {
168
this.isAnimating = false;
170
// render position with translateX when settled
171
if ( is3d ) {
172
this.positionSlider();
173
}
178
proto.shiftWrapCells = function( x ) {
179
// shift before cells
180
var beforeGap = this.cursorPosition + x;
181
this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
182
// shift after cells
183
var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
184
this._shiftCells( this.afterShiftCells, afterGap, 1 );
185
};
186
187
proto._shiftCells = function( cells, gap, shift ) {
188
for ( var i=0, len = cells.length; i < len; i++ ) {
189
var cell = cells[i];
190
var cellShift = gap > 0 ? shift : 0;
191
cell.wrapShift( cellShift );
192
gap -= cell.size.outerWidth;
193
}
194
};
195
196
proto._unshiftCells = function( cells ) {
197
if ( !cells || !cells.length ) {
198
return;
199
}
200
for ( var i=0, len = cells.length; i < len; i++ ) {
201
cells[i].wrapShift( 0 );
202
}
203
};
204
211
// reset acceleration
212
this.accel = 0;
213
};
214
215
proto.applyForce = function( force ) {
216
this.accel += force;
217
};
218
219
proto.getFrictionFactor = function() {
220
return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
221
};
222
225
// my thanks to Steven Wittens, who simplified this math greatly
226
return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
232
var len = this.cells.length;
233
if ( this.isPointerDown || this.isFreeScrolling || !len ) {
237
var wrap = this.options.wrapAround && len > 1 ?
238
this.slideableWidth * Math.floor( this.selectedIndex / len ) : 0;
239
var distance = ( cell.target + wrap ) * -1 - this.x;
240
var force = distance * this.options.selectedAttraction;
241
this.applyForce( force );
242
};
243