前端图形——绘图、截图、合成动图

前言

本文主要是前端图形处理相关,主题围绕canvas进行展开。包括canvas动效、html2Canvas截图、gif.js合成动图。研究这些东西,有工做须要也有兴趣使然,研究的不深、不过仍是有点成果的,欢迎有兴趣的小伙伴一块儿交流探讨。css

主线

图形相关的主要包括两个方面:绘图、截图。html

技术实现上截图又分拆出静态图、动图两大类。前端

总的来讲也就是三个方面:动效、截图、动图。vue

关键点

  • 动效:主要是创意、实践、优化(封装等)
  • 截图:主要是canvas转图片、dom元素解析。此外还有衍生的模糊问题、跨域图片、样式兼容等难点
  • 动图:主要是截图、延时播放。技术实现上则主要是worker多线程的概念和在vue框架下的使用。

canvas动效

Canvas_API
常见的canvas优化——模糊问题、旋转效果webpack

动效制做思路

关于前端动效这块,主要包括三部分:css三、svg、canvas。css3

其中css3最轻量、canvas功能最强大,svg对客户端性能的需求比canvas低,手机端经常使用svg代替canvas、或替canvas实现前置步骤(如html2Canvas1.0.0)。git

鉴于我对canvas比较熟悉,接下来将针对canvas进行展开。github

首先要了解相应API,知道能干什么。

好比canvas就要先通览它的api,才知道原来能够绘制图形、制做动效,还能够转成图片!web

其次要有创意,知道要作成什么。

好比网上的树镜动效,效果很酷炫,实现也不难,可是没有这个创意也是作不出来的,很遗憾创意这块我也没什么好的思路。固然创意是创建在已有事物基础上的,兴许了解的多了,天然就有了吧……算法

而后要有好的逻辑思惟能力,把创意变成可实现的方案。

最好能有良好的代码风格,实现可复用,这样开发10个动效的成本就不至因而开发1个动效的10倍。目前想到的一个思路是:创意用逻辑实现,具体绘图实现封装成公用方式,按需引用。

动效实现

这里强烈建议找一个网上的好的动效,照着实现一遍,而后再仔细品味改进。我是研究的树镜动效,也从中学到了不少东西,在此很是感谢该动效创做者分享出这么好的动效。

树镜动效在vue框架下整理后大概长这样子:
图片描述
图片描述
图片描述

关于这个动效所涉及到的知识点,我分了几个模块:

  • 树镜分支构造函数TreeBranch

这个对应于“创意变成可实现的方案”这条,复杂的动效拆分后,本质上就是一个树(分支设为2就是二叉树了,有没有很熟悉),经过改变树的树枝长度、分叉角度等实现如此酷炫的动效,真正须要画的只是点和线而已。

原理搞清楚以后,就能够用js计算出点和线的坐标、色值等参数,也就是这里TreeBranch的做用,以后直接从变量中取参绘图便可。

  • 绘图实现模块drawTree

这个方法接收树的各项参数branch,而后调用基础API画点画线,最终画出树某一状态下的图案。

  • 循环绘图实现动效loop

这个方法用来循环调用drawTree绘制图形,并修改相关参数修改树的状态,实现树镜动效。

  • 交互事件interEvent

这个方法是用来绑定用户事件的,这样用户能够经过鼠标或触屏的方式主动修改相关参数、控制树的状态。

html2Canvas截图

首次接触html2Canvas是2017年11月底,当时给的任务是要在微信中实现图片分享,由于种种缘由,最后任务定为“实现前端截屏,并可添加自定义标签”。而很巧合的12月初做者来了次大改版,兼容了不少css3样式、而且对此前0.5.0版本的一些不足也进行了相关优化。针对html2Canvas的研究也在出了1.0.0-alpha.3以后的12月11号结束了。

鉴于对低版本手机的兼容,最终没有用吊炸天的1.0.0的版本,而是用了0.5.0的版本,也就须要研究0.5.0相对1.0.0有哪些不足,而后自行修复……

截图原理

鉴于要自行修复0.5.0的不足,因此就愉(悲)快(催)的去扒html2Canvas的源码了,天然也就了解了一点html2Canvas实现截图功能的原理。

对比两个版本,以及网上查阅资料,发现了两大亮点:
一、前端截图依赖于canvas转为图片资源的功能。
截图结束会返回一个canvas对象,这个canvas对象上绘制的正是咱们的截图区域。而后再将canvas转成图片便可。
二、截图区域怎么绘制到canvas上呢——经过对dom对象解析,变成canvas能理解的语言,在canvas上绘制一遍便可。

理解到这两点,也就掌握了前端截图的精髓(是否是很厉害~)。而后按你须要去研究要优化的点便可。

优化点

截图模糊

这个问题是1.0.0版本以前讨论最多的一个了,能够说凡是涉及到canvas几乎必谈模糊问题。

这里就不讲演进过程了,直接说最终解决方案:获取dom的scale,用dom的scale去设置canvas的scale(缩放比例)。

缘由能够去了解下手机端devicePixelRatio参数。

样式兼容

项目中不少地方用到flex布局,后面发现html2Canvas-0.5.0居然不兼容!!!

若是了解了截图原理的第二点,相信你就清楚是怎么回事了。前端截图其实并非真正的截图,而是理解了要截图区域的dom以后,仿照着在canvas画布上实现了一遍。这里有个很关键的就是要能解析dom结构,扒源码就会发现,并无对flex样式的解析支持。
图片描述
图片描述

