-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjquery.tslot.js
297 lines (255 loc) · 8.37 KB
/
jquery.tslot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/**
* @file
* Holds the jquery.tslot plugin.
*/
(function ($) {
/**
* The object constructor to attach as jquery plugin below.
*
* @param element
* The DOM element to convert to a slot wheel.
* @param object options
* - spinningDuration: the duration for a single item to change
* - spinningBrake: the factor the spinning gets slower when stopping
* - itemsToStop: the number of items to roll, till the wheel stops
* - itemPosition: default position for the wheel (starts at 0)
*/
var tSlotsWheel = function (element, options) {
/**
* The jquery object for this wheel.
*
* @var
*/
var $wrapper = $(element);
/**
* The jquery object for the list.
*
* @var
*/
var $itemList = $wrapper.children('ul');
/**
* This $wheels object to store data and functions.
*
* @var
*/
var $wheel = this;
/**
* Holds the status of the current element.
*
* @var string
* - init
* - ready
* - starting
* - spinning
* - stopping
* - stopped
*/
this.status = 'init';
// This is the current itemPosition of the element.
this.itemPosition = $itemList.children('li').size();
// Time since the item stands in that position.
this.itemTime = +new Date;
// For the moment it is supposed all elements have the same height, so we
// can simply take the height of the first element.
this.itemHeight = $itemList.children('li').first().outerHeight();
this.itemCount = $itemList.children('li').size();
// To get a seemless animation, we have to clone items to the front and the
// end. For reference we set the offset count as properties.
$itemList.children('li').clone().prependTo($itemList);
$itemList.children('li').clone().appendTo($itemList);
this.prependedItems = this.itemCount;
this.appendedItems = this.itemCount * 2;
// Fill object params with value from options.
var settings = $.extend({
spinningDuration: 500,
spinningBrake: 1.1,
itemsToStop: 3
}, options || {});
this.spinningDuration = settings.spinningDuration;
this.spinningBrake = settings.spinningBrake;
this.itemsToStop = settings.itemsToStop;
// Vars that may be set as options in a later version.
this.spinningEasing = 'linear';
this.spinningAcc = 2;
// Temp param to set for stopping.
this.itemsToStopToGo = undefined;
/**
* Starts spinning the wheel.
*/
this.start = function () {
// We can only start, if the wheel is spinning.
if ($wheel.status != 'ready' && $wheel.status != 'stopped') {
console.log('Cannot start wheel, as it is not ready.');
return;
}
$wheel.status = 'starting';
// Trigger this event on the wrapper.
$wrapper.trigger('tslotStarting', {tslot: $wheel});
// Start spinning.
spinToNextPosition($wheel.spinningDuration, $wheel.spinningEasing, function () {
$wheel.spin();
});
};
/**
* Stops spinning the wheel.
*/
this.stop = function () {
// We can only stop, if the wheel is spinning.
if ($wheel.status != 'spinning') {
console.log('Cannot stop wheel, as wheel is not spinning.');
return;
}
// Stop and spin out the current item.
$itemList.stop(true, false);
// The spinning duration for rolling out is only a part of the default one.
var restDuration = $wheel.spinningDuration - (+new Date - this.itemTime);
spinToNextPosition(restDuration, $wheel.spinningEasing, function () {
// And now start stopping.
$wheel.itemsToStopToGo = $wheel.itemsToStop;
stopping();
});
};
/**
* Spins the wheel with a constant velocity, item by item.
*
* The function does one item after each other. So we have a fine grained
* control, instead of animating a whole wheel spin.
*/
this.spin = function () {
if ($wheel.status != 'spinning') {
$wheel.status = 'spinning';
// Trigger this event on the wrapper.
$wrapper.trigger('tslotSpinning', {tslot: $wheel});
}
spinToNextPosition($wheel.spinningDuration, $wheel.spinningEasing, function () {
$wheel.spin();
});
};
/**
* Provides css styles to show the item of a given item in the slot.
*
* @param int pos
* Position of the item (starts at 0)
*
* @return object
* Object containing css styles.
*/
this.getStyleForPosition = function (pos) {
var style = {
"margin-top": '-' + ( ( $wheel.appendedItems + pos) * $wheel.itemHeight) + 'px'
};
return style;
}
/**
* Speed up spinning for the next item and on.
*/
this.faster = function () {
$wheel.spinningDuration = $wheel.spinningDuration / $wheel.spinningAcc;
}
/**
* Slow down spinning for the next item and on.
*/
this.slower = function () {
$wheel.spinningDuration = $wheel.spinningDuration * $wheel.spinningBrake;
}
/**
* Private function to controll the spinning of the wheel to the next item.
*
* @param int duration
* @param string easing
*
* @param Function finished
* The callback to call when the position is reached.
*/
var spinToNextPosition = function (duration, easing, finished) {
var style = $wheel.getStyleForPosition($wheel.itemPosition - 1);
$itemList.animate(
style,
duration,
easing,
// When the animation ends, we will update the item position and make
// sure we start over at the first item, when we reached the last one
// (which is a duplicate of the first).
function () {
// As the animation ended, we are now on the next item.
setNextPosition();
// Continue with our callback.
finished();
}
);
};
/**
* Private helper to increment position.
*
* Makes the spinning infinite, as it makes sure the weel spins by resetting
* to the first item when we reached the last.
*/
var setNextPosition = function () {
$wheel.itemPosition--;
if ($wheel.itemPosition <= -1) {
setPosition($wheel.itemCount - 1);
}
$wheel.itemTime = +new Date;
};
/**
* Private helper to set the wheel to a specific position.
*
* @param int pos
*/
var setPosition = function (pos) {
// Make sure we got an integer one.
var pos = parseInt(pos);
var style = $wheel.getStyleForPosition(pos);
$itemList.css(style);
$wheel.itemPosition = pos;
}
/**
* Private function to stop the spinning wheel.
*/
var stopping = function() {
if ($wheel.status != 'stopping') {
$wheel.status = 'stopping';
// Trigger this event on the wrapper.
$wrapper.trigger('tslotStopping', {tslot: $wheel});
}
$wheel.slower();
if ($wheel.itemsToStopToGo > 1) {
spinToNextPosition($wheel.spinningDuration, $wheel.spinningEasing, function() {
$wheel.itemsToStopToGo--;
stopping();
});
}
else {
spinToNextPosition($wheel.spinningDuration * 2, 'easeOutBack', function() {
$wheel.itemsToStopToGo--;
$wheel.status = 'stopped';
// Trigger this event on the wrapper.
$wrapper.trigger('tslotStopped', {tslot: $wheel});
});
}
}
// If the options provided a default position, we set the init status to it.
if (options.itemPosition != undefined && options.itemPosition.length > 0) {
setPosition(options.itemPosition);
}
// Ensure the style for the given position is set.
else {
setPosition(this.itemPosition);
}
// Set ready status, after we registered all methods.
this.status = 'ready';
// Trigger this event on the wrapper.
$wrapper.trigger('tslotReady', {tslot: $wheel});
}
// Attaching our tSlotsWheel object as plugin to jquery elements.
$.fn.tSlotsWheel = function (options) {
return this.each(function () {
var element = $(this);
// Return early if this element already has a plugin instance
if (element.data('tSlotsWheel')) return;
var tSW = new tSlotsWheel(this, options);
// Store plugin object in this element's data
element.data('tSlotsWheel', tSW);
});
};
})(jQuery);