Skip to content

Commit ae9eb90

Browse files
committed
Merge branch '2.2.0'
2 parents a2d2b4c + b14a3a9 commit ae9eb90

16 files changed

+2475
-298
lines changed

anime.js

+109-55
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* http://animejs.com
33
* JavaScript animation engine
4-
* @version v2.1.0
4+
* @version v2.2.0
55
* @author Julian Garnier
66
* @copyright ©2017 Julian Garnier
77
* Released under the MIT license
@@ -55,6 +55,7 @@
5555
const is = {
5656
arr: a => Array.isArray(a),
5757
obj: a => stringContains(Object.prototype.toString.call(a), 'Object'),
58+
pth: a => is.obj(a) && a.hasOwnProperty('totalLength'),
5859
svg: a => a instanceof SVGElement,
5960
dom: a => a.nodeType || is.svg(a),
6061
str: a => typeof a === 'string',
@@ -229,6 +230,21 @@
229230

230231
// Arrays
231232

233+
function filterArray(arr, callback) {
234+
const len = arr.length;
235+
const thisArg = arguments.length >= 2 ? arguments[1] : void 0;
236+
let result = [];
237+
for (let i = 0; i < len; i++) {
238+
if (i in arr) {
239+
const val = arr[i];
240+
if (callback.call(thisArg, val, i, arr)) {
241+
result.push(val);
242+
}
243+
}
244+
}
245+
return result;
246+
}
247+
232248
function flattenArray(arr) {
233249
return arr.reduce((a, b) => a.concat(is.arr(b) ? flattenArray(b) : b), []);
234250
}
@@ -246,10 +262,6 @@
246262

247263
// Objects
248264

249-
function objectHas(obj, prop) {
250-
return obj.hasOwnProperty(prop);
251-
}
252-
253265
function cloneObject(o) {
254266
let clone = {};
255267
for (let p in o) clone[p] = o[p];
@@ -258,7 +270,7 @@
258270

259271
function replaceObjectProps(o1, o2) {
260272
let o = cloneObject(o1);
261-
for (let p in o1) o[p] = objectHas(o2, p) ? o2[p] : o1[p];
273+
for (let p in o1) o[p] = o2.hasOwnProperty(p) ? o2[p] : o1[p];
262274
return o;
263275
}
264276

@@ -270,21 +282,27 @@
270282

271283
// Colors
272284

273-
function hexToRgb(hexValue) {
285+
function rgbToRgba(rgbValue) {
286+
const rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue);
287+
return rgb ? `rgba(${rgb[1]},1)` : rgbValue;
288+
}
289+
290+
function hexToRgba(hexValue) {
274291
const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
275292
const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b );
276293
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
277294
const r = parseInt(rgb[1], 16);
278295
const g = parseInt(rgb[2], 16);
279296
const b = parseInt(rgb[3], 16);
280-
return `rgb(${r},${g},${b})`;
297+
return `rgba(${r},${g},${b},1)`;
281298
}
282299

283-
function hslToRgb(hslValue) {
284-
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue);
300+
function hslToRgba(hslValue) {
301+
const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
285302
const h = parseInt(hsl[1]) / 360;
286303
const s = parseInt(hsl[2]) / 100;
287304
const l = parseInt(hsl[3]) / 100;
305+
const a = hsl[4] || 1;
288306
function hue2rgb(p, q, t) {
289307
if (t < 0) t += 1;
290308
if (t > 1) t -= 1;
@@ -303,13 +321,13 @@
303321
g = hue2rgb(p, q, h);
304322
b = hue2rgb(p, q, h - 1/3);
305323
}
306-
return `rgb(${r * 255},${g * 255},${b * 255})`;
324+
return `rgba(${r * 255},${g * 255},${b * 255},${a})`;
307325
}
308326

309327
function colorToRgb(val) {
310-
if (is.rgb(val)) return val;
311-
if (is.hex(val)) return hexToRgb(val);
312-
if (is.hsl(val)) return hslToRgb(val);
328+
if (is.rgb(val)) return rgbToRgba(val);
329+
if (is.hex(val)) return hexToRgba(val);
330+
if (is.hsl(val)) return hslToRgba(val);
313331
}
314332

315333
// Units
@@ -361,7 +379,7 @@
361379
props.push(match[1]);
362380
values.push(match[2]);
363381
}
364-
const value = values.filter((val, i) => props[i] === propName );
382+
const value = filterArray(values, (val, i) => props[i] === propName);
365383
return value.length ? value[0] : defaultVal;
366384
}
367385

