SVGA-web實踐(開發禮物特效)

在實踐過bodymovin以後,發現若是須要在動畫裏面加邏輯比較麻煩,效果也很差。所以後面找到了另一個開源的工具,就是YY開源出來的svga,有android,ios,web版本,還有對應的AE插件,用法請看官方文檔html

之因此選擇svga:前端

  1. 比較強大的api;
  2. 聽說性能比bodymovin好(不敢下定論,由於按照目前接觸過bodymovin跟svga的狀況來看,感受若是隻是純播放,bodymovin的性能會流暢一點,固然,這個跟個人引用場景有關係,一個比較蛋疼的緣由,就是須要在本地播放。);

問題:由於須要本地播放,因此Parse.load傳的是svga文件轉成base64以後的字符串,load會多了一步readBlobAsArrayBuffer的過程,這個很耗瀏覽器性能。android

svga

設計經過AE+svga插件,導出一個動畫的svga格式的一個二進制文件,雖然看不到裏面的內容,可是把他扔到svga預覽,是能夠看到svga文件的一些信息的(轉換以後)ios

svga基本信息
{
  "version": "2.0",
  "FPS": 30,
  "frames": 110,
  "videoSize": {
    "width": 750,
    "height": 750
  }
}


//素材信息
A --- {"width":600,"height":493}
Aleft --- {"width":82,"height":67}
Aright --- {"width":82,"height":67}
Avatar --- {"width":72,"height":72}
BG --- {"width":750,"height":750}
Bleft --- {"width":120,"height":97}
Bright --- {"width":120,"height":97}
Planet --- {"width":80,"height":60}
flower --- {"width":63,"height":26}
hole --- {"width":113,"height":109}
img_491 --- {"width":38,"height":38}
medal --- {"width":376,"height":415}
medal-bling-l --- {"width":66,"height":66}

複製代碼

固然,文件裏面的信息確定不僅包含上面的信息,看svga-web的源碼,裏面的reader那一部分的邏輯,應該是有包含具體到哪一幀用canvas繪製上面樣的內容的一些信息(這個好像是廢話)。git

需求:寶箱1.0

設計大佬會給一個寶箱的svga,這邊須要作的就是經過設計大佬給一個imagekey+svga的setImage去設置寶箱開處理的禮物圖片。github

動畫gif以下:
部分代碼以下:
var parser = new svgaplayerweb.Parser('#canvas')
var player = new svgaplayerweb.Player('#canvas')

//之因此用這個方法去作適配是由於官方的庫設置fillMode屬性有在ios7p/8p 上面有bug,那時候沒去提issuse,不知道如今修復了沒
function setFill(){
    var $_canvas = document.getElementById('canvas'),
        w = window.innerWidth,
        h = window.innerHeight,
        screen_proportion = h/w,
        svga_proportion = 16/9;
    if(screen_proportion > svga_proportion){//長屏幕
        $_canvas.style.width = h/svga_proportion+'px';
        $_canvas.style.left = (w-h/svga_proportion)/2+'px';
    }else{
        $_canvas.style.height = w*svga_proportion+'px';
        $_canvas.style.top = (h-w*svga_proportion)/2+'px';
    }
    
}

//初始化
function svgaInitial(giftSrc){
    // svga ready
    parser.load(svgabase64,function(videoItem){
        //設置寶箱開出的禮物圖片
        player.setImage(giftSrc, 'gift')
        player.loops = 1;
        player.setVideoItem(videoItem);
        player.onFinished(function(){
            //播放結束後觸發離開邏輯
            leave();
        })
        enter();
    },function(err){
        // alert(err.message);
        //報錯直接觸發離開邏輯
        leave();
    })
}
複製代碼
需求:寶箱1.1

寶箱部分禮物須要開出圖片,一部分須要開出特效,這個時候就比較爲難,最後決定的解決方案是在寶箱裏面放置了好幾段特效,分別是:寶箱打開+普通禮物(1.0)+寶箱打開+大禮物特效*N(這樣致使了一個特效包最大的差很少2M)web

部分代碼以下:
//相對於1.0的版本,1.1的版本多了好幾個svga文件,多瞭如下判斷邏輯,經過參數去以爲播放哪個svga
if(giftId == 7){
    svgabase64 = box_JL;
}
else if(giftId == 8){
    svgabase64 = box_HD;
    
}
else if(giftId == 9){
    svgabase64 = box_CS;
}

