/**
* @private
*
* This easing is typically used for {@link Ext.scroll.Scroller}. It's a combination of
* {@link Ext.fx.easing.Momentum} and {@link Ext.fx.easing.Bounce}, which emulates deceleration
* when the animated element is still within its boundary, then bouncing back (snapping) when
* it's out-of-bound.
*/
Ext.define('Ext.fx.easing.BoundMomentum', {
extend: 'Ext.fx.easing.Abstract',
requires: [
'Ext.fx.easing.Momentum',
'Ext.fx.easing.Bounce'
],
config: {
/**
* @cfg {Object} momentum
* A valid config object for {@link Ext.fx.easing.Momentum}
* @accessor
*/
momentum: null,
/**
* @cfg {Object} bounce
* A valid config object for {@link Ext.fx.easing.Bounce}
* @accessor
*/
bounce: null,
minMomentumValue: 0,
maxMomentumValue: 0,
/**
* @cfg {Number} minVelocity
* The minimum velocity to end this easing
* @accessor
*/
minVelocity: 0.01,
/**
* @cfg {Number} startVelocity
* The start velocity
* @accessor
*/
startVelocity: 0
},
applyMomentum: function(config, currentEasing) {
return Ext.factory(config, Ext.fx.easing.Momentum, currentEasing);
},
applyBounce: function(config, currentEasing) {
return Ext.factory(config, Ext.fx.easing.Bounce, currentEasing);
},
updateStartTime: function(startTime) {
this.getMomentum().setStartTime(startTime);
this.callParent(arguments);
},
updateStartVelocity: function(startVelocity) {
this.getMomentum().setStartVelocity(startVelocity);
},
updateStartValue: function(startValue) {
this.getMomentum().setStartValue(startValue);
},
reset: function() {
this.lastValue = null;
this.isBouncingBack = false;
this.isOutOfBound = false;
return this.callParent(arguments);
},
getValue: function() {
var momentum = this.getMomentum(),
bounce = this.getBounce(),
startVelocity = momentum.getStartVelocity(),
direction = startVelocity > 0 ? 1 : -1,
minValue = this.getMinMomentumValue(),
maxValue = this.getMaxMomentumValue(),
boundedValue = (direction === 1) ? maxValue : minValue,
lastValue = this.lastValue,
value, velocity;
if (startVelocity === 0) {
return this.getStartValue();
}
if (!this.isOutOfBound) {
value = momentum.getValue();
velocity = momentum.getVelocity();
if (Math.abs(velocity) < this.getMinVelocity()) {
this.isEnded = true;
}
if (value >= minValue && value <= maxValue) {
return value;
}
this.isOutOfBound = true;
bounce.setStartTime(Ext.Date.now())
.setStartVelocity(velocity)
.setStartValue(boundedValue);
}
value = bounce.getValue();
if (!this.isEnded) {
if (!this.isBouncingBack) {
if (lastValue !== null) {
if ((direction === 1 && value < lastValue) ||
(direction === -1 && value > lastValue)) {
this.isBouncingBack = true;
}
}
}
else {
if (Math.round(value) === boundedValue) {
this.isEnded = true;
}
}
}
this.lastValue = value;
return value;
}
});