species-in-pieces網站動效的JS完成

難度係數:平常

關鍵詞:GSAP SVG

媒介

看到species網站做的很炫,想要自創,發明主如果用css3的clip-path完成的,兼容不好,因而想着用js完成下。下面作簡樸引見,須要細緻代碼見github庫

基礎知識

  1. SVG基礎知識,重點viewBox,polygon;
  2. GSAP動畫平台,重點TimelineMax,TweenMax;
  3. parcel構建東西的基礎運用,parcel

完成思緒

依據參考網站的代碼,動物圖案是用clip-path: polygon()完成的,第一時間想到了SVG的polygon;別的關於轉場動畫,過渡動畫,找個本身熟習的動畫庫完成就好了。須要迥殊申明的是:

  1. css的clip-path用的用的百分比數值,svg的polygon的points值不能用百分比數值,曉得viewBox觀點的應當清晰,實在points的值也不是平常以為的相對像素值,因而寫了個東西函數parsePolygonStr
  2. 由於圖案是分動物和場景(樹枝,石優等)兩部分,而且願望先繪製動物再繪製場景,因而HTML部分用g標籤分紅extraanis

重要的代碼以下:

進口文件HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>species</title>
</head>

<body>
    <div id="wrap">
        <svg class="stage" viewBox="0 0 1000 700" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <g id="extra">
                <polygon points="793.50,476.88,949.50,500.88,805.50,518.88" fill="hsla(0, 0%, 100%, 0)"></polygon>
                <polygon points="793.50,476.88,949.50,500.88,805.50,518.88" fill="hsla(0, 0%, 100%, 0)"></polygon>
                <polygon points="793.50,476.88,949.50,500.88,805.50,518.88" fill="hsla(0, 0%, 100%, 0)"></polygon>
            </g>
            <g id="anis">
                
            </g>
        </svg>
        <button id="go_btn">GO!</button>
        <h1 class="name"></h1>
        <h2 class="desc"></h2>
    </div>
    <script src="./index.js"></script>
</body>

</html>

重要js劇本

// 導入一個 SCSS module
import '../css/main.scss';

import { data, preData } from './data'

import { TweenMax, TweenLite, TimelineMax } from 'gsap'

// NodeList轉換Array
function NodeList2Array(nodelist) {
    let arr = [];
    if (nodelist.length) {
        arr = Array.prototype.slice.call(nodelist, 0);
    }
    return arr;
}
// 把'clip-path'值轉成svg polygon可用的值
function parsePolygonStr(polygonStr, width, height) {
    let pointsArr = polygonStr.split(/\s+|,\s/);
    let newPointArr = pointsArr.map(function(currentVal, index, arr) {
        if (index % 2 === 0) {
            return (parseFloat(currentVal) * width / 100).toFixed(2);
        } else {
            return (parseFloat(currentVal) * height / 100).toFixed(2);
        }
    });

    return newPointArr;
}



let body = document.querySelector('body'),
    wrap = document.querySelector('#wrap'),
    name = wrap.querySelector('.name'),
    desc = wrap.querySelector('.desc'),
    stage = wrap.querySelector('.stage'),
    anis = document.querySelector('#anis'),
    extra = document.querySelector('#extra'),
    goBtn = document.querySelector('#go_btn'),
    anisPolygons = null,
    extraPolygons = null;


let currentSpeciesIndex = 0,
    width = 1000,
    height = 700;


function init() {
    let initSpecies = preData.preload;
    name.innerHTML = initSpecies.name;
    desc.innerHTML = initSpecies.desc;
    body.style.background = initSpecies.background;

    let polygonArr = initSpecies.polygon;

    if (Object.prototype.toString.call(polygonArr) === '[object Array]') {
        let polygonHtml = '';

        polygonArr.forEach(function(element, index) {
            let pointsVal = parsePolygonStr(element[0], width, height);
            polygonHtml += '<polygon points="' + pointsVal + '" fill="' + element[1] + '"/>';
        });
        anis.innerHTML = polygonHtml;

    }
}
init();
anisPolygons = anis.querySelectorAll('polygon');
extraPolygons = extra.querySelectorAll('polygon');

let tl = new TimelineMax({ delay: 0.2 });
// 初始的loading動畫
NodeList2Array(anisPolygons).forEach(function(target, index) {
    let tm = TweenMax.fromTo(target, 0.9, { attr: { fill: 'rgba(0, 0, 0, .7)' } }, { attr: { fill: 'rgba(200, 20, 20, .45)' }, ease: Power0.easeNone, repeat: -1, yoyo: true });
    tl.add(tm, 0.9 - 0.03 * index);
})