問題:雖然只load一份base64,不過幾個base64文件打包到一個js裏面去,會致使js的體積很大
複製代碼
需求:寶箱1.2

寶箱須要開出的禮物有不一樣的類別(最大五種)+不一樣的數量,若是這個效果按照1.1的形式去作的話,得須要有五段不同的svga,那麼整個特效包的大小確定會超過2M。在去看文檔的時候,發現了startAnimationWithRange這個方法,播放svga動畫的某一個區間的動畫,但仍是知足不了,無奈之下fork一下倉庫,本身實現一些功能json

  1. 多段拼接播放(startAnimationWithRangeDouble)
  2. 特殊字體,字體顏色漸變,陰影的支持
player.setText({
    text:form,
    size:form > 99 ? "160px" :"200px",
    color:"linear-gradient(to right, #e1d7b4, #bfae7d)",
    family:"Impact",
    offset:{
        x:0,
        y:-10
    },
    textShadow:{
        color:'rgba(0, 0, 0, 0.01)',
        offsetX:0,
        offsetY:3,
        blur:3
    }
},"numberone");
複製代碼
動畫gif以下:
部分代碼以下:
function svgaInitial(){
    var len = gift.length;
    var releaseGift = function(data,len){
        data.forEach((item,index) => {
            player.setImage(item.src,`gift-${len == 1 ? "" : len+"-"}${index+1}`);
            player.setText({
                text:`X${item.count}`,
                size:item.count>999 ? "40px":"54px",
                family:"BaiZhouRenZhe",
                color: "#FFF2C8",
                offset: {x: 0, y: 0}
            },`gift-count-${len == 1 ? "" : len+"-"}${index+1}`)
        })
    }
    // svga ready
    parser.load(svgabase64,function(videoItem){
        player.loops = 1;
        releaseGift(gift,giftLen);
        player.setVideoItem(videoItem);
        player.onFinished(function(){
            leave();
        })
        if(len > 0){
            enter();
        }
    },function(err){
        leave();
    })
}


function enter() {
    var releaseSvga = function(gift,len){
        switch(len){
            case 1:
                player.startAnimationWithRange({location:0,length:200});
            break;
            case 2:
                player.startAnimationWithRangeDouble([{location:0,length:150},{location:200,length:50}]);
            break;
            case 3:
                player.startAnimationWithRangeDouble([{location:0,length:150},{location:250,length:50}]);
            break;
            case 4:
                player.startAnimationWithRangeDouble([{location:0,length:150},{location:300,length:50}]);
            break;
            case 5:
                player.startAnimationWithRangeDouble([{location:0,length:150},{location:350,length:50}]);
            break;
        }
    }
    releaseSvga(gift,giftLen)
}

//相對於1.1的版本,此次1.2的版本減小了打包以後總體的體積,可是由於是所有動畫都在一個svga文件,單個的svga的文件比較大,所以load起來的速度也會慢一些。
複製代碼

總結

  1. 關於bodymovin 跟 svga的性能,網上有分析,不過我仍是以爲要本身分析一下才能下定論。
  2. 因爲須要本地播放,所以對我來講,svga2base64的體積比svga的體積會大25%左右,若是是bodymovin的話,一份json的體積其實仍是挺小的,就是api支持不夠
  3. 對於android4.x的手機來講,不支持jszip,還有blob的,還得導入這兩個庫,這一部分的體積應該是在100kb左右,固然,這個是能夠作成離線緩存的,這個又是另一個話題了

bodymovin,svga幫助咱們解脫了看着mov寫特效,而後設計師坐在旁邊花費不少時間去調試到滿意的結果的日子。讓前端能夠更注重寫邏輯這塊的代碼。canvas

之後
  1. 目前bodymovin跟svga都不支持粒子效果,看下能不能撇開插件那塊,在svga-web裏面去作這一部分。主要是設計+產品的想法是永遠都沒法知足的 T T

原本是想在每一個版本上面都加上動畫的gif的,奈何md的寫法添加圖片比較煩,或者須要一個圖片服務器上傳圖片纔好,又不想用富文本編輯器去寫,因此就沒放了。api

相關文章
相關標籤/搜索