Skip to content

Commit 4d39bfa

Browse files
committed
Optimise "reverse" command, make use of built-in reverse flag
1 parent 95dfb21 commit 4d39bfa

File tree

9 files changed

+124
-112
lines changed

9 files changed

+124
-112
lines changed

Diff for: src/Velocity/tweens.ts

+28-36
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ namespace VelocityStatic {
8282
* pre-allocates the array as it is then the correct size and slightly
8383
* faster to access.
8484
*/
85-
export function expandProperties(animation: AnimationCall, properties: VelocityProperties, reverse?: boolean) {
85+
export function expandProperties(animation: AnimationCall, properties: VelocityProperties) {
8686
const tweens = animation.tweens = Object.create(null),
8787
elements = animation.elements,
8888
element = animation.element,
@@ -115,46 +115,38 @@ namespace VelocityStatic {
115115
continue;
116116
}
117117
const tween: VelocityTween = tweens[propertyName] = new Array(Tween.length) as any;
118-
if (reverse) {
119-
tween[Tween.START] = valueData[Tween.END];
120-
tween[Tween.EASING] = valueData[Tween.EASING];
121-
tween[Tween.END] = valueData[Tween.START];
122-
tween[Tween.PATTERN] = valueData[Tween.PATTERN];
123-
tween[Tween.ROUNDING] = valueData[Tween.ROUNDING];
124-
} else {
125-
let endValue: string,
126-
startValue: string;
118+
let endValue: string,
119+
startValue: string;
127120

128-
if (isFunction(valueData)) {
129-
// If we have a function as the main argument then resolve
130-
// it first, in case it returns an array that needs to be
131-
// split.
132-
valueData = (valueData as VelocityPropertyFn).call(element, elementArrayIndex, elements.length, elements);
133-
}
134-
if (Array.isArray(valueData)) {
135-
// valueData is an array in the form of
136-
// [ endValue, [, easing] [, startValue] ]
137-
const arr1 = valueData[1],
138-
arr2 = valueData[2];
121+
if (isFunction(valueData)) {
122+
// If we have a function as the main argument then resolve
123+
// it first, in case it returns an array that needs to be
124+
// split.
125+
valueData = (valueData as VelocityPropertyFn).call(element, elementArrayIndex, elements.length, elements);
126+
}
127+
if (Array.isArray(valueData)) {
128+
// valueData is an array in the form of
129+
// [ endValue, [, easing] [, startValue] ]
130+
const arr1 = valueData[1],
131+
arr2 = valueData[2];
139132

140-
endValue = valueData[0] as any;
141-
if ((isString(arr1) && (/^[\d-]/.test(arr1) || CSS.RegEx.isHex.test(arr1))) || isFunction(arr1) || isNumber(arr1)) {
142-
startValue = arr1 as any;
143-
} else if ((isString(arr1) && Easing.Easings[arr1]) || Array.isArray(arr1)) {
144-
tween[Tween.EASING] = arr1 as any;
145-
startValue = arr2 as any;
146-
} else {
147-
startValue = arr1 || arr2 as any;
148-
}
133+
endValue = valueData[0] as any;
134+
if ((isString(arr1) && (/^[\d-]/.test(arr1) || CSS.RegEx.isHex.test(arr1))) || isFunction(arr1) || isNumber(arr1)) {
135+
startValue = arr1 as any;
136+
} else if ((isString(arr1) && Easing.Easings[arr1]) || Array.isArray(arr1)) {
137+
tween[Tween.EASING] = arr1 as any;
138+
startValue = arr2 as any;
149139
} else {
150-
endValue = valueData as any;
151-
}
152-
tween[Tween.END] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName) as any;
153-
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
154-
tween[Tween.START] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName) as any;
140+
startValue = arr1 || arr2 as any;
155141
}
156-
explodeTween(propertyName, tween, duration, !!startValue);
142+
} else {
143+
endValue = valueData as any;
144+
}
145+
tween[Tween.END] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName) as any;
146+
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
147+
tween[Tween.START] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName) as any;
157148
}
149+
explodeTween(propertyName, tween, duration, !!startValue);
158150
}
159151
}
160152

Diff for: src/core.ts

+29-15
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
323323
options.repeat = options.repeatAgain = defaults.repeat;
324324
}
325325

