Skip to content

Commit

Permalink
Add Auto-parameterised start and end values #697
Browse files Browse the repository at this point in the history
Fixes #677
Closes #459
Fixes #562
Fixes #388
Fixes #263
  • Loading branch information
Rycochet committed Oct 23, 2016
1 parent 8779a09 commit 7b196f5
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 60 deletions.
211 changes: 153 additions & 58 deletions velocity.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,12 +622,12 @@
calls: []
},
/* Velocity's custom CSS stack. Made global for unit testing. */
CSS: { /* Defined below. */},
CSS: {/* Defined below. */},
/* A shim of the jQuery utility functions used by Velocity -- provided by Velocity's optional jQuery shim. */
Utilities: $,
/* Container for the user's custom animation redirects that are referenced by name in place of the properties map argument. */
Redirects: { /* Manually registered by the user. */},
Easings: { /* Defined below. */},
Redirects: {/* Manually registered by the user. */},
Easings: {/* Defined below. */},
/* Attempt to use ES6 Promises by default. Users can override this with a third-party promises library. */
Promise: window.Promise,
/* Velocity option defaults, which can be overriden by the user. */
Expand Down Expand Up @@ -882,7 +882,7 @@
dx: state.v,
dv: springAccelerationForState(state)
},
b = springEvaluateStateWithDerivative(state, dt * 0.5, a),
b = springEvaluateStateWithDerivative(state, dt * 0.5, a),
c = springEvaluateStateWithDerivative(state, dt * 0.5, b),
d = springEvaluateStateWithDerivative(state, dt, c),
dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx),
Expand All @@ -902,7 +902,7 @@
tension: null,
friction: null
},
path = [0],
path = [0],
time_lapsed = 0,
tolerance = 1 / 10000,
DT = 16 / 1000,
Expand Down Expand Up @@ -1493,6 +1493,11 @@

return extracted;
case "inject":
/* If we have a pattern then it might already have the right values */
if (/^rgb/.test(propertyValue)) {
return propertyValue;
}

/* If this is IE<=8 and an alpha component exists, strip it off. */
if (IE <= 8) {
if (propertyValue.split(" ").length === 4) {
Expand Down Expand Up @@ -2848,14 +2853,14 @@
start value since easings can only be non-hex strings or arrays. */
if ((!Type.isArray(valueData[1]) && /^[\d-]/.test(valueData[1])) || Type.isFunction(valueData[1]) || CSS.RegEx.isHex.test(valueData[1])) {
startValue = valueData[1];
/* Two or three-item array: If the second item is a non-hex string or an array, treat it as an easing. */
} else if ((Type.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1])) || Type.isArray(valueData[1])) {
/* Two or three-item array: If the second item is a non-hex string easing name or an array, treat it as an easing. */
} else if ((Type.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1]) && Velocity.Easings[valueData[1]]) || Type.isArray(valueData[1])) {
easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration);

/* Don't bother validating startValue's value now since the ensuing property cycling logic inherently does that. */
if (valueData[2] !== undefined) {
startValue = valueData[2];
}
startValue = valueData[2];
} else {
startValue = valueData[1] || valueData[2];
}
/* Handle the single-value format. */
} else {
Expand Down Expand Up @@ -2888,7 +2893,8 @@
/* Parse out endValue, easing, and startValue from the property's data. */
endValue = valueData[0],
easing = valueData[1],
startValue = valueData[2];
startValue = valueData[2],
pattern;

/**************************
Start Value Sourcing
Expand Down Expand Up @@ -2982,45 +2988,118 @@
return [numericValue, unitType];
};

/* Separate startValue. */
separatedValue = separateValue(property, startValue);
startValue = separatedValue[0];
startValueUnitType = separatedValue[1];
if (Type.isString(startValue) && Type.isString(endValue)) {
pattern = "";
var iStart = 0, // index in startValue
iEnd = 0, // index in endValue
aStart = [], // array of startValue numbers
aEnd = []; // array of endValue numbers

while (iStart < startValue.length && iEnd < endValue.length) {
var cStart = startValue[iStart],
cEnd = endValue[iEnd];

if (/[\d\.]/.test(cStart) && /[\d\.]/.test(cEnd)) {
var tStart = cStart, // temporary character buffer
tEnd = cEnd, // temporary character buffer
dotStart = ".", // Make sure we can only ever match a single dot in a decimal
dotEnd = "."; // Make sure we can only ever match a single dot in a decimal

while (++iStart < startValue.length) {
cStart = startValue[iStart];
if (cStart === dotStart) {
dotStart = ".."; // Can never match two characters
} else if (!/\d/.test(cStart)) {
break;
}
tStart += cStart;
}
while (++iEnd < endValue.length) {
cEnd = endValue[iEnd];
if (cEnd === dotEnd) {
dotEnd = ".."; // Can never match two characters
} else if (!/\d/.test(cEnd)) {
break;
}
tEnd += cEnd;
}
if (tStart === tEnd) {
pattern += tStart;
} else {
pattern += "{" + aStart.length + "}";
aStart.push(parseFloat(tStart));
aEnd.push(parseFloat(tEnd));
}
} else if (cStart === cEnd) {
pattern += cStart;
iStart++;
iEnd++;
} else {
// TODO: changing units, fixing colours
break;
}
}
if (iStart !== startValue.length || iEnd !== endValue.length) {
if (Velocity.debug) {
console.error("Trying to pattern match mis-matched strings [\"" + endValue + "\", \"" + startValue + "\"]");
}
pattern = undefined;
}
if (pattern) {
if (aStart.length) {
if (Velocity.debug) {
console.log("Pattern found \"" + pattern + "\" -> ", aStart, aEnd, startValue, endValue);
}
startValue = aStart;
endValue = aEnd;
endValueUnitType = startValueUnitType = "";
} else {
pattern = undefined;
}
}
}

if (!pattern) {
/* Separate startValue. */
separatedValue = separateValue(property, startValue);
startValue = separatedValue[0];
startValueUnitType = separatedValue[1];

/* Separate endValue, and extract a value operator (e.g. "+=", "-=") if one exists. */
separatedValue = separateValue(property, endValue);
endValue = separatedValue[0].replace(/^([+-\/*])=/, function(match, subMatch) {
operator = subMatch;
/* Separate endValue, and extract a value operator (e.g. "+=", "-=") if one exists. */
separatedValue = separateValue(property, endValue);
endValue = separatedValue[0].replace(/^([+-\/*])=/, function(match, subMatch) {
operator = subMatch;

/* Strip the operator off of the value. */
return "";
});
endValueUnitType = separatedValue[1];

/* Parse float values from endValue and startValue. Default to 0 if NaN is returned. */
startValue = parseFloat(startValue) || 0;
endValue = parseFloat(endValue) || 0;

/***************************************
Property-Specific Value Conversion
***************************************/

/* Custom support for properties that don't actually accept the % unit type, but where pollyfilling is trivial and relatively foolproof. */
if (endValueUnitType === "%") {
/* A %-value fontSize/lineHeight is relative to the parent's fontSize (as opposed to the parent's dimensions),
which is identical to the em unit's behavior, so we piggyback off of that. */
if (/^(fontSize|lineHeight)$/.test(property)) {
/* Convert % into an em decimal value. */
endValue = endValue / 100;
endValueUnitType = "em";
/* For scaleX and scaleY, convert the value into its decimal format and strip off the unit type. */
} else if (/^scale/.test(property)) {
endValue = endValue / 100;
endValueUnitType = "";
/* For RGB components, take the defined percentage of 255 and strip off the unit type. */
} else if (/(Red|Green|Blue)$/i.test(property)) {
endValue = (endValue / 100) * 255;
endValueUnitType = "";
/* Strip the operator off of the value. */
return "";
});
endValueUnitType = separatedValue[1];

/* Parse float values from endValue and startValue. Default to 0 if NaN is returned. */
startValue = parseFloat(startValue) || 0;
endValue = parseFloat(endValue) || 0;

/***************************************
Property-Specific Value Conversion
***************************************/

/* Custom support for properties that don't actually accept the % unit type, but where pollyfilling is trivial and relatively foolproof. */
if (endValueUnitType === "%") {
/* A %-value fontSize/lineHeight is relative to the parent's fontSize (as opposed to the parent's dimensions),
which is identical to the em unit's behavior, so we piggyback off of that. */
if (/^(fontSize|lineHeight)$/.test(property)) {
/* Convert % into an em decimal value. */
endValue = endValue / 100;
endValueUnitType = "em";
/* For scaleX and scaleY, convert the value into its decimal format and strip off the unit type. */
} else if (/^scale/.test(property)) {
endValue = endValue / 100;
endValueUnitType = "";
/* For RGB components, take the defined percentage of 255 and strip off the unit type. */
} else if (/(Red|Green|Blue)$/i.test(property)) {
endValue = (endValue / 100) * 255;
endValueUnitType = "";
}
}
}

Expand Down Expand Up @@ -3055,8 +3134,8 @@
position: CSS.getPropertyValue(element, "position"), /* GET */
fontSize: CSS.getPropertyValue(element, "fontSize") /* GET */
},
/* Determine if the same % ratio can be used. % is based on the element's position value and its parent's width and height dimensions. */
samePercentRatio = ((sameRatioIndicators.position === callUnitConversionData.lastPosition) && (sameRatioIndicators.myParent === callUnitConversionData.lastParent)),
/* Determine if the same % ratio can be used. % is based on the element's position value and its parent's width and height dimensions. */
samePercentRatio = ((sameRatioIndicators.position === callUnitConversionData.lastPosition) && (sameRatioIndicators.myParent === callUnitConversionData.lastParent)),
/* Determine if the same em ratio can be used. em is relative to the element's fontSize. */
sameEmRatio = (sameRatioIndicators.fontSize === callUnitConversionData.lastFontSize);

Expand Down Expand Up @@ -3239,6 +3318,9 @@
unitType: endValueUnitType,
easing: easing
};
if (pattern) {
tweensContainer[property].pattern = pattern;
}

if (Velocity.debug) {
console.log("tweensContainer (" + property + "): " + JSON.stringify(tweensContainer[property]), element);
Expand Down Expand Up @@ -3609,19 +3691,32 @@
Current Value Calculation
******************************/

/* If this is the last tick pass (if we've reached 100% completion for this tween),
ensure that currentValue is explicitly set to its target endValue so that it's not subjected to any rounding. */
if (percentComplete === 1) {
if (Type.isString(tween.pattern)) {
var patternReplace = percentComplete === 1 ?
function($0, index) {
return tween.endValue[index];
} :
function($0, index) {
var startValue = tween.startValue[index],
tweenDelta = tween.endValue[index] - startValue;

return startValue + (tweenDelta * easing(percentComplete, opts, tweenDelta));
};

currentValue = tween.pattern.replace(/{(\d+)}/g, patternReplace);
} else if (percentComplete === 1) {
/* If this is the last tick pass (if we've reached 100% completion for this tween),
ensure that currentValue is explicitly set to its target endValue so that it's not subjected to any rounding. */
currentValue = tween.endValue;
/* Otherwise, calculate currentValue based on the current delta from startValue. */
} else {
/* Otherwise, calculate currentValue based on the current delta from startValue. */
var tweenDelta = tween.endValue - tween.startValue;
currentValue = tween.startValue + (tweenDelta * easing(percentComplete, opts, tweenDelta));

currentValue = tween.startValue + (tweenDelta * easing(percentComplete, opts, tweenDelta));
/* If no value change is occurring, don't proceed with DOM updating. */
if (!firstTick && (currentValue === tween.currentValue)) {
continue;
}
}
if (!firstTick && (currentValue === tween.currentValue)) {
continue;
}

tween.currentValue = currentValue;
Expand Down
Loading

0 comments on commit 7b196f5

Please sign in to comment.