2019年6月28日 星期五

[啥Web]Adobe Animate CC 2018輸出HTML5後結合個人網頁的方式[含結合Swiper外掛做出動畫切換Slider效果]

 

   一直以來都有想把自自己學過的技術留下記錄,但因為很花時間所以有些記錄其實都沒來得及寫,比如過去的Game Maker教學還有After Effect光流教學(這個在宅學習有但其實那個是暫存,因為事實上還沒打完)。

  這次想記錄的是個人研究HTML5的動畫部分。在Adobe Animate CC 2018內做好的HTML5動畫或互動輸出後,我是如何將那些結合網頁的。基本上算是我個人研究出來的,實際上有沒有人也這樣做我不是很清楚,我是覺得反正只要懂一點html與js基本上應該差不多。當然這邊會這樣提只是想說可能會有更好的方式就是,我可能不清楚,畢竟這裡只是個人筆記,建議有人對這有興趣可以多找其他資源(當然如果有人有找到也希望能回覆分享一下)。

  在開始貼上我筆記前,我先放上我這邊的發佈設定

 
 
 

   這邊大概說明一下,在基本的標籤有個作出回應的選項,那個的意思就是做RWD,因為RWD的是Responsive Web Design的縮寫。所以Adobe就將make responsive翻成作出回應...也不能說翻錯啦,但我第一次看到時完全看不懂= =",好歹也翻成製作成響應性式或直接寫RWD...

  總之那是為了做RWD用的。不過Adobe Animate的RWD很單純,他就只是將輸出的網頁做等比例縮放,不像實際上在做rwd不是只是單純做等比例縮放這件事,有些是要因應不同視窗做出不同排版。這點Adobe Animate是無法做到的。Google出的Google Web Designer其實就是往這方向設計的,但我個人不太會用就是。而只有等比例縮放,我個人是認為這就已經很夠用了。畢竟做動畫你若要考慮到不同排版,除了累以外還很不直覺。如果不同平台的等比例縮放實在太怪或不方便閱讀的話,我會乾脆就另外做一個動畫取代顯示就是。

  然後就是大概說明一下我為何選擇依寬度做RWD,主要是在圖片做RWD縮放的網頁我還沒遇過以高度做等比例縮放的就是。我想應該是現在排版大多都是由左而右從上至下的關係,我們圖片的排版通常都是和文字做並排,像是Bootstrap在使用col時也都是以寬度為基準,也因此在針對縮放這邊以寬度做等比例縮放會比較好。

  而圖片輸出這邊的資料夾位置會和你之後主檔html(不是指輸出的html)一樣的相對位置的資料夾檔名一樣,所以輸出完檔案後記得把圖檔位置搬一下。

  再來是這邊要注意js要分開輸出,雖然我記得預設就是。只是這邊要稍微提醒一下, 要分開js他竟然不是用勾選的而是用按鈕顯示目前打包狀態的方式。所以當你想把js包在html裡面,看到按鈕狀態是寫將javascript包在HTML中就代表你是分開輸出的了

  輸出完後基本上就是打開你要放入的網頁,這邊我稱為mergeAdobeAnimate.html。而我因為之後會修改輸出後的原始碼,去針對我放的區域做等比例縮放,所以html檔我不用輸出的而是用自己寫的。Adobe Animate輸出是以整個視窗大小去做縮放的,沒那麼好心還為你寫你想顯示的局塊縮放。所以這邊我必須得自行判斷放入位置的寬度去做RWD。而這一塊因為我本身對js原始的呼叫方式沒那麼熟,我是用JQuery的方法。因此其實如果有看懂我在做什麼的,是不必一定要引入JQuery就是。