// 模仿加載完成
setTimeout(function() {
    // 消滅tl
    tl.clear();
    // loading完以後的一系列動畫
    // 1,變色,放大,爆炸碎片
    tl.add(
            [
                TweenMax.to('#anis polygon', .6, {
                    attr: {
                        fill: function(index) {
                            let fillVal = '#111';
                            if (index % 5 === 0) {
                                fillVal = '#28282a';
                            } else if (index % 5 === 1) {
                                fillVal = '#111';
                            } else if (index % 5 === 2) {
                                fillVal = '#333';
                            } else if (index % 5 === 3) {
                                fillVal = '#222';
                            } else if (index % 5 === 4) {
                                fillVal = '#121212';
                            }
                            return fillVal;
                        }
                    }
                }),
                TweenMax.to('#wrap .stage', .6, {
                    scale: 1,
                    ease: Back.easeOut.config(1.7)
                }),
                TweenMax.to('#anis polygon', .6, {

                    attr: {
                        points: function(index, target) {
                            let nextSpeciesPolygon = preData.ready.polygon;
                            // debugger
                            return parsePolygonStr(nextSpeciesPolygon[index][0], width, height)
                        },
                        fill: function(index, target) {
                            let nextSpeciesPolygon = preData.ready.polygon;
                            return nextSpeciesPolygon[index][1];
                        },
                    }
                    // ease: Power2.easeInOut,

                })
            ]
        )
        // 2,海豚
        .add(
            TweenLite.to('#anis polygon', .6, {

                attr: {
                    points: function(index, target) {
                        let nextSpeciesPolygon = preData.preAni.polygon;
                        return parsePolygonStr(nextSpeciesPolygon[index][0], width, height)
                    },
                    fill: function(index, target) {
                        let nextSpeciesPolygon = preData.preAni.polygon;
                        return nextSpeciesPolygon[index][1];
                    },
                },
                // ease: Power2.easeInOut,
            })
        )
        // 3,爆炸碎片
        .add(
            TweenMax.to('#anis polygon', .6, {

                attr: {
                    points: function(index, target) {
                        let nextSpeciesPolygon = preData.ready.polygon;
                        // debugger
                        return parsePolygonStr(nextSpeciesPolygon[index][0], width, height)
                    },
                    fill: function(index, target) {
                        let nextSpeciesPolygon = preData.ready.polygon;
                        return nextSpeciesPolygon[index][1];
                    },
                }
            }),
            '+=0.4'
        )
        // 4,“piece”logo
        .add(
            TweenMax.to('#anis polygon', .6, {

                attr: {
                    points: function(index, target) {
                        let nextSpeciesPolygon = preData.title.polygon;
                        // debugger
                        return parsePolygonStr(nextSpeciesPolygon[index][0], width, height)
                    },
                    fill: function(index, target) {
                        let nextSpeciesPolygon = preData.title.polygon;
                        return nextSpeciesPolygon[index][1];
                    },
                }
            }),
            '+=0.4'
        );

}, 3000);



// 動物圖案切換
function playHandler() {
    let nextSpecies = data[currentSpeciesIndex++];
    if (!nextSpecies) {
        return false;
    }

    name.innerHTML = nextSpecies.name;
    desc.innerHTML = nextSpecies.desc;
    body.style.background = nextSpecies.background;

    let nextSpeciesPolygon = nextSpecies.polygon;

    let subTl = new TimelineMax({ pause: true });

    let arr1 = NodeList2Array(anisPolygons);
    let arr2 = NodeList2Array(extraPolygons);

    // 之所以沒用TweenMax.staggerTo是由於屬性對象中沒法用取得index,以下完成不了
    // attr: {
    //     points: pointVal.join(' '),
    //     fill: function(index){return nextSpeciesPolygon[index][1];}
    // }

    arr1.concat(arr2).forEach(function(target, index) {
        let pointVal = parsePolygonStr(nextSpeciesPolygon[index][0], width, height),
            fillVal = nextSpeciesPolygon[index][1];
        subTl.add(
            TweenMax.to(target, 0.5, {
                attr: {
                    points: pointVal.join(' '),
                    fill: fillVal
                },
                ease: Back.easeOut.config(1.7)
            }),
            '-=0.47'
        )
    });

    subTl.play();


}

goBtn.addEventListener('click', playHandler, false);


export default () => {

};
    原文作者:正月初五
    原文地址: https://segmentfault.com/a/1190000014439308
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