【发布时间】:2016-11-07 10:09:00
【问题描述】:
首先,我是 GSAP 的新手,所以请多多包涵。我尽力描述我正在努力解决的问题。
为了制作 SVG 文件的动画,我开始深入研究 GSAP。我为我的 SVG 文件中的不同元素创建了几个 Tweens。 一切正常,动画效果符合预期。
由于我的 SVG 中有很多元素要制作动画,因此我开始添加 TimelineLite 以更好地控制整个事情。
此时,我的脚本文件如下所示:
首先我声明了我想要动画的所有元素:
this.phone = document.querySelector('#gsap-phone-svg');
this.body = document.querySelectorAll('.gsap-phone-body');
this.body.shadow = this.phone.querySelectorAll('.gsap-phone-body-shadow');
this.body.mask = this.phone.querySelectorAll('.gsap-phone-body-mask');
this.layer = this.phone.querySelectorAll('.gsap-phone-layer');
this.screen = this.phone.querySelectorAll('.gsap-phone-screen');
this.screen.clipPath = this.phone.querySelectorAll('.gsap-phone-screen-clipPath');
.
.
.
// many more following here
比我创建了一个对象来保存我的补间:
const tweens = {};
// creating tweens
tweens.body = TweenMax.to(this.body, this.animDur/2,{
y: this.maxExpand/6*-1,
ease: this.ease
});
.
.
.
// many more following here
最后,我将所有补间添加到一个临时数组中,然后像这样将它传递到一个新的 TimelineLite() 中:
const tl = new TimelineLite();
tl.add(tweensArray, 0, "start", 0.05);
到目前为止,我猜这似乎是合乎逻辑的......现在是症结所在。您可能已经注意到或没有注意到我喜欢 20 多个元素来制作动画。这就是为什么为每个元素单独添加补间变得非常混乱。我也希望整个主要时间线是重复的。这里的问题是,我希望我的所有补间在“动画内”和“动画外”上都有不同的缓动,并且我希望在“动画外”上没有交错。
所有这些小问题让我想到了一种替代解决方案来管理我的补间和时间线的创建。
我想到的最方便的解决方案是将有关我的动画元素和时间线的所有信息存储在一个对象中:
const animation = {
settings : {
duration: 1.5,
expansion: 1,
easeIn: Elastic.easeOut.config(1, 0.5),
easeOut: Power2.easeInOut
},
timelines : {
main : {
delay : 0,
paused : true,
align : 'start',
stagger : 0.05,
},
test : {
delay: 0,
paused : true,
align : 'start',
stagger : 0.5
}
},
items : {
phone : {
id : '#gsap-phone-svg',
start : { },
end : { },
timeline : 'test',
},
body : {
class : '.gsap-phone-body',
start : {
y : 0,
},
end : {
y : -21,
},
timeline : 'test',
},
layer : {
class : '.gsap-phone-layer',
start : {
y : 0,
},
end : {
y : -62.5,
},
timeline : 'main',
},
radar : {
class : '.gsap-phone-radar',
start : {
y : 0,
},
end : {
y : -25,
},
timeline : 'main',
},
radarBase : {
class : '.gsap-phone-radar-base',
start: {
y : 0,
},
end : {
y: -16,
},
timeline : 'test',
},
ringOne : {
class : '.gsap-phone-radar-ring-1',
start : {
y : 0,
},
end : {
y: -25,
},
timeline : 'test',
},
ringTwo : {
class : '.gsap-phone-radar-ring-2',
start : {
y : 0,
},
end : {
y: -41,
},
timeline : 'main',
},
ringThree : {
class : '.gsap-phone-radar-ring-3',
start : {
y : 0,
},
end : {
y: -62.5,
},
timeline : 'main',
},
cancel : {
class : '.gsap-phone-cancel',
start : {
y : 0,
},
end : {
y: -50,
},
timeline : 'main',
},
submit : {
class : '.gsap-phone-submit',
start : {
y : 0,
},
end : {
y: -100,
},
timeline : 'main',
}
}
};
我写了这个“createTweens”方法来返回 GSAP Tweens
/* create tweens */
function createTweens(anim){
const el = anim.items;
const settings = anim.settings;
const duration = settings.duration;
const easeIn = settings.easeIn;
const easeOut = settings.easeOut;
const tweensIn = [];
const tweensOut = [];
let tempTween = null;
for (const key in el){
const curEl = el[key];
const selector = curEl.class || el[key].id;
const startPoint = curEl.start || '';
const endPoint = curEl.end || '';
const timeline = curEl.timeline || '';
const nodes = document.querySelectorAll(selector);
nodes.forEach(object => {
tweensIn.push(getTween(object, endPoint, duration, easeIn, `${timeline}-in`));
tweensOut.push(getTween(object, startPoint, duration, easeOut, `${timeline}-out`));
});
}
function getTween(tw, twValues, twDur, twEase, tl){
const vars = twValues;
vars.paused = false;
vars.ease = twEase;
tempTween = TweenMax.to(tw, twDur/2, vars);
tempTween.data = {
timelineName : tl
};
return tempTween;
}
return tweensIn.concat(tweensOut);
}
还有一个返回时间线的函数:
/* create timelines */
function createTimelines(anim, tweens){
const el = anim.timelines;
const timelines = {};
// timelines.mainIn = new TimelineLite();
// timelines.mainOut = new TimelineLite();
const tweensForTimelines = {};
for(const key in el){
const delay = el[key].delay;
const paused = el[key].paused;
const align = el[key].align;
const stagger = el[key].stagger;
const vars = {};
vars.paused = paused;
timelines[`${key}-in`] = new TimelineLite(vars);
timelines[`${key}-in`].delay = delay;
timelines[`${key}-in`].align = align;
timelines[`${key}-in`].stagger = stagger;
timelines[`${key}-out`] = new TimelineLite(vars);
timelines[`${key}-out`].delay = delay;
timelines[`${key}-out`].align = align;
timelines[`${key}-out`].stagger = stagger;
tweensForTimelines[`${key}-in`] = [];
tweensForTimelines[`${key}-out`] = [];
}
if(Object.keys(tweensForTimelines).length !== 0){
for(let i = 0; i < tweens.length; i++){
const curTween = tweens[i];
const tlTarget = curTween.data.timelineName;
tweensForTimelines[tlTarget].push(curTween);
}
}
for(const key in timelines){
try{
timelines[key].add(tweensForTimelines[key], timelines[key].delay, timelines[key].align, timelines[key].stagger);
console.log(TweenMax.getTweensOf(timelines[key]));
timelines[key].data = tweensForTimelines[key];
} catch(e){
}
}
return timelines;
}
如果我执行以下代码,它将播放我的“主要”时间线。
const tweens = createTweens(animation);
const timelines = createTimelines(animation, tweens);
timelines['main-in'].play();
到目前为止,这确实有效。但是,如果我尝试将“main-in”时间线添加到新时间线,它就不再工作了。
const anotherTimeline = new TimelineLite();
anotherTimeline.add(timelines['main-in']);
anotherTimeline.play();
为了调试这个,我试过了
TweenMax.getTweensOf(anotherTimeline);
但是所有这些返回的是一个空数组。然后我为我的“主要”时间线记录了相同的内容:
console.log(TweenMax.getTweensOf(timelines['main-in']));
还返回一个空数组,这让我很困惑,因为即使这个时间线似乎是空的,它也会播放我的“动画”:
timelines['main-in'].play()
我真的被困在这里,非常感谢更高级的用户或任何对此有想法的人的帮助。我希望你们能够关注我......如果没有,看看提供的codepen..
提前致谢!
【问题讨论】:
标签: javascript animation svg gsap