@@ -454,10 +472,6 @@
454472

455473
// Motion path
456474

457-
function isPath(val) {
458-
return is.obj(val) && objectHas(val, 'totalLength');
459-
}
460-
461475
function getPath(path, percent) {
462476
const el = is.str(path) ? selectString(path)[0] : path;
463477
const p = percent || 100;
@@ -485,27 +499,23 @@
485499
}
486500
}
487501

488-
// Decompose / recompose functions adapted from Animate Plus https://github.com/bendc/animateplus
502+
// Decompose value
489503

490504
function decomposeValue(val, unit) {
491505
const rgx = /-?\d*\.?\d+/g;
492-
const value = validateValue((isPath(val) ? val.totalLength : val), unit) + '';
506+
const value = validateValue((is.pth(val) ? val.totalLength : val), unit) + '';
493507
return {
494508
original: value,
495509
numbers: value.match(rgx) ? value.match(rgx).map(Number) : [0],
496510
strings: (is.str(val) || unit) ? value.split(rgx) : []
497511
}
498512
}
499513

500-
function recomposeValue(numbers, strings) {
501-
return (strings.length === 0) ? numbers[0] : strings.reduce((a, b, i) => a + numbers[i - 1] + (b ? b : ' '));
502-
}
503-
504514
// Animatables
505515

506516
function parseTargets(targets) {
507517
const targetsArray = targets ? (flattenArray(is.arr(targets) ? targets.map(toArray) : toArray(targets))) : [];
508-
return targetsArray.filter((item, pos, self) => self.indexOf(item) === pos);
518+
return filterArray(targetsArray, (item, pos, self) => self.indexOf(item) === pos);
509519
}
510520

