~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/node-flick/node-flick.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
7
 
*/
8
 
YUI.add('node-flick', function(Y) {
9
 
 
10
 
/**
11
 
 * Provide a simple Flick plugin, which can be used along with the "flick" gesture event, to 
12
 
 * animate the motion of the host node in response to a (mouse or touch) flick gesture. 
13
 
 * 
14
 
 * <p>The current implementation is designed to move the node, relative to the bounds of a parent node and is suitable
15
 
 * for scroll/carousel type implementations. Future versions will remove that constraint, to allow open ended movement within
16
 
 * the document.</p>
17
 
 *
18
 
 * @module node-flick
19
 
 */
20
 
 
21
 
    var HOST = "host",
22
 
        PARENT_NODE = "parentNode",
23
 
        BOUNDING_BOX = "boundingBox",
24
 
        OFFSET_HEIGHT = "offsetHeight",
25
 
        OFFSET_WIDTH = "offsetWidth",
26
 
        SCROLL_HEIGHT = "scrollHeight",
27
 
        SCROLL_WIDTH = "scrollWidth",
28
 
        BOUNCE = "bounce",
29
 
        MIN_DISTANCE = "minDistance",
30
 
        MIN_VELOCITY = "minVelocity",
31
 
        BOUNCE_DISTANCE = "bounceDistance",
32
 
        DECELERATION = "deceleration",
33
 
        STEP = "step",
34
 
        DURATION = "duration",
35
 
        EASING = "easing",
36
 
        FLICK = "flick",
37
 
        
38
 
        getClassName = Y.ClassNameManager.getClassName;
39
 
 
40
 
    /**
41
 
     * A plugin class which can be used to animate the motion of a node, in response to a flick gesture.
42
 
     * 
43
 
     * @class Flick
44
 
     * @namespace Plugin
45
 
     * @param {Object} config The initial attribute values for the plugin
46
 
     */
47
 
    function Flick(config) {
48
 
        Flick.superclass.constructor.apply(this, arguments);
49
 
    }
50
 
 
51
 
    Flick.ATTRS = {
52
 
 
53
 
        /**
54
 
         * Drag coefficent for inertial scrolling. The closer to 1 this
55
 
         * value is, the less friction during scrolling.
56
 
         *
57
 
         * @attribute deceleration
58
 
         * @default 0.98
59
 
         */
60
 
        deceleration : {
61
 
            value: 0.98
62
 
        },
63
 
 
64
 
        /**
65
 
         * Drag coefficient for intertial scrolling at the upper
66
 
         * and lower boundaries of the scrollview. Set to 0 to 
67
 
         * disable "rubber-banding".
68
 
         *
69
 
         * @attribute bounce
70
 
         * @type Number
71
 
         * @default 0.7
72
 
         */
73
 
        bounce : {
74
 
            value: 0.7
75
 
        },
76
 
 
77
 
        /**
78
 
         * The bounce distance in pixels
79
 
         *
80
 
         * @attribute bounceDistance
81
 
         * @type Number
82
 
         * @default 150
83
 
         */
84
 
        bounceDistance : {
85
 
            value: 150
86
 
        },
87
 
 
88
 
        /**
89
 
         * The minimum flick gesture velocity (px/ms) at which to trigger the flick response
90
 
         *
91
 
         * @attribute minVelocity
92
 
         * @type Number
93
 
         * @default 0
94
 
         */
95
 
        minVelocity : {
96
 
            value: 0
97
 
        },
98
 
 
99
 
        /**
100
 
         * The minimum flick gesture distance (px) for which to trigger the flick response
101
 
         *
102
 
         * @attribute minVelocity
103
 
         * @type Number
104
 
         * @default 10
105
 
         */
106
 
        minDistance : {
107
 
            value: 10
108
 
        },
109
 
 
110
 
        /**
111
 
         * The constraining box relative to which the flick animation and bounds should be calculated.
112
 
         *
113
 
         * @attribute boundingBox
114
 
         * @type Node
115
 
         * @default parentNode
116
 
         */
117
 
        boundingBox : {
118
 
            valueFn : function() {
119
 
                return this.get(HOST).get(PARENT_NODE);
120
 
            }
121
 
        },
122
 
 
123
 
        /**
124
 
         * The constraining box relative to which the flick animation and bounds should be calculated.
125
 
         *
126
 
         * @attribute boundingBox
127
 
         * @type Node
128
 
         * @default parentNode
129
 
         */
130
 
        step : {
131
 
            value:10
132
 
        },
133
 
 
134
 
        /**
135
 
         * The custom duration to apply to the flick animation. By default,
136
 
         * the animation duration is controlled by the deceleration factor.
137
 
         *
138
 
         * @attribute duration
139
 
         * @type Number
140
 
         * @default null
141
 
         */
142
 
        duration : {
143
 
            value:null
144
 
        },
145
 
 
146
 
        /**
147
 
         * The custom transition easing to use for the flick animation. If not
148
 
         * provided defaults to internally to Flick.EASING, or Flick.SNAP_EASING based
149
 
         * on whether or not we're animating the flick or bounce step. 
150
 
         *
151
 
         * @attribute easing
152
 
         * @type String
153
 
         * @default null
154
 
         */
155
 
        easing : {
156
 
            value:null
157
 
        }
158
 
    };
159
 
 
160
 
    /**
161
 
     * The NAME of the Flick class. Used to prefix events generated
162
 
     * by the plugin.
163
 
     *
164
 
     * @property Flick.NAME
165
 
     * @static
166
 
     * @type String
167
 
     * @default "pluginFlick"
168
 
     */
169
 
    Flick.NAME = "pluginFlick";
170
 
 
171
 
    /**
172
 
     * The namespace for the plugin. This will be the property on the node, which will 
173
 
     * reference the plugin instance, when it's plugged in.
174
 
     *
175
 
     * @property Flick.NS
176
 
     * @static
177
 
     * @type String
178
 
     * @default "flick"
179
 
     */
180
 
    Flick.NS = "flick";
181
 
 
182
 
    Y.extend(Flick, Y.Plugin.Base, {
183
 
 
184
 
        /**
185
 
         * The initializer lifecycle implementation.
186
 
         *
187
 
         * @method initializer
188
 
         * @param {Object} config The user configuration for the plugin  
189
 
         */
190
 
        initializer : function(config) {
191
 
            this._node = this.get(HOST);
192
 
 
193
 
            this._renderClasses();
194
 
            this.setBounds();
195
 
 
196
 
            this._node.on(FLICK, Y.bind(this._onFlick, this), {
197
 
                minDistance : this.get(MIN_DISTANCE),
198
 
                minVelocity : this.get(MIN_VELOCITY)
199
 
            });
200
 
        },
201
 
 
202
 
        /**
203
 
         * Sets the min/max boundaries for the flick animation,
204
 
         * based on the boundingBox dimensions.
205
 
         * 
206
 
         * @method setBounds
207
 
         */
208
 
        setBounds : function () {
209
 
            var box = this.get(BOUNDING_BOX),
210
 
                node = this._node,
211
 
 
212
 
                boxHeight = box.get(OFFSET_HEIGHT),
213
 
                boxWidth = box.get(OFFSET_WIDTH),
214
 
 
215
 
                contentHeight = node.get(SCROLL_HEIGHT),
216
 
                contentWidth = node.get(SCROLL_WIDTH);
217
 
 
218
 
            if (contentHeight > boxHeight) {
219
 
                this._maxY = contentHeight - boxHeight;
220
 
                this._minY = 0;
221
 
                this._scrollY = true;
222
 
            }
223
 
 
224
 
            if (contentWidth > boxWidth) {
225
 
                this._maxX = contentWidth - boxWidth;
226
 
                this._minX = 0;
227
 
                this._scrollX = true;
228
 
            }
229
 
 
230
 
            this._x = this._y = 0;
231
 
 
232
 
            node.set("top", this._y + "px");
233
 
            node.set("left", this._x + "px");
234
 
        },
235
 
 
236
 
        /**
237
 
         * Adds the CSS classes, necessary to set up overflow/position properties on the
238
 
         * node and boundingBox. 
239
 
         *
240
 
         * @method _renderClasses
241
 
         * @protected
242
 
         */
243
 
        _renderClasses : function() {
244
 
            this.get(BOUNDING_BOX).addClass(Flick.CLASS_NAMES.box);
245
 
            this._node.addClass(Flick.CLASS_NAMES.content);
246
 
        },
247
 
 
248
 
        /**
249
 
         * The flick event listener. Kicks off the flick animation.
250
 
         *
251
 
         * @method _onFlick
252
 
         * @param e {EventFacade} The flick event facade, containing e.flick.distance, e.flick.velocity etc.
253
 
         * @protected
254
 
         */
255
 
        _onFlick: function(e) {
256
 
            this._v = e.flick.velocity;
257
 
            this._flick = true;
258
 
            this._flickAnim();
259
 
        },
260
 
 
261
 
        /**
262
 
         * Executes a single frame in the flick animation
263
 
         *
264
 
         * @method _flickFrame
265
 
         * @protected
266
 
         */
267
 
        _flickAnim: function() {
268
 
 
269
 
            var y = this._y,
270
 
                x = this._x,
271
 
 
272
 
                maxY = this._maxY,
273
 
                minY = this._minY,
274
 
                maxX = this._maxX,
275
 
                minX = this._minX,
276
 
                velocity = this._v,
277
 
 
278
 
                step = this.get(STEP),
279
 
                deceleration = this.get(DECELERATION),
280
 
                bounce = this.get(BOUNCE);
281
 
 
282
 
            this._v = (velocity * deceleration);
283
 
 
284
 
            this._snapToEdge = false;
285
 
 
286
 
            if (this._scrollX) {
287
 
                x = x - (velocity * step);
288
 
            }
289
 
    
290
 
            if (this._scrollY) {
291
 
                y = y - (velocity * step);
292
 
            }
293
 
 
294
 
            if (Math.abs(velocity).toFixed(4) <= Flick.VELOCITY_THRESHOLD) {
295
 
 
296
 
                this._flick = false;
297
 
 
298
 
                this._killTimer(!(this._exceededYBoundary || this._exceededXBoundary));
299
 
 
300
 
                if (this._scrollX) {
301
 
                    if (x < minX) {
302
 
                        this._snapToEdge = true;
303
 
                        this._setX(minX);
304
 
                    } else if (x > maxX) {
305
 
                        this._snapToEdge = true;
306
 
                        this._setX(maxX);
307
 
                    }
308
 
                }
309
 
 
310
 
                if (this._scrollY) {
311
 
                    if (y < minY) {
312
 
                        this._snapToEdge = true;
313
 
                        this._setY(minY);
314
 
                    } else if (y > maxY) {
315
 
                        this._snapToEdge = true;
316
 
                        this._setY(maxY);
317
 
                    }
318
 
                }
319
 
 
320
 
            } else {
321
 
 
322
 
                if (this._scrollX && (x < minX || x > maxX)) {
323
 
                    this._exceededXBoundary = true;
324
 
                    this._v *= bounce;
325
 
                }
326
 
 
327
 
                if (this._scrollY && (y < minY || y > maxY)) {
328
 
                    this._exceededYBoundary = true;
329
 
                    this._v *= bounce;
330
 
                }
331
 
 
332
 
                if (this._scrollX) {
333
 
                    this._setX(x);
334
 
                }
335
 
 
336
 
                if (this._scrollY) {
337
 
                    this._setY(y);
338
 
                }
339
 
 
340
 
                this._flickTimer = Y.later(step, this, this._flickAnim);
341
 
            }
342
 
        },
343
 
 
344
 
        /**
345
 
         * Internal utility method to set the X offset position
346
 
         *
347
 
         * @param {Number} val
348
 
         * @private
349
 
         */
350
 
        _setX : function(val) {
351
 
            this._move(val, null, this.get(DURATION), this.get(EASING));
352
 
        },
353
 
 
354
 
        /**
355
 
         * Internal utility method to set the Y offset position
356
 
         * 
357
 
         * @param {Number} val
358
 
         * @private
359
 
         */
360
 
        _setY : function(val) {
361
 
            this._move(null, val, this.get(DURATION), this.get(EASING));
362
 
        },
363
 
 
364
 
        /**
365
 
         * Internal utility method to move the node to a given XY position,
366
 
         * using transitions, if specified.
367
 
         *
368
 
         * @param {Number} x The X offset position
369
 
         * @param {Number} y The Y offset position
370
 
         * @param {Number} duration The duration to use for the transition animation
371
 
         * @param {String} easing The easing to use for the transition animation.
372
 
         *
373
 
         * @private
374
 
         */
375
 
        _move: function(x, y, duration, easing) {
376
 
 
377
 
            if (x !== null) {
378
 
                x = this._bounce(x);
379
 
            } else {
380
 
                x = this._x; 
381
 
            }
382
 
 
383
 
            if (y !== null) {
384
 
                y = this._bounce(y);
385
 
            } else {
386
 
                y = this._y;
387
 
            }
388
 
 
389
 
            duration = duration || this._snapToEdge ? Flick.SNAP_DURATION : 0;
390
 
            easing = easing || this._snapToEdge ? Flick.SNAP_EASING : Flick.EASING;
391
 
 
392
 
            this._x = x;
393
 
            this._y = y;
394
 
 
395
 
            this._anim(x, y, duration, easing);
396
 
        },
397
 
 
398
 
        /**
399
 
         * Internal utility method to perform the transition step
400
 
         *
401
 
         * @param {Number} x The X offset position
402
 
         * @param {Number} y The Y offset position
403
 
         * @param {Number} duration The duration to use for the transition animation
404
 
         * @param {String} easing The easing to use for the transition animation.
405
 
         *
406
 
         * @private
407
 
         */
408
 
        _anim : function(x, y, duration, easing) {
409
 
            var xn = x * -1,
410
 
                yn = y * -1,
411
 
 
412
 
                transition = {
413
 
                    duration : duration / 1000,
414
 
                    easing : easing
415
 
                };
416
 
 
417
 
 
418
 
            if (Y.Transition.useNative) {
419
 
                transition.transform = 'translate('+ (xn) + 'px,' + (yn) +'px)'; 
420
 
            } else {
421
 
                transition.left = xn + 'px';
422
 
                transition.top = yn + 'px';
423
 
            }
424
 
 
425
 
            this._node.transition(transition);
426
 
        },
427
 
 
428
 
        /**
429
 
         * Internal utility method to constrain the offset value
430
 
         * based on the bounce criteria. 
431
 
         *
432
 
         * @param {Number} x The offset value to constrain.
433
 
         * @param {Number} max The max offset value.
434
 
         *
435
 
         * @private
436
 
         */
437
 
        _bounce : function(val, max) {
438
 
            var bounce = this.get(BOUNCE),
439
 
                dist = this.get(BOUNCE_DISTANCE),
440
 
                min = bounce ? -dist : 0;
441
 
 
442
 
            max = bounce ? max + dist : max;
443
 
    
444
 
            if(!bounce) {
445
 
                if(val < min) {
446
 
                    val = min;
447
 
                } else if(val > max) {
448
 
                    val = max;
449
 
                }            
450
 
            }
451
 
            return val;
452
 
        },
453
 
 
454
 
        /**
455
 
         * Stop the animation timer
456
 
         *
457
 
         * @method _killTimer
458
 
         * @private
459
 
         */
460
 
        _killTimer: function() {
461
 
            if(this._flickTimer) {
462
 
                this._flickTimer.cancel();
463
 
            }
464
 
        }
465
 
 
466
 
    }, {
467
 
 
468
 
        /**
469
 
         * The threshold used to determine when the decelerated velocity of the node
470
 
         * is practically 0.
471
 
         *
472
 
         * @property Flick.VELOCITY_THRESHOLD
473
 
         * @static
474
 
         * @type Number
475
 
         * @default 0.015
476
 
         */
477
 
        VELOCITY_THRESHOLD : 0.015,
478
 
 
479
 
        /**
480
 
         * The duration to use for the bounce snap-back transition
481
 
         *
482
 
         * @property Flick.SNAP_DURATION
483
 
         * @static
484
 
         * @type Number
485
 
         * @default 400
486
 
         */
487
 
         SNAP_DURATION : 400,
488
 
        
489
 
        /**
490
 
         * The default easing to use for the main flick movement transition
491
 
         *
492
 
         * @property Flick.EASING
493
 
         * @static
494
 
         * @type String
495
 
         * @default 'cubic-bezier(0, 0.1, 0, 1.0)'
496
 
         */
497
 
        EASING : 'cubic-bezier(0, 0.1, 0, 1.0)',
498
 
 
499
 
        /**
500
 
         * The default easing to use for the bounce snap-back transition
501
 
         *
502
 
         * @property Flick.SNAP_EASING
503
 
         * @static
504
 
         * @type String
505
 
         * @default 'ease-out'
506
 
         */
507
 
        SNAP_EASING : 'ease-out',
508
 
 
509
 
        /**
510
 
         * The default CSS class names used by the plugin
511
 
         *
512
 
         * @property Flick.CLASS_NAMES
513
 
         * @static
514
 
         * @type Object
515
 
         */
516
 
        CLASS_NAMES : {
517
 
            box: getClassName(Flick.NS),
518
 
            content: getClassName(Flick.NS, "content")
519
 
        }
520
 
    });
521
 
 
522
 
    Y.Plugin.Flick = Flick;
523
 
 
524
 
 
525
 
}, '3.2.0' ,{requires:['classnamemanager', 'transition', 'event-flick', 'plugin']});