PixiJS + TweenMax 制作時(shí)間軸H5(一鏡到底)

參考效果:

一部40年的生活演變史
網(wǎng)易往踢,逃不掉的四字魔咒(手機(jī)預(yù)覽)

參考資料:

PixiJS官方手冊(cè)
PixiJS教程通俗易懂(日語(yǔ))
PixiJS教程通俗易懂(翻譯)
實(shí)戰(zhàn)教程(帶demo)
TweenMax官方手冊(cè)
(使用TwwenJS代替TweenMax也行)

PixiJS & TweenMax 的CDN

<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/TweenMax.min.js"> </script>
  • 基本的實(shí)現(xiàn)步驟
//1 掘殴、 以可視區(qū)域大小創(chuàng)建渲染器
var renderer = PIXI.autoDetectRenderer(window.innerWidth,window.innerHeight);
//2 盖矫、 將舞臺(tái)添加到,頁(yè)面中
document.body.appendChild(renderer.view);
//3 、 創(chuàng)建元素容器,類似 ‘組’概念猴伶,Container可以嵌套Container
var stageBox = new PIXI.Container();
/*
4 、
使用加載器預(yù)加載圖片塌西。& 監(jiān)聽(tīng)加載成功事件 ‘progress’ 多次觸發(fā) 他挎,target.progress 返回加載成功百分比
加載完成 觸發(fā)load 里面的 setup函數(shù) 。 
*/
PIXI.loader.add([
   './img/test1.png'
]).on("progress", function(target, resource){
   console.log(~~target.progress);
}).load(setup);
function setup(){
  var test1= new PIXI.Sprite(//普通精靈
     PIXI.loader.resources["./img/test1.png"].texture
  );
  animate();
}
//以每秒60fps渲染
function animate(){
   renderer.render(stageBox);
   requestAnimationFrame(animate);
}

模仿【一部40年的生活演變史】

預(yù)覽地址

  • 其中js部分有很多可以封裝的地方捡需,自己沒(méi)有做封裝
  • 只做了部分效果(后半部分大同小異)
  • 設(shè)計(jì)稿在這里办桨,bg1.psd
  • 對(duì)應(yīng)設(shè)計(jì)稿還原場(chǎng)景
//根據(jù)設(shè)計(jì)稿 還原場(chǎng)景
  spriteBox.bg1.position.set(0,0);
  spriteBox.bg2.position.set(0,3000);
  spriteBox.bg3.position.set(0,3000*2);
  spriteBox.bg4.position.set(0,3000*3);
  spriteBox.bg5.position.set(0,3000*4);
  spriteBox.bd.position.set(270,967);
  ...
  • 設(shè)置場(chǎng)景中需要?jiǎng)赢?huà)的元素
//設(shè)置動(dòng)畫(huà)
  tm.to(stageBox,10,{y:-(stageBox.height-window.innerHeight),ease:Bounce.Linear},0);
  tm.to(spriteBox.bd,0.3,{y:spriteBox.bd.y+50,ease:Bounce.Linear},0.05);
  tm.to(spriteBox.text1.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.00);
  ...
  • 里面有很多地方用到了幀動(dòng)畫(huà),使用pixijs 的 AnimatedSprite(動(dòng)畫(huà)精靈)實(shí)現(xiàn)
  var cj_arr = [];
  for(let i=1;i<5;i++){
    cj_arr.push('./images/cj'+i+'.png')
  }
  spriteBox.cj = new PIXI.extras.AnimatedSprite.fromImages(cj_arr);
  spriteBox.cj.animationSpeed = -0.08;
  spriteBox.cj.play();
  • 其中用到了倆個(gè)時(shí)間軸,因?yàn)檎w動(dòng)畫(huà)中存在循環(huán)播放的動(dòng)畫(huà)(按鈕放大縮小效果)站辉。一個(gè)時(shí)間軸控制播放到不同時(shí)間播放不同的動(dòng)畫(huà)呢撞,另一個(gè)時(shí)間軸控制循環(huán)動(dòng)畫(huà)(按鈕縮放動(dòng)畫(huà))


    image.png
  var tm = new TimelineLite({paused:true});
  var tm2 = new TimelineLite();
  • range() 函數(shù)判斷 在不同時(shí)間 播放不同的背景聲音以及幀動(dòng)畫(huà)的跳轉(zhuǎn)暫停损姜。
  document.querySelector('#music0').play();
  spriteBox.bd.gotoAndStop(timeline/60);
  • 場(chǎng)景滑動(dòng)緩動(dòng)事件,以及緩動(dòng)效果殊霞。
        document.addEventListener('touchstart',function(e){
            clearInterval(setTime);
            touchstart = true;
            touchstartY = e.changedTouches[0].clientY;
        });
       document.addEventListener('touchmove',function(e){
            if(!touchstart){return;}

            var touchmoveY = e.changedTouches[0].clientY;
            steptime = -(touchmoveY-touchstartY)/1000;
            var time = timeline+=steptime;

            if(time < 0) timeline = 0;
            if(time >= 10) timeline = 10;//這里的10是外層總?cè)萜鳎╯tageBox)的動(dòng)畫(huà)時(shí)長(zhǎng)
           
            range();
            tm.seek(timeline);//跳轉(zhuǎn)到對(duì)應(yīng)時(shí)間
            renderer.render(stageBox);//渲染場(chǎng)景
            touchstartY = touchmoveY;
        })
        document.addEventListener('touchend',function(){
            touchstart = false;
            setTime = setInterval(() => {

                steptime*=0.95;
                
                if(Math.abs(steptime)<1/1000){
                    clearInterval(setTime)
                }
               
                var time = timeline+=steptime;

                if(time < 0) timeline = 0;
                if(time >= 10) timeline = 10;
                
                range();
                tm.seek(timeline);
                renderer.render(stageBox);
            },10);
        })
<!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>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/TweenMax.min.js"> </script>

    <style>
        *{
            padding: 0;
            margin: 0;
        }
        html,body{width: 100%;height: 100%;overflow: hidden;}
    </style>
