JavaScript基于libgif.js实现控制gif动画帧
作者:夏末_阳光依然耀眼
一、原理
1.canvas、img、video,都是图像对象,属于图像类型的节点。这种图像对象不是Image 对象,而是对加载图像数据流的节点的统称。
- img 里的图像数据来源于提前制作好图片文件的,是静止的,比如.jpg,.png,.svg 等。.gif 是个特殊存在,另当别论。
- vedio 里的视频数据来源于提前制作好的视频文件,是动起来的。
- canvas 图像数据是动态生成的。
2.图像对象的数据的读写
读取图像数据
- img 和video 没有直接获取ImageData 的方法,但可以通过canvas 获取
- canvas 使用getImageData 方法读取自身的图像数据
写入图像数据
- img 和video 只能通过src ,以资源路径的方式设置其显示图像(img 的src 还可以使用base64)。但他们无法直接用ImageData 设置图像。
- canvas 可以用drawImage 或fillStyle 方法,以图像对象为参数,为canvas 或其内部元素写入图像数据。canvas 也可以通过putImageData方法,以ImageData 对象为参数,为其写入图像数据。
- gif 是介于图片和视频之间的特殊存在。
用读取image 数据的原理读取它,只能读到第一帧gif 图片。
直接绘制gif 肯定是不好使的,这里就用到了一个插件libgif.js
二、插件libgif.js
libgif.js已经完成了对gif 的解析,并将其写入了canvas 中。
libgif.js网址:github.com/buzzfeed/libgif-js
下面是我从官网上复制粘贴下来,用百度翻译一下 ,然后略作调整。英语好的可以跳过这里,看官网。
1.写在图片标签里的属性 Image tag attributes
- rel:animated_src - 如果指定了此url,则将其加载到播放器而不是src中。这允许显示预览帧,直到动画gif数据流入画布
- rel:auto_play - 如果未指定,则默认为1。如果设置为零,则需要调用play()方法
- rel:rubbable - 如果未指定,则默认为0。如果设置为1,则gif将是一个带有处理程序的画布来处理摩擦。
2.构造函数 Constructor options
- gif - 必填。img标签的DOM元素。
- loop_mode - 可选。将此设置为false将强制禁用gif的循环。
- auto_play - 可选。与上面的rel:auto_play属性相同,此arg会覆盖img标记信息。
- max_width - 可选。将图像从max_width缩放到max_width。有助于移动。
- rubbable - 可选。让它可以擦掉。
- on_end - 可选。添加一个回调,用于当gif到达单个循环结束时(一次迭代)。传递的第一个参数将是gif HTMLElement。
- loop_delay - 可选。每次循环(迭代)后暂停的时间(以毫秒为单位)。
- progressbar_height - 可选。进度条的高度。
- progressbar_background_color - 可选。进度条的背景颜色。
- progressbar_foreground_color - 可选。进度条的前景色。
3.loading 事件
- load(callback) - 将src指定的gif或img标记的rel:animated_src sttributie加载到canvas元素中,然后调用callback(如果有的话)
- load_url(src,callback) - 将src参数中指定的gif文件加载到canvas元素中,如果传递了一个,则调用callback
4.播放控制器 play controls
- play - 开始玩GIF
- pause - 停止播放gif
- move_to(i) - 移动到gif的第i帧
- move_relative(i) - 向前移动i帧(如果i <0则向后移动)
5.数据获取 getters
- get_canvas - gif正在播放的canvas元素。方便分配事件处理程序。
- get_playing - gif当前是否正在播放
- get_loading - gif是否已完成加载/解析
- get_auto_play - 是否将gif设置为自动播放
- get_length - gif中的帧数
- get_current_frame - 当前显示的gif帧的索引
6.官方案例
<center> <h1>控制gif播放/暂停/快进快退</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 对象继承自 SuperGif 对象,SuperGif是解析gif 的核心。
- 前端建立的 节点,只是一个向SuperGif 对象传递数据的工具,等SuperGif 解析完了gif,就会用canvas 将img 替换掉。
三、实际应用
前景是这样的,用gif做一个进度条,等待gif动画播放完成后,显示按钮;
一开始我是用了一个定时器设置时间跟gif动画时间一样长,时间到动画播放完成,按钮显示,没毛病; 但是,在实际运用过程中发现,加载gif由于网络原因跟定时器就不会同步,很多情况是,定时器走完了,gif才播放一半,显然效果不理想,后来经过产品提醒,能不能判断gif播放完毕后,再显示这个按钮;于是查找资料,发现了这个libgif.js插件挺好的,于是做了尝试,完美解决问题,在此记录一下。
本文重点讲述运用libgif.js实现,加载一个load.gif完成后,进行下一步的业务逻辑,代码如下:
<!--样式--> <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结构--> <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标签的DOM元素。 loop_mode:false, //将此设置为false将强制禁用gif的循环。 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(); // 设置一个定时器,周期性检查当前帧 var timer = setInterval(function() { if (gif.get_current_frame() === lastFrameIndex) { console.log("播放结束"); document.getElementById('btn').style.display='block'; clearInterval(timer); // 清除定时器 } }, 100); }); </script>
最终效果,是loadbg.gif动画播放完成后,a.play_2按钮显示。
附上libgif.js github:github.com/buzzfeed/libgif-js?tab=readme-ov-file
到此这篇关于JavaScript基于libgif.js实现控制gif动画帧的文章就介绍到这了,更多相关JavaScript控制动画帧内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!