2017-11-10 230 views
-1

所以我有這個類是用於形狀變形:與JavaScript(形狀變形)創建SVG路徑

class ShapeOverlays { 
    constructor(elm) { 
    this.elm = elm; 
    this.path = elm.querySelectorAll('path'); 
    this.numPoints = 18; 
    this.duration = 600; 
    this.delayPointsArray = []; 
    this.delayPointsMax = 300; 
    this.delayPerPath = 100; 
    this.timeStart = Date.now(); 
    this.isOpened = false; 
    this.isAnimating = false; 
    } 
    toggle() { 
    this.isAnimating = true; 
    const range = 4 * Math.random() + 6; 
    for (var i = 0; i < this.numPoints; i++) { 
     const radian = i/(this.numPoints - 1) * Math.PI; 
     this.delayPointsArray[i] = (Math.sin(-radian) + Math.sin(-radian * range) + 2)/4 * this.delayPointsMax; 
    } 
    if (this.isOpened === false) { 
     this.open(); 
    } else { 
     this.close(); 
    } 
    } 
    open() { 
    this.isOpened = true; 
    this.elm.classList.add('is-opened'); 
    this.timeStart = Date.now(); 
    this.renderLoop(); 
    } 
    close() { 
    this.isOpened = false; 
    this.elm.classList.remove('is-opened'); 
    this.timeStart = Date.now(); 
    this.renderLoop(); 
    } 
    updatePath(time) { 
    const points = []; 
    for (var i = 0; i < this.numPoints + 1; i++) { 
     points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0)/this.duration, 1)) * 100 
    } 

    let str = ''; 
    str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `; 
    for (var i = 0; i < this.numPoints - 1; i++) { 
     const p = (i + 1)/(this.numPoints - 1) * 100; 
     const cp = p - (1/(this.numPoints - 1) * 100)/2; 
     str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `; 
    } 
    str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`; 
    return str; 
    } 
    render() { 
    if (this.isOpened) { 
     for (var i = 0; i < this.path.length; i++) { 
     this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i))); 
     } 
    } else { 
     for (var i = 0; i < this.path.length; i++) { 
     this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1)))); 
     } 
    } 
    } 
    renderLoop() { 
    this.render(); 
    if (Date.now() - this.timeStart < this.duration + this.delayPerPath * (this.path.length - 1) + this.delayPointsMax) { 
     requestAnimationFrame(() => { 
     this.renderLoop(); 
     }); 
    } 
    else { 
     this.isAnimating = false; 
    } 
    } 
} 

(function() { 
    const elmHamburger = document.querySelector('.hamburger'); 
    const gNavItems = document.querySelectorAll('.global-menu__item'); 
    const elmOverlay = document.querySelector('.shape-overlays'); 
    const overlay = new ShapeOverlays(elmOverlay); 

    elmHamburger.addEventListener('click',() => { 
    if (overlay.isAnimating) { 
     return false; 
    } 
    overlay.toggle(); 
    if (overlay.isOpened === true) { 
     elmHamburger.classList.add('is-opened-navi'); 
     for (var i = 0; i < gNavItems.length; i++) { 
     gNavItems[i].classList.add('is-opened'); 
     } 
    } else { 
     elmHamburger.classList.remove('is-opened-navi'); 
     for (var i = 0; i < gNavItems.length; i++) { 
     gNavItems[i].classList.remove('is-opened'); 
     } 
    } 
    }); 
}()); 

能有人請解釋這個代碼?我真的不知道如何使用時間創建路徑,點的放置方式以及如何修改它。範圍用於什麼?爲什麼delayPointsArray使用三角函數?

基本上它的這一部分,我不明白:

updatePath(time) { 
     const points = []; 
     for (var i = 0; i < this.numPoints + 1; i++) { 
      points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0)/this.duration, 1)) * 100 
     } 

     let str = ''; 
     str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `; 
     for (var i = 0; i < this.numPoints - 1; i++) { 
      const p = (i + 1)/(this.numPoints - 1) * 100; 
      const cp = p - (1/(this.numPoints - 1) * 100)/2; 
      str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `; 
     } 
     str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`; 
     return str; 
     } 
     render() { 
     if (this.isOpened) { 
      for (var i = 0; i < this.path.length; i++) { 
      this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i))); 
      } 
     } else { 
      for (var i = 0; i < this.path.length; i++) { 
      this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1)))); 
      } 
     } 
     } 

爲什麼被使用的時間?什麼是這樣做的目的:

points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0)/this.duration, 1)) * 100 
+1

這是一個動畫。難道你不希望它被驅逐的時間? –

+0

是的,我知道我明白這一點,但時間與點位置相對應。我對這一切都相當陌生。你有什麼辦法可以更深入地解釋一下?我確實看到你在這方面經驗很豐富...... –

+0

這個問題是否有任何理由被標記爲'd'編程語言? – Eljay

回答

1

如果你看一下updatePath()是如何被調用時,它是這樣的:

this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)) 

所以在通過time值是當前時間之間的差異,以及我們正在使用的路徑的開始時間。

那麼你感興趣的代碼行是什麼呢?

points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0)/this.duration, 1)) * 100 

我打算忽略。它會根據角度稍微修改開始時間。沒有看到完整的演示,我不確定這個原因。

這段代碼的目的是計算我們當前路徑的動畫有多遠。結果是以0到100的座標值的形式。

它在這一行代碼中做了很多工作。所以我們來分解一下各個步驟。

  1. 首先,我們夾緊經過time最低的0

    Math.max(time, 0) 
    

    換句話說,動畫前的任何時間開始變爲零。

  2. 然後我們除以動畫的持續時間。

    Math.max(time, 0)/duration 
    

    這將導致其值從0,表示動畫的開始時,爲1時,表示該動畫的結束。但是,如果經過時間在動畫結束之後,該值也可能大於1。因此下一步。

  3. 現在夾緊該值到最大值的1

    Math.min(Math.max(time, 0)/duration, 1) 
    

    我們現在具有值> = 0和< = 1 whichdescribes其中在動畫的過程中,該路徑應該是。 0如果我們應該在動畫開始位置。 1如果我們應該在動畫結束位置。如果動畫正在進行中,則介於兩者之間。

  4. 然而,這個值是嚴格線性的,與時間的進展相對應。通常線性運動不是你想要的。這是不自然的。對象在開始移動時加速並在停止時減速。這將是easeInOut()函數將要做的事情。如果您不熟悉緩動曲線,請看下面的圖表。

    Ease In Out timing curve

    來源:Google: The Basics of Easing

    因此,我們在一個線性時間值傳遞從0..1(水平軸)。它會返回一個考慮加速和減速的修改值。

  5. 最後一步是乘以100,轉換爲最終座標值(0..100)。

希望這會有所幫助。

+0

謝謝你sooo !!!! –