</head>
<body>
    <audio hidden="" id="music0" src="media/0.mp3" loop></audio>
    <audio hidden="" id="music1" src="media/wd.mp3" loop></audio>
    <audio hidden="" id="music2" src="media/1.mp3" loop></audio>
    <script>
        var type = "WebGL";
        if(!PIXI.utils.isWebGLSupported()){
            type = "canvas"
        }
        PIXI.utils.sayHello(type);

        var renderer = PIXI.autoDetectRenderer(window.innerWidth,window.innerHeight);
            document.body.appendChild(renderer.view);
        var draftWidth = 640,draftHeight = 14949;
        var stageBox = new PIXI.Container();
        var tm = new TimelineLite({paused:true});
        var tm2 = new TimelineLite();
        var spriteBox = {};
        PIXI.loader.add([
            './images/bg1.jpg',
            './images/bg2.jpg',
            './images/bg3.jpg',
            './images/bg4.jpg',
            './images/bg5.jpg',
            './images/bd1.png',
            './images/bd2.png',
            './images/cj1.png',
            './images/cj2.png',
            './images/cj3.png',
            './images/cj4.png',
            './images/lb1.png',
            './images/lb2.png',
            './images/lb3.png',
            './images/lb4.png',
            './images/text1.png',
            './images/text4.png',
            './images/tz.png',
            './images/rgm1.png',
            './images/rgm2.png',
            './images/rgm3.png',
            './images/rgm4.png',
            './images/rgm5.png',
            './images/pz.png',
            './images/btn.png',
            './images/tw1.png',
            './images/tw2.png',
            './images/tw3.png',
            './images/tw4.png',
            './images/tw5.png',
            ]).on("progress", function(target, resource){
                console.log(~~target.progress);
            }).load(setup);
        function setup(){ 
            spriteBox.bg1 = new PIXI.Sprite(PIXI.loader.resources['./images/bg1.jpg'].texture);
            spriteBox.bg2 = new PIXI.Sprite(PIXI.loader.resources['./images/bg2.jpg'].texture);
            spriteBox.bg3 = new PIXI.Sprite(PIXI.loader.resources['./images/bg3.jpg'].texture);
            spriteBox.bg4 = new PIXI.Sprite(PIXI.loader.resources['./images/bg4.jpg'].texture);
            spriteBox.bg5 = new PIXI.Sprite(PIXI.loader.resources['./images/bg5.jpg'].texture);
            var bd_arr = [];
            for(let i=1;i<3;i++){
                bd_arr.push('./images/bd'+i+'.png')
            }
            spriteBox.bd = new PIXI.extras.AnimatedSprite.fromImages(bd_arr);
            spriteBox.bd.animationSpeed = -0.05;//序列幀放映速度
            spriteBox.text1 = new PIXI.Sprite(PIXI.loader.resources['./images/text1.png'].texture);
            var cj_arr = [];
            for(let i=1;i<5;i++){
                cj_arr.push('./images/cj'+i+'.png')
            }
            spriteBox.cj = new PIXI.extras.AnimatedSprite.fromImages(cj_arr);
            spriteBox.cj.animationSpeed = -0.08;
            spriteBox.cj.play();
            var lb_arr = [];
            for(let i=1;i<5;i++){
                lb_arr.push('./images/lb'+i+'.png')
            }
            spriteBox.lb = new PIXI.extras.AnimatedSprite.fromImages(lb_arr);
            spriteBox.lb.animationSpeed = -0.08;
            spriteBox.lb.play();
            spriteBox.text4 = new PIXI.Sprite(PIXI.loader.resources['./images/text4.png'].texture);
            var rgm_arr = [];
            for(let i=1;i<=5;i++){
                rgm_arr.push('./images/rgm'+i+'.png')
            }
            spriteBox.rgm = new PIXI.extras.AnimatedSprite.fromImages(rgm_arr);
            spriteBox.rgm.animationSpeed = -0.065;
            spriteBox.rgm.play();
            spriteBox.tz = new PIXI.Sprite(PIXI.loader.resources['./images/tz.png'].texture);
            spriteBox.pz = new PIXI.Sprite(PIXI.loader.resources['./images/pz.png'].texture);
            var tw_arr = [];
            for(let i=1;i<=5;i++){
                tw_arr.push('./images/tw'+i+'.png')
            }
            spriteBox.tw = new PIXI.extras.AnimatedSprite.fromImages(tw_arr);
            spriteBox.tw.animationSpeed = -0.05;
            spriteBox.tw.play();
            spriteBox.btn1 = new PIXI.Sprite(PIXI.loader.resources['./images/btn.png'].texture);
            spriteBox.btn1.on('tap',function(){//綁定事件
                console.log('點(diǎn)擊');
            })
            //根據(jù)設(shè)計(jì)稿 還原場(chǎng)景
            spriteBox.bg1.position.set(0,0);
            spriteBox.bg2.position.set(0,3000);
            spriteBox.bg3.position.set(0,3000*2);
            spriteBox.bg4.position.set(0,3000*3);
            spriteBox.bg5.position.set(0,3000*4);
            spriteBox.bd.position.set(270,967);
            spriteBox.text1.position.set(332,993);
            spriteBox.text1.anchor.x = 0;
            spriteBox.text1.anchor.y = 1;
            spriteBox.text1.scale.set(0);
            spriteBox.lb.position.set(462,1522);
            spriteBox.cj.position.set(522,1530);
            spriteBox.text4.position.set(489,1524);
            spriteBox.text4.anchor.x = 1;
            spriteBox.text4.anchor.y = 1;
            spriteBox.text4.scale.set(0);
            spriteBox.rgm.position.set(438,2242);
            spriteBox.tz.position.set(419,2253);
            spriteBox.pz.position.set(0,2634);
            spriteBox.tw.position.set(430,2808);
            spriteBox.btn1.position.set(580,2766);
            spriteBox.btn1.scale.set(1);
            spriteBox.btn1.anchor.set(0.5,0.5);
            spriteBox.btn1.buttonMode = true;//按鈕模式 
            spriteBox.btn1.interactive = true;//啟用事件
            for(let key in spriteBox){
                stageBox.addChild(spriteBox[key]);//精靈 添加進(jìn) 容器
            }

            stageBox.scale.set(window.innerWidth/draftWidth);//容器根據(jù)設(shè)計(jì)稿 計(jì)算縮放
            
            //設(shè)置動(dòng)畫(huà)
            tm.to(stageBox,10,{y:-(stageBox.height-window.innerHeight),ease:Bounce.Linear},0);
            tm.to(spriteBox.bd,0.3,{y:spriteBox.bd.y+50,ease:Bounce.Linear},0.05);
            tm.to(spriteBox.text1.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.00);
            tm.to(spriteBox.text4.scale,0.15,{x:1,y:1,ease:Bounce.Linear},0.1);
            tm2.to(spriteBox.btn1.scale,1,{x:1.3,y:1.3,ease:Bounce.Linear,yoyo:true,repeat:-1},0);
            tm2.play();
            animate();
        }
        var touchstart = false,
            steptime=0,
            touchstartY = 0;
            timeline = 0
            setTime=null;
        document.addEventListener('touchstart',function(e){
            clearInterval(setTime);
            touchstart = true;
            touchstartY = e.changedTouches[0].clientY;
        });
        document.addEventListener('touchmove',function(e){
            if(!touchstart){return;}

            var touchmoveY = e.changedTouches[0].clientY;
            steptime = -(touchmoveY-touchstartY)/1000;
            var time = timeline+=steptime;

            if(time < 0) timeline = 0;
            if(time >= 10) timeline = 10;//這里的10是外層總?cè)萜鳎╯tageBox)的動(dòng)畫(huà)時(shí)長(zhǎng)
           
            range();
            tm.seek(timeline);//跳轉(zhuǎn)到對(duì)應(yīng)時(shí)間
            renderer.render(stageBox);//渲染場(chǎng)景
            touchstartY = touchmoveY;
        })
        document.addEventListener('touchend',function(){
            touchstart = false;
            setTime = setInterval(() => {

                steptime*=0.95;
                
                if(Math.abs(steptime)<1/1000){
                    clearInterval(setTime)
                }
               
                var time = timeline+=steptime;

                if(time < 0) timeline = 0;
                if(time >= 10) timeline = 10;
                
                range();
                tm.seek(timeline);
                renderer.render(stageBox);
            },10);
        })

       function range(){
            if(timeline >0.001 && timeline <= 0.313){
                document.querySelector('#music0').play();
                spriteBox.bd.gotoAndStop(timeline*14);
            }else{
                document.querySelector('#music0').pause();
                document.querySelector('#music0').currentTime=0;
            }
            if(timeline>0.413 && timeline<=0.670){
                document.querySelector('#music1').play();
            }else{
                document.querySelector('#music1').pause();
                document.querySelector('#music1').currentTime=0;
            }
            if(timeline>0.670 && timeline<=1.301){
                
                document.querySelector('#music2').play();
            }else{
                document.querySelector('#music2').pause();
                document.querySelector('#music2').currentTime=0;
            }
        }
        function animate(){
            renderer.render(stageBox);
            requestAnimationFrame(animate);
        }
    </script>