326+
if (isReverse && options.queue === false) {
327+
throw new Error("VelocityJS: Cannot reverse a queue:false animation.");
328+
}
329+
326330
/* When a set of elements is targeted by a Velocity call, the set is broken up and each element has the current Velocity call individually queued onto it.
327331
In this way, each element's existing queue is respected; some elements may already be animating and accordingly should not have this current Velocity call triggered immediately. */
328332
/* In each queue, tween data is processed for each animating property then pushed onto the call-wide calls array. When the last element in the set has had its tweens processed,
@@ -343,26 +347,36 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
343347
animations = [];
344348
for (let index = 0; index < elements.length; index++) {
345349
const element = elements[index];
350+
let flags = 0;
346351

347-
if (isNode(element)) {
348-
if (isReverse && options.queue !== false) {
349-
const lastAnimation = Data(element).lastAnimationList[options.queue];
352+
if (isNode(element)) { // TODO: This needs to check for valid animation targets, not just Elements
353+
if (isReverse) {
354+
const lastAnimation = Data(element).lastAnimationList[options.queue as string];
350355

351356
propertiesMap = lastAnimation && lastAnimation.tweens;
357+
if (!propertiesMap) {
358+
console.error("VelocityJS: Attempting to reverse an animation on an element with no previous animation:", element);
359+
continue;
360+
}
361+
flags |= AnimationFlags.REVERSE & ~(lastAnimation._flags & AnimationFlags.REVERSE);
352362
}
353-
if (propertiesMap) {
354-
const tweens = Object.create(null),
355-
animation: AnimationCall = Object.assign({
356-
element: element,
357-
tweens: tweens
358-
}, rootAnimation);
359-
360-
options._total++;
361-
animations.push(animation);
362-
363-
VelocityStatic.expandProperties(animation, propertiesMap, isReverse);
364-
VelocityStatic.queue(element, animation, getValue(animation.queue, options.queue));
363+
const tweens = Object.create(null),
364+
animation: AnimationCall = Object.assign({
365+
element: element,
366+
tweens: tweens
367+
}, rootAnimation);
368+
369+
options._total++;
370+
animation._flags |= flags;
371+
animations.push(animation);
372+
if (isReverse) {
373+
// In this case we're using the previous animation, so
374+
// it will be expanded correctly when that one runs.
375+
animation.tweens = propertiesMap as any;
376+
} else {
377+
VelocityStatic.expandProperties(animation, propertiesMap);
365378
}
379+
VelocityStatic.queue(element, animation, options.queue);
366380
}
367381
}
368382
if (VelocityStatic.State.isTicking === false) {

Diff for: test/src/3. Command/Command Reverse.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ QUnit.test("Reverse", function(assert) {
1717
async(assert, 2, function(done) {
1818
Velocity($target, defaultProperties, {
1919
complete: function(elements) {
20-
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Initial property #1 set correctly.");
21-
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Initial property #2 set correctly.");
20+
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Initial property #1 set correctly. (" + defaultProperties.opacity + ")");
21+
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Initial property #2 set correctly. (" + defaultProperties.width + ")");
2222

2323
done();
2424
}
@@ -28,8 +28,8 @@ QUnit.test("Reverse", function(assert) {
2828
async(assert, 2, function(done) {
2929
Velocity($target, "reverse", {
3030
complete: function(elements) {
31-
assert.equal(elements[0].velocity("style", "opacity"), opacity, "Reversed property #1 set correctly.");
32-
assert.equal(elements[0].velocity("style", "width"), width, "Reversed property #2 set correctly.");
31+
assert.equal(elements[0].velocity("style", "opacity"), opacity, "Reversed property #1 set correctly. (" + opacity + ")");
32+
assert.equal(elements[0].velocity("style", "width"), width, "Reversed property #2 set correctly. (" + width + ")");
3333

3434
done();
3535
}
@@ -39,8 +39,8 @@ QUnit.test("Reverse", function(assert) {
3939
async(assert, 2, function(done) {
4040
Velocity($target, "reverse", {
4141
complete: function(elements) {
42-
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Chained reversed property #1 set correctly.");
43-
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Chained reversed property #2 set correctly.");
42+
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Chained reversed property #1 set correctly. (" + defaultProperties.opacity + ")");
43+
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Chained reversed property #2 set correctly. (" + defaultProperties.width + ")");
4444

4545
done();
4646
}

Diff for: test/test.js

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: test/test.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: velocity.js

+50-44
Original file line numberDiff line numberDiff line change
@@ -3596,7 +3596,7 @@ var VelocityStatic;
35963596
* pre-allocates the array as it is then the correct size and slightly
35973597
* faster to access.
35983598
*/
3599-
function expandProperties(animation, properties, reverse) {
3599+
function expandProperties(animation, properties) {
36003600
var tweens = animation.tweens = Object.create(null), elements = animation.elements, element = animation.element, elementArrayIndex = elements.indexOf(element), data = Data(element), queue = getValue(animation.queue, animation.options.queue), duration = getValue(animation.options.duration, VelocityStatic.defaults.duration);
36013601
for (var property in properties) {
36023602
var propertyName = VelocityStatic.CSS.camelCase(property);
@@ -3617,42 +3617,34 @@ var VelocityStatic;
36173617
continue;
36183618
}
36193619
var tween_4 = tweens[propertyName] = new Array(5);
3620-
if (reverse) {
3621-
tween_4[2] = valueData[0];
3622-
tween_4[1] = valueData[1];
3623-
tween_4[0] = valueData[2];
3624-
tween_4[3] = valueData[3];
3625-
tween_4[4] = valueData[4];
3626-
} else {
3627-
var endValue = void 0, startValue = void 0;
3628-
if (isFunction(valueData)) {
3629-
// If we have a function as the main argument then resolve
3630-
// it first, in case it returns an array that needs to be
3631-
// split.
3632-
valueData = valueData.call(element, elementArrayIndex, elements.length, elements);
3633-
}
3634-
if (Array.isArray(valueData)) {
3635-
// valueData is an array in the form of
3636-
// [ endValue, [, easing] [, startValue] ]
3637-
var arr1 = valueData[1], arr2 = valueData[2];
3638-
endValue = valueData[0];
3639-
if (isString(arr1) && (/^[\d-]/.test(arr1) || VelocityStatic.CSS.RegEx.isHex.test(arr1)) || isFunction(arr1) || isNumber(arr1)) {
3640-
startValue = arr1;
3641-
} else if (isString(arr1) && VelocityStatic.Easing.Easings[arr1] || Array.isArray(arr1)) {
3642-
tween_4[1] = arr1;
3643-
startValue = arr2;
3644-
} else {
3645-
startValue = arr1 || arr2;
3646-
}
3620+
var endValue = void 0, startValue = void 0;
3621+
if (isFunction(valueData)) {
3622+
// If we have a function as the main argument then resolve
3623+
// it first, in case it returns an array that needs to be
3624+
// split.
3625+
valueData = valueData.call(element, elementArrayIndex, elements.length, elements);
3626+
}
3627+
if (Array.isArray(valueData)) {
3628+
// valueData is an array in the form of
3629+
// [ endValue, [, easing] [, startValue] ]
3630+
var arr1 = valueData[1], arr2 = valueData[2];
3631+
endValue = valueData[0];
3632+
if (isString(arr1) && (/^[\d-]/.test(arr1) || VelocityStatic.CSS.RegEx.isHex.test(arr1)) || isFunction(arr1) || isNumber(arr1)) {
3633+
startValue = arr1;
3634+
} else if (isString(arr1) && VelocityStatic.Easing.Easings[arr1] || Array.isArray(arr1)) {
3635+
tween_4[1] = arr1;
3636+
startValue = arr2;
36473637
} else {
3648-
endValue = valueData;
3649-
}
3650-
tween_4[0] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName);
3651-
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
3652-
tween_4[2] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName);
3638+
startValue = arr1 || arr2;
36533639
}
3654-
explodeTween(propertyName, tween_4, duration, !!startValue);
3640+
} else {
3641+
endValue = valueData;
36553642
}
3643+
tween_4[0] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName);
3644+
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
3645+
tween_4[2] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName);
3646+
}
3647+
explodeTween(propertyName, tween_4, duration, !!startValue);
36563648
}
36573649
}
36583650
VelocityStatic.expandProperties = expandProperties;
@@ -4462,6 +4454,9 @@ function VelocityFn() {
44624454
options.loop = defaults.loop;
44634455
options.repeat = options.repeatAgain = defaults.repeat;
44644456
}
4457+
if (isReverse && options.queue === false) {
4458+
throw new Error("VelocityJS: Cannot reverse a queue:false animation.");
4459+
}
44654460
/* When a set of elements is targeted by a Velocity call, the set is broken up and each element has the current Velocity call individually queued onto it.
44664461
In this way, each element's existing queue is respected; some elements may already be animating and accordingly should not have this current Velocity call triggered immediately. */
44674462
/* In each queue, tween data is processed for each animating property then pushed onto the call-wide calls array. When the last element in the set has had its tweens processed,
@@ -4480,21 +4475,32 @@ function VelocityFn() {
44804475
animations = [];
44814476
for (var index = 0; index < elements.length; index++) {
44824477
var element = elements[index];
4478+
var flags = 0;
44834479
if (isNode(element)) {
4484-
if (isReverse && options.queue !== false) {
4480+
if (isReverse) {
44854481
var lastAnimation = Data(element).lastAnimationList[options.queue];
44864482
propertiesMap = lastAnimation && lastAnimation.tweens;
4483+
if (!propertiesMap) {
4484+
console.error("VelocityJS: Attempting to reverse an animation on an element with no previous animation:", element);
4485+
continue;
4486+
}
4487+
flags |= 64 & ~(lastAnimation._flags & 64);
44874488
}
4488-
if (propertiesMap) {
4489-
var tweens = Object.create(null), animation = Object.assign({
4490-
element: element,
4491-
tweens: tweens
4492-
}, rootAnimation);
4493-
options._total++;
4494-
animations.push(animation);
4495-
VelocityStatic.expandProperties(animation, propertiesMap, isReverse);
4496-
VelocityStatic.queue(element, animation, getValue(animation.queue, options.queue));
4489+
var tweens = Object.create(null), animation = Object.assign({
4490+
element: element,
4491+
tweens: tweens
4492+
}, rootAnimation);
4493+
options._total++;
4494+
animation._flags |= flags;
4495+
animations.push(animation);
4496+
if (isReverse) {
4497+
// In this case we're using the previous animation, so
4498+
// it will be expanded correctly when that one runs.
4499+
animation.tweens = propertiesMap;
4500+
} else {
4501+
VelocityStatic.expandProperties(animation, propertiesMap);
44974502
}
4503+
VelocityStatic.queue(element, animation, options.queue);
44984504
}
44994505
}
45004506
if (VelocityStatic.State.isTicking === false) {

Diff for: velocity.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: velocity.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)