• 【CodePen】SVG多邊形動畫教程(翻譯)

    分類:文檔教程
    原文:Animating SVG polygons - Nat
    翻譯:SVG多邊形動畫教程(翻譯) - xh_loop
    ps:如發現有翻譯錯誤,歡迎在下方評論區指出,謝謝 :)

    導語

    我收到了很多關于 我是如何制作 "animating svg polygon points" 的疑問,所以我決定寫一個小教程。我制作這個Pen是為了試著重新實現這個網站 facesofpower.net 的效果。

    免責聲明

    我不知道我做的是否是最佳的或者最優的方式,所以如果有人有任何建議或批評,請讓我知道!

    內容清單

    1. Tools
    2. 邏輯概述
    3. HTML & SCSS
    4. Javascript
    5. 資源

    Tools

    • 我使用了 primitive, 它能將圖片轉換為SVG。
      終端命令我使用的是 primitive -i input.jpg -o output.svg -n 250 -m 1。
      這個 -n 250 指定了 250 個多邊形, -m 1 指定了三角形, 然后 -i input.jpg -o output.svg 是輸入和輸出。

    為這個特定的例子指定三角形是很重要的,因為這將影響多邊形的各個points屬性如何展現。如果你指定了一個不同的形狀,你必須更新getCoordinates function中的正則表達式,并相應地改變animatePolygons function中的setAttribute方法

    • 動畫效果的制作使用了 TweenMax。

    邏輯概述

    我們將為每個多邊形的points屬性添加動畫。我們需要2個數組來做這個動畫:一個是我們變化目標的值集合,一個是我們變化之前的值集合。變化之前的數組從它展現到頁面上開始,將一直擁有一個svg-holder的class。

    每當一個鏈接被點擊:

    1. 根據被點擊的元素的href的值去尋找id為該值的svg。
    2. 獲取該svg中多邊形的每個points屬性的值,將他們放入一個object,并將這個object加入to數組。
    3. Animate the from values to the to values.
    4. After animation, set the from array to the to array.

    HTML & SCSS

    在創建了SVG之后,將他們粘貼到HTML的body中。復制第一個SVG,并給它添加class svg-holder。這個 svg-holder 將成為唯一一個真正的可見區域,并且所有被移動的多邊形將在這里進和出。

    給除了可見區域 以外的SVG都添加一個class hidden 和一個唯一的id。這個id必須和鏈接的href值統一。這些 hidden 將用display: none;隱藏。

    很重要的一點是,確保每個鏈接的href和他們各自對應的svg的id值統一吻合:

    <a href="#nat">Nat</a>
    <a href="#bwl">bwl</a>
    <a href="#kevin">kevin</a>
    
    <svg class="svg-holder">
      polygons for #nat go here
    </svg>
    <svg id="nat" class="hidden">
     polygons for #nat go here
    </svg>
    <svg id="bwl" class="hidden">
     polygons for #bwl go here
    </svg>
    <svg id="kevin" class="hidden">
     polygons for #kevin go here
    </svg>
    

    這里同樣需要一些樣式。這將規定當前這個點如何展現:

    Javascript

    Variables

    首先,讓我們聲明我們的變量。

    let toPolygonArray = [];
    let fromPolygonArray = [];
    const links = document.querySelectorAll("a");
    

    這里的重點是開頭的兩個數組。 他們被使用 let 聲明,因為這些數組不會擁有一個常量值。toPolygonArray會保存我們將要變化的目標多邊形,fromPolygonArray會保存變化之前的多邊形。

    那些鏈接上將會有一個點擊事件監聽,以此來觸發動畫效果。

    Functions

    Click Event Listene(點擊事件監聽)

    [].forEach.call(links, function(el, i, els) {
        el.addEventListener("click", function(event) {
            const idToAnimateTo = this.getAttribute("href").substring(1);
    
            [].forEach.call(els, function(el) {
                if (el !== this) {
                    el.classList.remove("active");
                } else {
                    this.classList.add("active");
                }
            }, this);
    
            event.preventDefault();
            this.classList.add("active");
            updatePolygonArrays(idToAnimateTo);
        });
    });
    

    每當一個鏈接被點擊,這個函數就會取得其 href 并將它賦值給 idToAnimateTo 變量:

    const idToAnimateTo = this.getAttribute("href").substring(1);
    

    然后調用updatePolygonArrays函數,idToAnimateTo作為參數傳入。

    updatePolygonArrays(idToAnimateTo);
    

    點擊事件監聽還會設置一個激活狀態的class到當前鏈接上,以此來讓這個激活的鏈接擁有不同的樣式。

    getCoordinates

    const getCoordinates = (polygon) => {
      return polygon.getAttribute("points").match(/(-?[0-9][0-9\.]*),(-?[0-9][0-9\.]*)\ (-?[0-9][0-9\.]*),(-?[0-9][0-9\.]*)\ (-?[0-9][0-9\.]*),(-?[0-9][0-9\.]*)/);
    };
    

    這個函數傳入一個 polygon 元素,返回一個包含points屬性的所有數字的數組

    這個函數根據points屬性的設置可以不同。在我的示例中,每個points擁有相同的精確設置:6個被逗號或空格分割的數字。這6個數字是三角形的x,y坐標。

    <polygon fill="#ffffff" points="-16,-16 32,69 271,7" />
    

    這個函數使用了正則表達式來尋找每個數字。這個正則表達式能被修改,例如你想變化一個 path 的d屬性。

    在上面這個例子中,path 的內容如下:

    <path d="M46,282L28,228L62,184Z" fill="rgb(7, 7, 7)" fill-opacity="0.66"/>
    

    d屬性相應的正則表達式應該如下:

    path.getAttribute("d").match(/M(-?[0-9][0-9]*),(-?[0-9][0-9]*)L(-?[0-9][0-9]*),(-?[0-9][0-9]*)L(-?[0-9][0-9]*),(-?[0-9][0-9]*)Z/);
    

    createPolygonPointsObject

    const createPolygonPointsObject = (polygons) => {
      const polygonsArray = [];
    
      polygons.forEach((polygon, i) => {
        const coordinates = getCoordinates(polygon);
    
        polygonsArray.push({
          fill: polygon.getAttribute("fill"),
          one: coordinates[1],
          two: coordinates[2],
          three: coordinates[3],
          four: coordinates[4],
          five: coordinates[5],
          six: coordinates[6]
        });
      });
    
      return polygonsArray;
    }
    

    這個函數將 polygons 作為參數傳入,返回包含每個多邊形的fill和points屬性的object數組

    創建一個空的數組:

    const polygonsArray = [];
    

    獲取參數(儲存多邊形的一個數組),并且為數組中的每個項 調用 getCoordinates 函數

    polygons.forEach((polygon, i) => {
       const coordinates = getCoordinates(polygon);
    });	
    

    這設置coordinatespoints里的一個數字數組

    在同一個forEach中,將points的值和每個多邊形的fill屬性push到polygonsArray里。這些值將被作為object存入,以此來簡化發生動畫時對他們的處理。

    所以現在 polygonsArray 是一個object對象數組,每個object指向一個多邊形并且擁有7個屬性:fill屬性和points屬性的6個數字。所以舉例來說,要獲取第三個多邊形的fill屬性,你只需要寫 polygonsArray[2].fill。要獲取第三個多邊形的points屬性的第一個數字,你只需要寫polygonsArray[2].one。

    polygons.forEach((polygon, i) => {
      const coordinates = getCoordinates(polygon);
    
        polygonsArray.push({
          fill: polygon.getAttribute("fill"),
          one: coordinates[1],
          two: coordinates[2],
          three: coordinates[3],
          four: coordinates[4],
          five: coordinates[5],
          six: coordinates[6]
      });
    });
    

    返回數組。

    return polygonsArray;
    

    updatePolygonArrays

    const updatePolygonArrays = (idToAnimateTo) => {
      toPolygonArray = createPolygonPointsObject(document.getElementById(idToAnimateTo).querySelectorAll("polygon"));
    
      animatePolygons();
    
      fromPolygonArray = toPolygonArray;
    }
    

    這是那個在點擊監聽事件中被調用的函數。

    idToAnimateTo 是那個被點擊的鏈接的href值。所以這個函數尋找一個id和href值吻合的svg。它獲取該svg中的所有多邊形,把他們傳入createPolygonPointsObject運行,并設置到toPolygonArray。

    所以現在,獲取我們將要變化的第三個多邊形的fill值,也就是toPolygonArray[2].fill。

    然后,調用animatePolygons。

    變化之后,fromPolygonArray會被更新,來獲得上個周期的toPolygonArray的值。

    animatePolygons

    const animatePolygons = () => {
      const polygons = document.querySelector(".svg-holder").querySelectorAll("polygon");
      fromPolygonArray = createPolygonPointsObject(polygons);
    
      fromPolygonArray.forEach((obj, i) => {
        TweenMax.to(obj, 1, {
          one: toPolygonArray[i].one,
          two: toPolygonArray[i].two,
          three: toPolygonArray[i].three,
          four: toPolygonArray[i].four,
          five: toPolygonArray[i].five,
          six: toPolygonArray[i].six,
          ease: Power3.easeOut,
          onUpdate: () => {
            polygons[i].setAttribute("points", `${obj.one},${obj.two} ${obj.three},${obj.four} ${obj.five},${obj.six}`);
          }
        });
      });
    
      // animate color
      polygons.forEach((polygon, i) => {
        const toColor = toPolygonArray[i].fill;
    
        TweenLite.to(polygon, 1, {
          fill: toColor,
          ease: Power3.easeOut
        });
      });
    }
    

    獲取當前svg-holder的多邊形。這是當前可見的SVG,并且是我們將要變化的多邊形。

    const polygons = document.querySelector(".svg-holder").querySelectorAll("polygon");
    

    將這些多邊形傳入createPolygonPointsObject運行,并且將他們放入from數組。

    fromPolygonArray = createPolygonPointsObject(polygons);
    

    變化多邊形的位置/尺寸。

    fromPolygonArray.forEach((obj, i) => {
       TweenMax.to(obj, 1, {
          one: toPolygonArray[i].one,
          two: toPolygonArray[i].two,
          three: toPolygonArray[i].three,
          four: toPolygonArray[i].four,
          five: toPolygonArray[i].five,
          six: toPolygonArray[i].six,
          })
       });
    

    from數組中的值放入to中,替代原來的值。

    onUpdate: () => {
     polygons[i].setAttribute("points", `${obj.one},${obj.two} ${obj.three},${obj.four} ${obj.five},${obj.six}`);
    }
    

    在每次動畫中,設置新的值到當前可見的多邊形(.svg-holder)的points屬性。TweenMaX中的onUpdate方法在每一次動畫更新時都被調用,所以在這執行obj.one, obj.two,obj.three等值的每次變化。所以我們正在設置obj.onetoPolygonArray[i].onepoints屬性的每個屬性。這就是從變化屬性開始后,動畫發生的最基本所在。

    Animate Polygon fill

    每個.svg-holder中的多邊形,設置他的fill到toPolygonArray中的相同索引值的fill

    polygons.forEach((polygon, i) => {
        const toColor = toPolygonArray[i].fill;
    
        TweenLite.to(polygon, 1, {
          fill: toColor,
          ease: Power3.easeOut
        });
      });
    

    資源

    1. Regex
    2. SVG polygons
    3. TweenMax.to

    2017-02-06 16:53 - xh_loop 3772

    非特殊說明,本文版權歸原作者所有,轉載請注明出處

    推薦閱讀

    ? 105彩票官网 kg9| ssw| u9w| qco| 0gw| qe8| ue8| gak| k8s| sue| 8qm| mo8| gua| kk9| ckg| q9y| ayu| 7ck| ck7| ce7| iie| q7i| oea| 8ic| ya8| kku| k8y| ukk| 8wg| qe6| mwi| u7e| o7u| acy| 7ak| gg7| uuq| c7m| gus| 7sq| km6| yys| kg6| kmy| i6s| c6s| sqm| 6qi| gi6| aak| g7y| oou| 7wo| my5| owa| y5y| egw| 5ay| kwm| cq6| ggm| m6i| weg| 6se| yy4| ukq| w4a| csy| 4qk| eg5| 5ye| mau| uq5| ggo| y5s| qgq| 3ya| yy3| sok| c4y| uuw| 4io| ge4| kku| u4c| m4o| ywq| 4ke| ee3| qqm|