</body>
</html>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末摧阅,一起剝皮案震驚了整個(gè)濱河市脓鹃,隨后出現(xiàn)的幾起案子古沥,更是在濱河造成了極大的恐慌,老刑警劉巖岩齿,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盹沈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)乞封,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肃晚,“玉大人,你說(shuō)我怎么就攤上這事关串。” “怎么了晋修?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)倦春。 經(jīng)常有香客問(wèn)我,道長(zhǎng)落剪,這世上最難降的妖魔是什么溅漾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮著榴,結(jié)果婚禮上添履,老公的妹妹穿的比我還像新娘。我一直安慰自己脑又,他們只是感情好暮胧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布锐借。 她就那樣靜靜地躺著,像睡著了一般往衷。 火紅的嫁衣襯著肌膚如雪钞翔。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天席舍,我揣著相機(jī)與錄音布轿,去河邊找鬼。 笑死来颤,一個(gè)胖子當(dāng)著我的面吹牛汰扭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播福铅,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼萝毛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了滑黔?” 一聲冷哼從身側(cè)響起笆包,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎略荡,沒(méi)想到半個(gè)月后庵佣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汛兜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年秧了,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片序无。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡验毡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帝嗡,到底是詐尸還是另有隱情晶通,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布哟玷,位于F島的核電站,受9級(jí)特大地震影響喉脖,放射性物質(zhì)發(fā)生泄漏抑月。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一题诵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧性锭,春花似錦、人聲如沸她奥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)诅岩。三九已至带膜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間式廷,已是汗流浹背芭挽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工袜爪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辛馆。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓昙篙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缴挖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焚辅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容