2016-11-07 81 views
0

第一件事是第一件事,我是GSAP的新手,請耐心等待。我試着盡我所能描述我正在努力的。GSAP:一次管理多個補間和時間線

爲了創建一個SVG文件的動畫,我開始潛入GSAP。我爲SVG文件中的不同元素創建了幾個補間。 一切工作正常,並按預期動畫。

由於我在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吐溫

/* 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(); 

到目前爲止,這實際上是工作。但是,如果我嘗試將「主入」時間線添加到新時間線,則不再有效。

const anotherTimeline = new TimelineLite(); 
anotherTimeline.add(timelines['main-in']); 
anotherTimeline.play(); 

爲了調試這一點,我想

TweenMax.getTweensOf(anotherTimeline); 

但所有這返回的是一個空數組。然後我登錄同爲我的「主在」時間線:

console.log(TweenMax.getTweensOf(timelines['main-in'])); 

也返回一個空Array,這是非常令人困惑的我,因爲即使這個時間表似乎是空的,它扮演着我「,在動畫「上:

timelines['main-in'].play() 

我真的堅持在這裏,真的希望從更高級的用戶提供一些幫助,或者乾脆的人誰擁有了這個想法。我希望你們能跟隨我......萬一不是,看看提供的codepen ..

UPDATE:提前Click for Codepen DEMO

謝謝!

回答

1

我沒有時間解析所有的代碼並製作完整的替代品,但它確實讓我有點過度設計,但我也意識到我的大腦可能只是以不同的方式工作,這是一種風格選擇(不好或壞)。

我發現最直觀,最具可讀性和靈活性的方法是將動畫分成多個塊,每個塊中放入一個可以嵌套在主時間軸中的TimelineLite/Max或TweenLite/Max函數如果你這麼選擇)。

有點像:

function phoneIntro() { 
    var tl = new TimelineLite(); 
    tl.to(...) 
     .to(...); 
    return tl; 
} 

function flipPhone() { 
    var tl = new TimelineLite(); 
    tl.to(...); 
    return tl; 
} 

var master = new TimelineMax({repeat:-1}); 
master.add(phoneIntro(), 0) 
     .add(flipPhone(), "-=1"); //overlap by 1 second 
     ... 

,當然如果你有很多,你在做同種動畫的元素,這種模塊化的方法是非常有用的,因爲你可以在飼料無論您需要哪些變量來爲您工作,並吐出動畫。

function buildStep(element, duration, x, y) { 
    return TweenMax.to(element, duration, {x:x, y:y, rotation:30}); 
} 

希望它越來越清楚如何靈活,當你創建一些模塊化的功能,你只給你需要一些力所能及的事情就可以了。這整個方法可以使編輯動畫的速度更快(並且可以測試時間等),因爲它很容易在代碼中找到你的位置。 「我想讓介紹再延長2秒......」只需找到phoneIntro()函數並調整其中的內容即可。完成。由於您在主TimelineMax中將相關時間串在一起,因此對第一個模塊化塊進行的更改會自動推回後續事件的時間,並且流暢地流過。不要弄亂20個不同的延遲。

此外,TweenLite.getTweensOf(anotherTimeline)返回空數組的原因是因爲該方法找到該對象的補間。就像,從字面上看,如果你補間時間表本身(也許是它的進步),它會返回這個補間。這聽起來像你認爲它得到了一些時間軸實例的補間INSIDE(它沒有)。不過,如果這就是你所追求的,那就像anotherTimeline.getChildren()一樣簡單。

我希望至少有一點幫助。歡迎在http://greensock.com/forums的論壇上發佈問題,那裏有一個GSAP專業人士的偉大社區。這是一個神話般的地方學習,即使你永遠不會發布問題:)

快樂補間!

+0

非常感謝您的詳細解答。你可能正確的事實是我可能在這裏過度設計一些; D。我已經達成了將所有事情分割多一點的條款,並且只有函數返回補間或時間軸。 我也在Greensock論壇發佈了這篇文章,但還沒有得到任何答覆,這就是爲什麼我在這裏發佈它; D。 –

+0

順便說一下,即使這個問題可能與svg更相關,但在製作當前動畫時遇到了另一個問題,我在另一個主題中發佈了這些動畫。 http://stackoverflow.com/questions/40482500/svg-issue-with-multiple-masks-in-different-svg檢查出來,如果你喜歡,也許你有這個:)的答案。 –

+0

是的,不幸的是,在各種瀏覽器中,隱藏在SVG中(尤其是動畫)掩蓋了(與GSAP完全無關)。在上面添加一個過濾器,你要求麻煩:)我希望我有一個簡單的解決方案。 – Jack