虽然找到了样式不兼容的缘由,然而并不能针对性的解决——毕竟在旧版本上开发解析样式的任务仍是太大了点、也不实用,只能指望何时能用新版本。

最终咱们仍是老老实实的把须要截图的dom中的flex布局都替换掉了(万恶的兼容)。

跨域图片

当时截图元素包括微信头像和微信生成的带参二维码,结果图片出不来,好气哦!

由于已经悟到了截图原理的第一条——最终图片是经过canvas转过来的,并且canvas上是能画出来的,转成图片后才加载不出来微信头像和带参二维码,因此就针对性的研究canvas转图片的环节。这里要了解两点:
一、跨域图片会污染canvas
二、被污染的canvas不能转成图片(麻烦的同源策略)

而html2Canvas就提供了这两个参数的配置:useCORS、allowTaint,默认不加载跨域图片、不容许污染。
若是要转成图片allowTaint就必须为false,若是要加载跨域图片useCORS就必须为true。

因此要么咱们能把图片变成不跨域的,要否则就要解决跨域图片污染canvas的问题。

索性跨域图片的问题是仅此与截图模糊的一个问题,天然也有不少成熟方案。经过修改html2Canvas的源码,能够解决跨域图片污染canvas的问题。

clipboard.png

经过这个方案,咱们解决了微信头像的问题,然而带参二维码仍是不行。这里还要了解一点:加载跨域资源是须要后端支持的。而显然带参二维码的配置是不容许这样使用的。 那就只能把图片变成不跨域的了……
很幸运的,前端生成二维码的能力仍是有的,因此前端再也不请求二维码的url,而是直接在前端生成二维码。

通过一系列努力,跨域图片的问题总算也是圆满解决了。

gif.js生成动图

研究这个的动力来源于网上看到的一个例子canvas+gif.js打造本身的数字雨头像。而个人初步目标是实如今vue框架下实现gif.js的使用,从而方便以后研究调试(不用一直刷新浏览器),成果能够看个人github,路由是‘#/test/testCtxGif’。

踩过的坑

要有url才能使用,不能用本地文件路径

研究的最初天然是扒网上的代码放到本地访问,可是居然不能生成动图!自此开始研究gif.js。
gif.js是一个可直接在浏览器上运行的JS GIF编码器。使用类型化数组和web workers来渲染背景中的每一帧,速度很是快。

对比网上可正常使用的实例和本地没法正常使用的复制版,结合报错信息,尝试把实例挂到一个服务器上运行——IIS服务器,见证奇迹的时刻来了,方案可行!!!

移植代码到vue框架下

验证方案可行,只是须要挂在服务器上以后,就着手搬到vue框架下了。然而过程并不轻松。

  • Web Worker——前端多线程

首先是文件不能正常加载。gif.js却是好说,直接import就能够用了,GIF对象会挂载到window上;可是gif.worker.js倒是怎么都不能正常加载,因此也就老是不能正常执行。
而后开始探究gif.worker.js到底是何方神圣,能不能改造一下。
再而后就认识了webworkers这尊大佛,简直就是前端的一大利器啊!

Web Workers API 的 Worker 接口表明一个能够轻松建立的后台任务,并能够将消息发送回其建立者。建立一个工做程序只要简单的调用Worker() 构造函数,并指定一个要在工做线程中运行的脚本。

前端也能够多线程了?这简直是神迹了!

  • gif.worker.js文件加载

而gif.worker.js显然就是运用了Worker这个,Worker的建立是要传入要执行脚本的url,而后由worker去加载调用。那问题很明显了,就是worker的加载机制,不能正确加载到vue框架下的gif.worker.js文件——相对路径、hash路由,问题多多。

尝试了修改路径、改路由配置等方法失败后,灵光一闪——这不是webpack给的配置吗?加载失败我应该去找webpack啊!

而后就查到了worker-loader,配置好webpack的配置并适当修改gif.js的源码以后,文件终于加载成功了。vue框架下跑成功了!


可是也发现了个严重的问题:用worker-loader方式加载会严重影响worker的性能,对比不用vue框架,速度反而慢下来了。这可就大条了,搬到vue框架下是要提高开发效率的,可不能越搞越慢啊~

具体缘由没有深究,但经过实现效果来看,应该是webpack的这种引用方式破坏了worker的多线程的性能,居然会阻塞用户操做。因而乎开始抛开webpack去加载gif.worker.js。

事实证实,有梦想老是好的。把gif.js和gif.worker.js移到static文件夹下以后,终于成功了,速度贼快、性能贼好。

使用gif.js实现合成动图

可行性验证经过、开发环境配置完成以后,终于能够实践一下了,成品以下图。
clipboard.png

制做canvas动效-用做截动图

仿照网上的例子,我也实现了一个简单的canvas动效做为素材。也就是动图中的效果,具体实现能够看github上的代码。

gif.js实现动图合成

gif.js支持咱们加载canvas对象、image对象或直接拷贝从ctx中拷贝像素点,设置帧延迟、采样间隔、循环方式等。

而原理则是gif相关的:截取多张图片、按照设置的时间间隔依次展现,从而实现动图的效果。

具体的参数设置好比:画图尺寸(主要是缩放效果)、canvas对象截图间隔等等,还有待进一步探究。

结语

从接触canvas到如今也有将近一年,也许是从canvas开始入门前端的缘故,老是会对图形相关的比较有兴趣。如今也算是对这系列的研究有个小结,但愿以后有机会接触更酷炫的效果或者游戏相关的,固然前端、算法这些也但愿都有突破。嗯,总要有点梦想的,说不定就实现了呢~
图片描述

相关文章
相关标签/搜索