JavaScript基于libgif.js實(shí)現(xiàn)控制gif動(dòng)畫幀
一、原理
1.canvas、img、video,都是圖像對(duì)象,屬于圖像類型的節(jié)點(diǎn)。這種圖像對(duì)象不是Image 對(duì)象,而是對(duì)加載圖像數(shù)據(jù)流的節(jié)點(diǎn)的統(tǒng)稱。
- img 里的圖像數(shù)據(jù)來(lái)源于提前制作好圖片文件的,是靜止的,比如.jpg,.png,.svg 等。.gif 是個(gè)特殊存在,另當(dāng)別論。
- vedio 里的視頻數(shù)據(jù)來(lái)源于提前制作好的視頻文件,是動(dòng)起來(lái)的。
- canvas 圖像數(shù)據(jù)是動(dòng)態(tài)生成的。
2.圖像對(duì)象的數(shù)據(jù)的讀寫
讀取圖像數(shù)據(jù)
- img 和video 沒有直接獲取ImageData 的方法,但可以通過(guò)canvas 獲取
- canvas 使用getImageData 方法讀取自身的圖像數(shù)據(jù)
寫入圖像數(shù)據(jù)
- img 和video 只能通過(guò)src ,以資源路徑的方式設(shè)置其顯示圖像(img 的src 還可以使用base64)。但他們無(wú)法直接用ImageData 設(shè)置圖像。
- canvas 可以用drawImage 或fillStyle 方法,以圖像對(duì)象為參數(shù),為canvas 或其內(nèi)部元素寫入圖像數(shù)據(jù)。canvas 也可以通過(guò)putImageData方法,以ImageData 對(duì)象為參數(shù),為其寫入圖像數(shù)據(jù)。
- gif 是介于圖片和視頻之間的特殊存在。
用讀取image 數(shù)據(jù)的原理讀取它,只能讀到第一幀gif 圖片。
直接繪制gif 肯定是不好使的,這里就用到了一個(gè)插件libgif.js
二、插件libgif.js
libgif.js已經(jīng)完成了對(duì)gif 的解析,并將其寫入了canvas 中。
libgif.js網(wǎng)址:github.com/buzzfeed/libgif-js
下面是我從官網(wǎng)上復(fù)制粘貼下來(lái),用百度翻譯一下 ,然后略作調(diào)整。英語(yǔ)好的可以跳過(guò)這里,看官網(wǎng)。
1.寫在圖片標(biāo)簽里的屬性 Image tag attributes
- rel:animated_src - 如果指定了此url,則將其加載到播放器而不是src中。這允許顯示預(yù)覽幀,直到動(dòng)畫gif數(shù)據(jù)流入畫布
- rel:auto_play - 如果未指定,則默認(rèn)為1。如果設(shè)置為零,則需要調(diào)用play()方法
- rel:rubbable - 如果未指定,則默認(rèn)為0。如果設(shè)置為1,則gif將是一個(gè)帶有處理程序的畫布來(lái)處理摩擦。
2.構(gòu)造函數(shù) Constructor options
- gif - 必填。img標(biāo)簽的DOM元素。
- loop_mode - 可選。將此設(shè)置為false將強(qiáng)制禁用gif的循環(huán)。
- auto_play - 可選。與上面的rel:auto_play屬性相同,此arg會(huì)覆蓋img標(biāo)記信息。
- max_width - 可選。將圖像從max_width縮放到max_width。有助于移動(dòng)。
- rubbable - 可選。讓它可以擦掉。
- on_end - 可選。添加一個(gè)回調(diào),用于當(dāng)gif到達(dá)單個(gè)循環(huán)結(jié)束時(shí)(一次迭代)。傳遞的第一個(gè)參數(shù)將是gif HTMLElement。
- loop_delay - 可選。每次循環(huán)(迭代)后暫停的時(shí)間(以毫秒為單位)。
- progressbar_height - 可選。進(jìn)度條的高度。
- progressbar_background_color - 可選。進(jìn)度條的背景顏色。
- progressbar_foreground_color - 可選。進(jìn)度條的前景色。
3.loading 事件
- load(callback) - 將src指定的gif或img標(biāo)記的rel:animated_src sttributie加載到canvas元素中,然后調(diào)用callback(如果有的話)
- load_url(src,callback) - 將src參數(shù)中指定的gif文件加載到canvas元素中,如果傳遞了一個(gè),則調(diào)用callback
4.播放控制器 play controls
- play - 開始玩GIF
- pause - 停止播放gif
- move_to(i) - 移動(dòng)到gif的第i幀
- move_relative(i) - 向前移動(dòng)i幀(如果i <0則向后移動(dòng))
5.數(shù)據(jù)獲取 getters
- get_canvas - gif正在播放的canvas元素。方便分配事件處理程序。
- get_playing - gif當(dāng)前是否正在播放
- get_loading - gif是否已完成加載/解析
- get_auto_play - 是否將gif設(shè)置為自動(dòng)播放
- get_length - gif中的幀數(shù)
- get_current_frame - 當(dāng)前顯示的gif幀的索引
6.官方案例
<center> <h1>控制gif播放/暫停/快進(jìn)快退</h1> <img id="example1" src="./example_gifs/rub_test_preview.jpg" rel:animated_src="./example_gifs/rub_test.gif" rel:auto_play="0" width="467" height="375" /> <br> <script type="text/javascript"> var sup1 = new SuperGif({ gif: document.getElementById('example1') } ); sup1.load(); </script> <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onmousedown="sup1.play(); return false;">播放</a> | <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onmousedown="sup1.pause(); return false;">暫停</a> <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onmousedown="sup1.move_to(0); return false;">還原</a> | <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onmousedown="sup1.move_relative(1); return false;">下一幀</a> | <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onmousedown="sup1.move_relative(-1); return false;">上一幀</a> </center> <img src="./example1_preview.gif" rel:animated_src="./example1.gif" width="360" height="360" rel:auto_play="1" rel:rubbable="1" /> <script type="text/javascript"> $$('img').each(function (img_tag) { if (/.*\.gif/.test(img_tag.src)) { var rub = new SuperGif({ gif: img_tag } ); rub.load(function(){ console.log('oh hey, now the gif is loaded'); }); } }); </script>
提示:
- RubbableGif 對(duì)象繼承自 SuperGif 對(duì)象,SuperGif是解析gif 的核心。
- 前端建立的 節(jié)點(diǎn),只是一個(gè)向SuperGif 對(duì)象傳遞數(shù)據(jù)的工具,等SuperGif 解析完了gif,就會(huì)用canvas 將img 替換掉。
三、實(shí)際應(yīng)用
前景是這樣的,用gif做一個(gè)進(jìn)度條,等待gif動(dòng)畫播放完成后,顯示按鈕;
一開始我是用了一個(gè)定時(shí)器設(shè)置時(shí)間跟gif動(dòng)畫時(shí)間一樣長(zhǎng),時(shí)間到動(dòng)畫播放完成,按鈕顯示,沒毛??; 但是,在實(shí)際運(yùn)用過(guò)程中發(fā)現(xiàn),加載gif由于網(wǎng)絡(luò)原因跟定時(shí)器就不會(huì)同步,很多情況是,定時(shí)器走完了,gif才播放一半,顯然效果不理想,后來(lái)經(jīng)過(guò)產(chǎn)品提醒,能不能判斷gif播放完畢后,再顯示這個(gè)按鈕;于是查找資料,發(fā)現(xiàn)了這個(gè)libgif.js插件挺好的,于是做了嘗試,完美解決問(wèn)題,在此記錄一下。
本文重點(diǎn)講述運(yùn)用libgif.js實(shí)現(xiàn),加載一個(gè)load.gif完成后,進(jìn)行下一步的業(yè)務(wù)邏輯,代碼如下:
<!--樣式--> <style type="text/css"> *{margin: 0; padding: 0;} .load_p{ position: relative; width: 100vw; height: 100vh; } a.play_2{display: none; position: absolute; left: 50%; top: 50%; margin-left:-370px; margin-top:-37px;} </style>
<!--dom結(jié)構(gòu)--> <script type="text/javascript" src="./libgif.js"></script> <div class="load_p"> <img id="load" src="./example_gifs/loadbg.gif" rel:animated_src="./example_gifs/loadbg.gif" rel:auto_play="0"/> <a href="javascript://" rel="external nofollow" class="play_2" id="btn"><img src="./example_gifs/p1_btn_v.png" alt=""/></a> </div>
<!--js--> <script type="text/javascript"> var gif = new SuperGif({ gif: document.getElementById('load'), //img標(biāo)簽的DOM元素。 loop_mode:false, //將此設(shè)置為false將強(qiáng)制禁用gif的循環(huán)。 progressbar_foreground_color: "rgba(255,255,255,0.1)", progressbar_background_color: "rgba(255,255,255,0.1)", progressbar_height: 1 }); gif.load(function() { var lastFrameIndex = gif.get_length() - 1; // 獲取最后一幀的索引 gif.play(); // 設(shè)置一個(gè)定時(shí)器,周期性檢查當(dāng)前幀 var timer = setInterval(function() { if (gif.get_current_frame() === lastFrameIndex) { console.log("播放結(jié)束"); document.getElementById('btn').style.display='block'; clearInterval(timer); // 清除定時(shí)器 } }, 100); }); </script>
最終效果,是loadbg.gif動(dòng)畫播放完成后,a.play_2按鈕顯示。
附上libgif.js github:github.com/buzzfeed/libgif-js?tab=readme-ov-file
到此這篇關(guān)于JavaScript基于libgif.js實(shí)現(xiàn)控制gif動(dòng)畫幀的文章就介紹到這了,更多相關(guān)JavaScript控制動(dòng)畫幀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS一維數(shù)組轉(zhuǎn)化為三維數(shù)組方法
這篇文章主要給大家分享了JS一維數(shù)組轉(zhuǎn)化為三維數(shù)組的方法,下面文章圍繞JS數(shù)組轉(zhuǎn)換的相關(guān)資料展開內(nèi)容,對(duì)大家的學(xué)習(xí)有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-01-01你需要知道的TypeScript高級(jí)類型總結(jié)
在開發(fā)過(guò)程中,為了應(yīng)對(duì)多變的復(fù)雜場(chǎng)景,我們需要了解一下?TypeScript?的高級(jí)類型。本文就為大家整理了一些需要掌握的TypeScript高級(jí)類型,需要的可以參考一下2022-08-08Javascript表單序列化原理及實(shí)現(xiàn)代碼詳解
這篇文章主要介紹了Javascript表單序列化原理及實(shí)現(xiàn)代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10JavaScript+canvas實(shí)現(xiàn)七色板效果實(shí)例
這篇文章主要介紹了JavaScript+canvas實(shí)現(xiàn)七色板效果的方法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript結(jié)合html5的canvas技術(shù)實(shí)現(xiàn)繪制七色板效果的相關(guān)技巧,需要的朋友可以參考下2016-02-02JavaScript循環(huán)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了JavaScript循環(huán)的相關(guān)資料,JavaScript的兩種循環(huán)方式,一種是for循環(huán),另while一種是循環(huán)具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06BOM之navigator對(duì)象和用戶代理檢測(cè)
navigator對(duì)象現(xiàn)在已經(jīng)成為識(shí)別客戶端瀏覽器的事實(shí)標(biāo)準(zhǔn),navigator對(duì)象是所有支持javascript的瀏覽器所共有的。本文將詳細(xì)介紹navigator對(duì)象和用戶代理檢測(cè)。下面跟著小編一起來(lái)看下吧2017-02-02jQuery animate()實(shí)現(xiàn)背景色漸變效果的處理方法【使用jQuery.color.js插件】
這篇文章主要介紹了jQuery animate()實(shí)現(xiàn)背景色漸變效果的處理方法,結(jié)合實(shí)例形式分析了jQuery顏色插件jquery.color.js實(shí)現(xiàn)背景色漸變的簡(jiǎn)單操作技巧,需要的朋友可以參考下2017-03-03