撰寫html


  因為fla檔名就叫html5Example1,所以他會輸出html5Example1.html與html5Example1.js。這邊要把html5Example1.html裡的canvas tag貼在自己的mergeAdobeAnimate.html,並改名,避免之後有機會和其他canvas衝突。更改方式如下:

    <div id="id_html5Example1"><!--注意這邊要有寬高才會顯示-->
        <div id="id_html5Example1_animation_container">
            <canvas id="id_html5Example1_canvas" width="512" height="384" style="position: absolute; display: block; background-color:rgba(255, 255, 255, 1.00);"></canvas><!--注意這邊要有寬高只是參考用,RWD會自動修改,所以其實刪掉也行-->
            <div id="html5Example1_dom_overlay_container" style="pointer-events:none; overflow:hidden; width:512px; height:384px; position: absolute; left: 0px; top: 0px; display: block;"><!--注意這邊要有寬高只是參考用,RWD會自動修改,所以其實刪掉也行-->
            </div>
        </div>
    </div>

   注意到我改了3個地方的id,這代表之後js也有地方得動到。做這個的目的是為了避免之後若要引用其他地方的canvas會有衝突。

 完整獨立js


  再來看html5Example1.html檔。你會看到裡面還是有部分的js,我為了要做到在我們自己的html只要引入一個js檔並且使用一個函式乎叫,也為了避免之後引入其他檔案會有變數衝突,所以這邊要把那些js做合併全都放入html5Example1.js。這邊開始複製html5Example1.html裡從var canvas開始的語法。然後再打開html5Example1.js檔,拉到最底下寫一個呼叫的初始函式,比如html5Example1Init。把剛剛從html裡複製的語法通通貼到這個函式內。並更改剛剛改過的canvas、animation_container與dom_overlay_container。最後在var iw = window.innerWidth, ih=window.innerHeight這段改為取得的id_html5Example1的寬與高,不過這邊要注意,因為我們在發佈設定是以寬度為基準做RWD,所以其實高度的地方不會被用到就是。只要而改好後還有一個地方要改,就是要記得呼叫初始方法init();。總之整個要貼在html5Example1.js底端的原始碼如下:

function html5Example1Init()
{
    var canvas, stage, exportRoot, anim_container, dom_overlay_container, fnStartAnimation;
    init();
    function init() {
        canvas = document.getElementById("id_html5Example1_canvas");
        anim_container = document.getElementById("id_html5Example1_animation_container");
        dom_overlay_container = document.getElementById("id_html5Example1_dom_overlay_container");

        var comp=AdobeAn.getComposition("B1C74C98C1ED9C40A39A92EED8EFD7E6");
        var lib=comp.getLibrary();
        var loader = new createjs.LoadQueue(false);
        loader.addEventListener("fileload", function(evt){handleFileLoad(evt,comp)});
        loader.addEventListener("complete", function(evt){handleComplete(evt,comp)});
        var lib=comp.getLibrary();
        loader.loadManifest(lib.properties.manifest);
    }
    function handleFileLoad(evt, comp) {
        var images=comp.getImages();   
        if (evt && (evt.item.type == "image")) { images[evt.item.id] = evt.result; }   
    }
    function handleComplete(evt,comp) {
        //This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
        var lib=comp.getLibrary();
        var ss=comp.getSpriteSheet();
        var queue = evt.target;
        var ssMetadata = lib.ssMetadata;
        for(i=0; i<ssMetadata.length; i++) {
            ss[ssMetadata[i].name] = new createjs.SpriteSheet( {"images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames} )
        }
        exportRoot = new lib.html5Example1();
        stage = new lib.Stage(canvas);   
        //Registers the "tick" event listener.
        fnStartAnimation = function() {
            stage.addChild(exportRoot);
            createjs.Ticker.setFPS(lib.properties.fps);
            createjs.Ticker.addEventListener("tick", stage);
        }       
        //Code to support hidpi screens and responsive scaling.
        function makeResponsive(isResp, respDim, isScale, scaleType) {       
            var lastW, lastH, lastS=1;       
            window.addEventListener('resize', resizeCanvas);       
            resizeCanvas();       
            function resizeCanvas() {           
                var w = lib.properties.width, h = lib.properties.height;           
                var iw = $('#id_html5Example1').width(), ih=$('#id_html5Example1').height();           
                var pRatio = window.devicePixelRatio || 1, xRatio=iw/w, yRatio=ih/h, sRatio=1;           
                if(isResp) {               
                    if((respDim=='width'&&lastW==iw) || (respDim=='height'&&lastH==ih)) {                   
                        sRatio = lastS;               
                    }               
                    else if(!isScale) {                   
                        if(iw<w || ih<h)                       
                            sRatio = Math.min(xRatio, yRatio);               
                    }               
                    else if(scaleType==1) {                   
                        sRatio = Math.min(xRatio, yRatio);               
                    }               
                    else if(scaleType==2) {                   
                        sRatio = Math.max(xRatio, yRatio);               
                    }           
                }           
                canvas.width = w*pRatio*sRatio;           
                canvas.height = h*pRatio*sRatio;
                canvas.style.width = dom_overlay_container.style.width = anim_container.style.width =  w*sRatio+'px';               
                canvas.style.height = anim_container.style.height = dom_overlay_container.style.height = h*sRatio+'px';
                stage.scaleX = pRatio*sRatio;           
                stage.scaleY = pRatio*sRatio;           
                lastW = iw; lastH = ih; lastS = sRatio;           
                stage.tickOnUpdate = false;           
                stage.update();           
                stage.tickOnUpdate = true;       
            }
        }
        makeResponsive(true,'width',true,1);   
        AdobeAn.compositionLoaded(lib.properties.id);
        fnStartAnimation();
    }
}

  上面藍色的地方要注意的是那個地方如果日後不小心更動到,要注意他那序號是否和an.compositions['這邊']序號一模一樣,不然他會出不來。寫好後就可以丟入自己的js資料夾了。還有一點就是如果有兩個以上canvas,這個序號必須要不一樣,不然不會顯示。所以如果發生一樣的狀況(可能是同一檔案複製),請記得去改,那個序號可以拿其他檔案的,但建議重新開檔輸出會比較好。

  只是說,我在使用這個的過程常常會出現經過縮放視窗後回不去原來大小的狀況。而我不是很清楚原來Adobe的RWD縮放方式到底如何調整,所以我後來的改法是,當視窗大小小於本身動畫預設的大小才要改就好,也不會像Adobe的好像還有記憶一些我不是很清楚的參數。所以一開始如果id_html5Example1的大小若大於本身在Animate做的動畫大小時他絕對不會經過縮放。這雖然聽起來有點問題,但對我來說是最單純的設計。我只要一開始做動畫時給他大一點就好。所以我這邊就開始改了蠻大的了,然後我又再寫了一個參數讓他們統一乘以該數字,方便我之後覺得那樣的大小不理想還可以去調整。因此我的改法還多了一個參數canvasSizeModified。 這是我比較常用的改法:

function html5Example1Init()
{
    var canvas, stage, exportRoot, anim_container, dom_overlay_container, fnStartAnimation;
    var canvasSizeModified=1;
    init();
    function init() {
        canvas = document.getElementById("id_html5Example1_canvas");
        anim_container = document.getElementById("id_html5Example1_animation_container");
        dom_overlay_container = document.getElementById("id_html5Example1_dom_overlay_container");
        var comp=AdobeAn.getComposition("B1C74C98C1ED9C40A39A92EED8EFD7E6");
        var lib=comp.getLibrary();
        var loader = new createjs.LoadQueue(false);
        loader.addEventListener("fileload", function(evt){handleFileLoad(evt,comp)});
        loader.addEventListener("complete", function(evt){handleComplete(evt,comp)});
        var lib=comp.getLibrary();
        loader.loadManifest(lib.properties.manifest);
    }
    function handleFileLoad(evt, comp) {
        var images=comp.getImages();   
        if (evt && (evt.item.type == "image")) { images[evt.item.id] = evt.result; }   
    }
    function handleComplete(evt,comp) {
        //This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
        var lib=comp.getLibrary();
        var ss=comp.getSpriteSheet();
        var queue = evt.target;
        var ssMetadata = lib.ssMetadata;
        for(i=0; i<ssMetadata.length; i++) {
            ss[ssMetadata[i].name] = new createjs.SpriteSheet( {"images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames} )
        }
        exportRoot = new lib.html5Example1();
        stage = new lib.Stage(canvas);   
        //Registers the "tick" event listener.
        fnStartAnimation = function() {
            stage.addChild(exportRoot);
            createjs.Ticker.setFPS(lib.properties.fps);
            createjs.Ticker.addEventListener("tick", stage);
        }       
        //Code to support hidpi screens and responsive scaling.
        function makeResponsive(isResp, respDim, isScale, scaleType) {       
            var lastW, lastH, lastS=1;       
            window.addEventListener('resize', resizeCanvas);       
            resizeCanvas();       
            function resizeCanvas() {           
                var w = lib.properties.width, h = lib.properties.height;           
                var iw = $('#id_html5Example1').width();           
                var pRatio = window.devicePixelRatio || 1, xRatio=iw/w, sRatio=1;         
                 var pRatio = window.devicePixelRatio || 1, xRatio=iw/w,sRatio=1;         
                 if(isResp)
                 {             

/*
(如果你不在意失真,希望他完全隨著設定寬度做縮放的話,那你可能就得把判斷拿掉,直接讓sRatio=xRatio      
*/               
                     if(w>iw)
                    
                     {              
                        sRatio = xRatio;            
                     }
                 }          
                 canvas.width = w*pRatio*sRatio*canvasSizeModified;        
                 canvas.height = h*pRatio*sRatio*canvasSizeModified;
                 canvas.style.width = dom_overlay_container.style.width = anim_container.style.width =  w*sRatio*canvasSizeModified+'px';              
                 canvas.style.height = anim_container.style.height = dom_overlay_container.style.height = h*sRatio*canvasSizeModified+'px';
                 stage.scaleX = pRatio*sRatio*canvasSizeModified;          
                 stage.scaleY = pRatio*sRatio*canvasSizeModified;     
     

                stage.tickOnUpdate = false;           
                stage.update();           
                stage.tickOnUpdate = true;     
           
            }
        }
        makeResponsive(true,'width',true,1);   
        AdobeAn.compositionLoaded(lib.properties.id);
        fnStartAnimation();
    }
}

引入createjs和合併後的js


  接下來要開始回到mergeAdobeAnimate.html檔, 要引入createjs和合併後的js,他和剛剛提的jquery順序如下:
    <script src="js/createjs-2015.11.26.min.js"></script>
    <script src="js/jquery-3.1.1.min.js"></script>  
    <script src="js/html5Example1.js"></script> 

  然後再寫入自定義的呼叫函式:
    <script>
        function animeInit()
        {
            html5Example1Init();
        }
    </script>

  最後再在body輸入初始化函式:
<body onload="animeInit();">

  這樣就差不多了,記得在css裡要給id_html5Example1寬與高,這樣整個canvas才會顯示出來。而我為了讓這樣的寫法更能顯示RWD,我的範例還加上了Bootstrap.將canvas與80pt大的文字放在一起分別給文字col-5與id_html5Example1這動畫col-7。差不多長這樣:

  <div class="container-fluid">
        <div class="row">
            <p style="font-size:80pt" class="col-5">This is Test</p>
            <div id="id_html5Example1" class="col-7"><!-這邊因為bootstrap已經給定RWD會有的長寬了,所以才會顯示-->
                <div id="id_html5Example1_animation_container">
                    <canvas id="id_html5Example1_canvas" width="512" height="384" style="position: absolute; display: block; background-color:rgba(255, 255, 255, 1.00);"></canvas><!--注意這邊要有寬高只是參考用,RWD會自動修改,所以其實刪掉也行-->
                    <div id="id_html5Example1_dom_overlay_container" style="pointer-events:none; overflow:hidden; width:512px; height:384px; position: absolute; left: 0px; top: 0px; display: block;"><!--注意這邊要有寬高只是參考用,RWD會自動修改,所以其實刪掉也行-->
                    </div>
                </div>
            </div>
        </div>
    </div>

  縮放視窗就會看到如下的縮放:

 


 放入另一個HTML5動畫


  因此我相信會寫網頁的大概就知道要怎麼應用了 ,我這邊再做一個利用Swiper這個知名效果外卦去做兩個動畫的Slider切換(不過可能要注意我因為是拿以前寫的範例來改,所以用的Swiper是舊版語法,新版語法應該也是沒問題的就是)。基本上是另外做一個js,照上面步驟另外命名所有id與初始函式名稱(我是把所有html5Example1都改為html5Example2,然後記得在html5Example1Init();下再多執行一行 html5Example2Init();),還有要注意顯示序號必須不一樣就可以了。詳細寫法可以直接看我demo2的檔案或載我放的打包檔看mergeAdobeAnimateWithSwiper.html檔了。以下是用該外掛的coverflow效果:



最後補充

  • 如果有寫互動建議把stage變數提取出來變全域變數。因為如果你是寫互動式的網頁,你有機會想用到stage.gotoAndPlay之類的指令,我個人認為這是蠻方便的就是。而這邊還有一點要注意就是請改名字比如html5Example1Stage,然後在我們修改的js全部取代,避免和另外一個canvas衝突。
     
  • 還有如果想做loading進度讀取%數,可在js裡的loader.addEventListener("fileload", function(evt){handleFileLoad(evt,comp)});上方加入loader.addEventListener("progress", handlePreload);  並新增一個function handlePreload:
    function handlePreload(v)
    {
    myProgress=v.loaded; 
    } 

    myProgress這邊是全域變數,總之建議可以寫個timer一直去讀取他就是,只是Animate的進度其實都很完整,我記得都是25%為倍數,所以我也不清楚是不是有更好的讀取進度的地方。
     
  • 有個要注意的是,有的模糊或濾鏡效果在Adobe Animate內看都有,但其實輸出是沒有出現效果的。目前只有alpha才可以使用(像我個人DEMO1全都是透明度變化),其他似乎都有問題。
     
  • 後來我在前端社群討論得知放出以下教學影片的大大:
     

    他在他的底下回應有提到要把makeResponsive這個函式註解掉,我才驚覺之前有點被這函式給限制住了。雖然我透過js去做等比例縮放也是一種方式,但我之所以採取這個的原因是因為我一開始對canvas不熟,然後css怎麼修改他的長和寬都不會改變,所以就只好另找方法。聽到他的回應我才想到改不了的原因就是那個makeResponsive在搞的鬼啊....所以要是有不怎麼熟js的朋友或許在css改是比較好的,且記得把makeResponsive註解掉。

沒有留言: