Autoría | Ultima modificación | Ver Log |
YUI.add('node-flick', function (Y, NAME) {/*** Provide a simple Flick plugin, which can be used along with the "flick" gesture event, to* animate the motion of the host node in response to a (mouse or touch) flick gesture.** <p>The current implementation is designed to move the node, relative to the bounds of a parent node and is suitable* for scroll/carousel type implementations. Future versions will remove that constraint, to allow open ended movement within* the document.</p>** @module node-flick*/var HOST = "host",PARENT_NODE = "parentNode",BOUNDING_BOX = "boundingBox",OFFSET_HEIGHT = "offsetHeight",OFFSET_WIDTH = "offsetWidth",SCROLL_HEIGHT = "scrollHeight",SCROLL_WIDTH = "scrollWidth",BOUNCE = "bounce",MIN_DISTANCE = "minDistance",MIN_VELOCITY = "minVelocity",BOUNCE_DISTANCE = "bounceDistance",DECELERATION = "deceleration",STEP = "step",DURATION = "duration",EASING = "easing",FLICK = "flick",getClassName = Y.ClassNameManager.getClassName;/*** A plugin class which can be used to animate the motion of a node, in response to a flick gesture.** @class Flick* @namespace Plugin* @param {Object} config The initial attribute values for the plugin*/function Flick(config) {Flick.superclass.constructor.apply(this, arguments);}Flick.ATTRS = {/*** Drag coefficent for inertial scrolling. The closer to 1 this* value is, the less friction during scrolling.** @attribute deceleration* @default 0.98*/deceleration : {value: 0.98},/*** Drag coefficient for intertial scrolling at the upper* and lower boundaries of the scrollview. Set to 0 to* disable "rubber-banding".** @attribute bounce* @type Number* @default 0.7*/bounce : {value: 0.7},/*** The bounce distance in pixels** @attribute bounceDistance* @type Number* @default 150*/bounceDistance : {value: 150},/*** The minimum flick gesture velocity (px/ms) at which to trigger the flick response** @attribute minVelocity* @type Number* @default 0*/minVelocity : {value: 0},/*** The minimum flick gesture distance (px) for which to trigger the flick response** @attribute minVelocity* @type Number* @default 10*/minDistance : {value: 10},/*** The constraining box relative to which the flick animation and bounds should be calculated.** @attribute boundingBox* @type Node* @default parentNode*/boundingBox : {valueFn : function() {return this.get(HOST).get(PARENT_NODE);}},/*** Time between flick animation frames.** @attribute step* @type Number* @default 10*/step : {value:10},/*** The custom duration to apply to the flick animation. By default,* the animation duration is controlled by the deceleration factor.** @attribute duration* @type Number* @default null*/duration : {value:null},/*** The custom transition easing to use for the flick animation. If not* provided defaults to internally to Flick.EASING, or Flick.SNAP_EASING based* on whether or not we're animating the flick or bounce step.** @attribute easing* @type String* @default null*/easing : {value:null}};/*** The NAME of the Flick class. Used to prefix events generated* by the plugin.** @property NAME* @static* @type String* @default "pluginFlick"*/Flick.NAME = "pluginFlick";/*** The namespace for the plugin. This will be the property on the node, which will* reference the plugin instance, when it's plugged in.** @property NS* @static* @type String* @default "flick"*/Flick.NS = "flick";Y.extend(Flick, Y.Plugin.Base, {/*** The initializer lifecycle implementation.** @method initializer* @param {Object} config The user configuration for the plugin*/initializer : function(config) {this._node = this.get(HOST);this._renderClasses();this.setBounds();this._node.on(FLICK, Y.bind(this._onFlick, this), {minDistance : this.get(MIN_DISTANCE),minVelocity : this.get(MIN_VELOCITY)});},/*** Sets the min/max boundaries for the flick animation,* based on the boundingBox dimensions.** @method setBounds*/setBounds : function () {var box = this.get(BOUNDING_BOX),node = this._node,boxHeight = box.get(OFFSET_HEIGHT),boxWidth = box.get(OFFSET_WIDTH),contentHeight = node.get(SCROLL_HEIGHT),contentWidth = node.get(SCROLL_WIDTH);if (contentHeight > boxHeight) {this._maxY = contentHeight - boxHeight;this._minY = 0;this._scrollY = true;}if (contentWidth > boxWidth) {this._maxX = contentWidth - boxWidth;this._minX = 0;this._scrollX = true;}this._x = this._y = 0;node.set("top", this._y + "px");node.set("left", this._x + "px");},/*** Adds the CSS classes, necessary to set up overflow/position properties on the* node and boundingBox.** @method _renderClasses* @protected*/_renderClasses : function() {this.get(BOUNDING_BOX).addClass(Flick.CLASS_NAMES.box);this._node.addClass(Flick.CLASS_NAMES.content);},/*** The flick event listener. Kicks off the flick animation.** @method _onFlick* @param e {EventFacade} The flick event facade, containing e.flick.distance, e.flick.velocity etc.* @protected*/_onFlick: function(e) {this._v = e.flick.velocity;this._flick = true;this._flickAnim();},/*** Executes a single frame in the flick animation** @method _flickFrame* @protected*/_flickAnim: function() {var y = this._y,x = this._x,maxY = this._maxY,minY = this._minY,maxX = this._maxX,minX = this._minX,velocity = this._v,step = this.get(STEP),deceleration = this.get(DECELERATION),bounce = this.get(BOUNCE);this._v = (velocity * deceleration);this._snapToEdge = false;if (this._scrollX) {x = x - (velocity * step);}if (this._scrollY) {y = y - (velocity * step);}if (Math.abs(velocity).toFixed(4) <= Flick.VELOCITY_THRESHOLD) {this._flick = false;this._killTimer(!(this._exceededYBoundary || this._exceededXBoundary));if (this._scrollX) {if (x < minX) {this._snapToEdge = true;this._setX(minX);} else if (x > maxX) {this._snapToEdge = true;this._setX(maxX);}}if (this._scrollY) {if (y < minY) {this._snapToEdge = true;this._setY(minY);} else if (y > maxY) {this._snapToEdge = true;this._setY(maxY);}}} else {if (this._scrollX && (x < minX || x > maxX)) {this._exceededXBoundary = true;this._v *= bounce;}if (this._scrollY && (y < minY || y > maxY)) {this._exceededYBoundary = true;this._v *= bounce;}if (this._scrollX) {this._setX(x);}if (this._scrollY) {this._setY(y);}this._flickTimer = Y.later(step, this, this._flickAnim);}},/*** Internal utility method to set the X offset position** @method _setX* @param {Number} val* @private*/_setX : function(val) {this._move(val, null, this.get(DURATION), this.get(EASING));},/*** Internal utility method to set the Y offset position** @method _setY* @param {Number} val* @private*/_setY : function(val) {this._move(null, val, this.get(DURATION), this.get(EASING));},/*** Internal utility method to move the node to a given XY position,* using transitions, if specified.** @method _move* @param {Number} x The X offset position* @param {Number} y The Y offset position* @param {Number} duration The duration to use for the transition animation* @param {String} easing The easing to use for the transition animation.** @private*/_move: function(x, y, duration, easing) {if (x !== null) {x = this._bounce(x);} else {x = this._x;}if (y !== null) {y = this._bounce(y);} else {y = this._y;}duration = duration || this._snapToEdge ? Flick.SNAP_DURATION : 0;easing = easing || this._snapToEdge ? Flick.SNAP_EASING : Flick.EASING;this._x = x;this._y = y;this._anim(x, y, duration, easing);},/*** Internal utility method to perform the transition step** @method _anim* @param {Number} x The X offset position* @param {Number} y The Y offset position* @param {Number} duration The duration to use for the transition animation* @param {String} easing The easing to use for the transition animation.** @private*/_anim : function(x, y, duration, easing) {var xn = x * -1,yn = y * -1,transition = {duration : duration / 1000,easing : easing};Y.log("Transition: duration, easing:" + transition.duration, transition.easing, "node-flick");if (Y.Transition.useNative) {transition.transform = 'translate('+ (xn) + 'px,' + (yn) +'px)';} else {transition.left = xn + 'px';transition.top = yn + 'px';}this._node.transition(transition);},/*** Internal utility method to constrain the offset value* based on the bounce criteria.** @method _bounce* @param {Number} x The offset value to constrain.* @param {Number} max The max offset value.** @private*/_bounce : function(val, max) {var bounce = this.get(BOUNCE),dist = this.get(BOUNCE_DISTANCE),min = bounce ? -dist : 0;max = bounce ? max + dist : max;if(!bounce) {if(val < min) {val = min;} else if(val > max) {val = max;}}return val;},/*** Stop the animation timer** @method _killTimer* @private*/_killTimer: function() {if(this._flickTimer) {this._flickTimer.cancel();}}}, {/*** The threshold used to determine when the decelerated velocity of the node* is practically 0.** @property VELOCITY_THRESHOLD* @static* @type Number* @default 0.015*/VELOCITY_THRESHOLD : 0.015,/*** The duration to use for the bounce snap-back transition** @property SNAP_DURATION* @static* @type Number* @default 400*/SNAP_DURATION : 400,/*** The default easing to use for the main flick movement transition** @property EASING* @static* @type String* @default 'cubic-bezier(0, 0.1, 0, 1.0)'*/EASING : 'cubic-bezier(0, 0.1, 0, 1.0)',/*** The default easing to use for the bounce snap-back transition** @property SNAP_EASING* @static* @type String* @default 'ease-out'*/SNAP_EASING : 'ease-out',/*** The default CSS class names used by the plugin** @property CLASS_NAMES* @static* @type Object*/CLASS_NAMES : {box: getClassName(Flick.NS),content: getClassName(Flick.NS, "content")}});Y.Plugin.Flick = Flick;}, '3.18.1', {"requires": ["classnamemanager", "transition", "event-flick", "plugin"], "skinnable": true});