Files
CHIEFSOFT\ameye e592ca6823 first commit
2024-09-30 18:11:26 -04:00

524 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
};
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});