511521
function getAnimatables(targets) {
@@ -534,7 +544,7 @@
534544
// Default delay value should be applied only on the first tween
535545
const delay = !i ? tweenSettings.delay : 0;
536546
// Use path object as a tween value
537-
let obj = is.obj(v) && !isPath(v) ? v : {value: v};
547+
let obj = is.obj(v) && !is.pth(v) ? v : {value: v};
538548
// Set default delay value
539549
if (is.und(obj.delay)) obj.delay = delay;
540550
return obj;
@@ -545,7 +555,7 @@
545555
let properties = [];
546556
const settings = mergeObjects(instanceSettings, tweenSettings);
547557
for (let p in params) {
548-
if (!objectHas(settings, p) && p !== 'targets') {
558+
if (!settings.hasOwnProperty(p) && p !== 'targets') {
549559
properties.push({
550560
name: p,
551561
offset: settings['offset'],
@@ -587,14 +597,15 @@
587597
const from = is.arr(tweenValue) ? tweenValue[0] : previousValue;
588598
const to = getRelativeValue(is.arr(tweenValue) ? tweenValue[1] : tweenValue, from);
589599
const unit = getUnit(to) || getUnit(from) || getUnit(originalValue);
590-
tween.isPath = isPath(tweenValue);
591600
tween.from = decomposeValue(from, unit);
592601
tween.to = decomposeValue(to, unit);
593602
tween.start = previousTween ? previousTween.end : prop.offset;
594603
tween.end = tween.start + tween.delay + tween.duration;
595604
tween.easing = normalizeEasing(tween.easing);
596605
tween.elasticity = (1000 - minMaxValue(tween.elasticity, 1, 999)) / 1000;
597-
if (is.col(tween.from.original)) tween.round = 1;
606+
tween.isPath = is.pth(tweenValue);
607+
tween.isColor = is.col(tween.from.original);
608+
if (tween.isColor) tween.round = 1;
598609
previousTween = tween;
599610
return tween;
600611
});
@@ -630,18 +641,22 @@
630641
}
631642

632643
function getAnimations(animatables, properties) {
633-
return flattenArray(animatables.map(animatable => {
644+
return filterArray(flattenArray(animatables.map(animatable => {
634645
return properties.map(prop => {
635646
return createAnimation(animatable, prop);
636647
});
637-
})).filter(a => !is.und(a));
648+
})), a => !is.und(a));
638649
}
639650

640651
// Create Instance
641652

642-
function getInstanceTimings(type, animations, tweenSettings) {
643-
const math = (type === 'delay') ? Math.min : Math.max;
644-
return animations.length ? math.apply(Math, animations.map(anim => anim[type])) : tweenSettings[type];
653+
function getInstanceTimings(type, animations, instanceSettings, tweenSettings) {
654+
const isDelay = (type === 'delay');
655+
if (animations.length) {
656+
return (isDelay ? Math.min : Math.max).apply(Math, animations.map(anim => anim[type]));
657+
} else {
658+
return isDelay ? tweenSettings.delay : instanceSettings.offset + tweenSettings.delay + tweenSettings.duration;
659+
}
645660
}
646661

647662
function createNewInstance(params) {
@@ -654,8 +669,8 @@
654669
children: [],
655670
animatables: animatables,
656671
animations: animations,
657-
duration: getInstanceTimings('duration', animations, tweenSettings),
658-
delay: getInstanceTimings('delay', animations, tweenSettings)
672+
duration: getInstanceTimings('duration', animations, instanceSettings, tweenSettings),
673+
delay: getInstanceTimings('delay', animations, instanceSettings, tweenSettings)
659674
});
660675
}
661676

@@ -710,38 +725,76 @@
710725

711726
function syncInstanceChildren(time) {
712727
const children = instance.children;
728+
const childrenLength = children.length;
713729
if (time >= instance.currentTime) {
714-
for (let i = 0; i < children.length; i++) children[i].seek(time);
730+
for (let i = 0; i < childrenLength; i++) children[i].seek(time);
715731
} else {
716-
for (let i = children.length; i--;) children[i].seek(time);
732+
for (let i = childrenLength; i--;) children[i].seek(time);
717733
}
718734
}
719735

720736
function setAnimationsProgress(insTime) {
721737
let i = 0;
722738
let transforms = {};
723739
const animations = instance.animations;
724-
while (i < animations.length) {
740+
const animationsLength = animations.length;
741+
while (i < animationsLength) {
725742
const anim = animations[i];
726743
const animatable = anim.animatable;
727744
const tweens = anim.tweens;
728-
const tween = tweens.filter(t => (insTime < t.end))[0] || tweens[tweens.length - 1];
745+
const tweenLength = tweens.length - 1;
746+
let tween = tweens[tweenLength];
747+
// Only check for keyframes if there is more than one tween
748+
if (tweenLength) tween = filterArray(tweens, t => (insTime < t.end))[0] || tween;
729749
const elapsed = minMaxValue(insTime - tween.start - tween.delay, 0, tween.duration) / tween.duration;
730750
const eased = isNaN(elapsed) ? 1 : tween.easing(elapsed, tween.elasticity);
751+
const strings = tween.to.strings;
731752
const round = tween.round;
732-
const progress = recomposeValue(tween.to.numbers.map((number, p) => {
733-
const start = tween.from.numbers[p];
734-
let value = start + eased * (number - start);
735-
if (tween.isPath) value = getPathProgress(tween.value, value);
736-
if (round) value = Math.round(value * round) / round;
737-
return value;
738-
}), tween.to.strings);
753+
let numbers = [];
754+
let progress;
755+
const toNumbersLength = tween.to.numbers.length;
756+
for (let n = 0; n < toNumbersLength; n++) {
757+
let value;
758+
const toNumber = tween.to.numbers[n];
759+
const fromNumber = tween.from.numbers[n];
760+
if (!tween.isPath) {
761+
value = fromNumber + (eased * (toNumber - fromNumber));
762+
} else {
763+
value = getPathProgress(tween.value, eased * toNumber);
764+
}
765+
if (round) {
766+
if (!(tween.isColor && n > 2)) {
767+
value = Math.round(value * round) / round;
768+
}
769+
}
770+
numbers.push(value);
771+
}
772+
// Manual Array.reduce for better performances
773+
const stringsLength = strings.length;
774+
if (!stringsLength) {
775+
progress = numbers[0];
776+
} else {
777+
progress = strings[0];
778+
for (let s = 0; s < stringsLength; s++) {
779+
const a = strings[s];
780+
const b = strings[s + 1];
781+
const n = numbers[s];
782+
if (!isNaN(n)) {
783+
if (!b) {
784+
progress += n + ' ';
785+
} else {
786+
progress += n + b;
787+
}
788+
}
789+
}
790+
}
739791
setTweenProgress[anim.type](animatable.target, anim.property, progress, transforms, animatable.id);
740792
anim.currentValue = progress;
741793
i++;
742794
}
743-
if (transforms) {
744-
let id; for (id in transforms) {
795+
const transformsLength = Object.keys(transforms).length;
796+
if (transformsLength) {
797+
for (let id = 0; id < transformsLength; id++) {
745798
if (!transformString) {
746799
const t = 'transform';
747800
transformString = (getCSSValue(document.body, t) ? t : `-webkit-${t}`);
@@ -766,17 +819,17 @@
766819
function setInstanceProgress(engineTime) {
767820
const insDuration = instance.duration;
768821
const insOffset = instance.offset;
769-
const insDelay = instance.delay;
822+
const insStart = insOffset + instance.delay;
770823
const insCurrentTime = instance.currentTime;
771824
const insReversed = instance.reversed;
772825
const insTime = adjustTime(engineTime);
773826
if (instance.children.length) syncInstanceChildren(insTime);
774-
if (insTime >= insDelay) {
775-
setCallback('run');
827+
if (insTime >= insStart || !insDuration) {
776828
if (!instance.began) {
777829
instance.began = true;
778830
setCallback('begin');
779831
}
832+
setCallback('run');
780833
}
781834
if (insTime > insOffset && insTime < insDuration) {
782835
setAnimationsProgress(insTime);
@@ -785,7 +838,7 @@
785838
setAnimationsProgress(0);
786839
if (insReversed) countIteration();
787840
}
788-
if (insTime >= insDuration && insCurrentTime !== insDuration) {
841+
if ((insTime >= insDuration && insCurrentTime !== insDuration) || !insDuration) {
789842
setAnimationsProgress(insDuration);
790843
if (!insReversed) countIteration();
791844
}
@@ -904,6 +957,7 @@
904957
const tlDuration = tl.duration;
905958
const insOffset = insParams.offset;
906959
insParams.autoplay = false;
960+
insParams.direction = tl.direction;
907961
insParams.offset = is.und(insOffset) ? tlDuration : getRelativeValue(insOffset, tlDuration);
908962
tl.began = true;
909963
tl.completed = true;
@@ -922,7 +976,7 @@
922976
return tl;
923977
}
924978

925-
anime.version = '2.1.0';
979+
anime.version = '2.2.0';
926980
anime.speed = 1;
927981
anime.running = activeInstances;
928982
anime.remove = removeTargets;

0 commit comments

Comments
 (0)