写些我的职业生涯中关于 canvas 的总结

·  阅读 1333

作为一个大龄转行的前端程序猿,很想总结下自己在这3年时间的 canvas 经验,感觉冥冥中自己与canvas有特殊的缘分。

初见

最初决定转行做前端的时候,我辞职窝在家学习了3个月的基础,出于对游戏的热爱还对canvas做了专门的学习,做了几个简单的canvas demo(贪吃蛇, 时钟),这是我初次结识canvas。

通过这段时间的学习,我认识到了canvas开发的一些基本要求:

  1. 熟练使用所有的 canvas api;
  2. 良好的数学基础;
  3. 面向对象的编程思想。

有意思的是,我入职第一家公司面试我的技术主管对canvas有着丰富经验(负责过语音转波形工具的开发),我至今都记得他当时提出的问题:

如果让你做一个坦克大战的游戏,有着复杂的地图背景,你有什么性能优化方式?

一、绕不过的坎 - echarts

入职我接手了好几个中后台的项目,它们都有着共同的特点,大量的表单,表格,还是最重要的:图表。

简单的图表展示用echarts就是傻瓜式配置,我所能遇到的坑都是由于自己对官方文档的不熟悉。当时我只觉得echarts还挺简单的嘛,直到我接手了那个陪伴我一年多的项目。

这个项目有一个亟待解决的canvas性能问题,因为它用了echarts的力导向关系图组件,当画布上的节点和关系边达到上千个时页面会有严重的卡顿。主要的问题点有两个:

  1. 布局:大量节点的力引导模拟计算,导致关系图的布局时间过长。
  2. 渲染:大量节点、关系边以及label的渲染,导致关系图在鼠标交互时卡顿。

当时的echarts2实际上已经对布局做了很多性能优化工作,比如 Barnes Hut 算法,比如启用 web worker,然而对于渲染的性能问题并没有解决。沈毅在github对这个问题的建议是使用echarts GL,并称echarts GL在不久后就可以支持节点的鼠标交互 (然而直到2年后的今天依然没有实现 \手动滑稽)。

没有办法,只有改源码了,通过分层渲染解决节点拖拽的性能问题,通过隐藏文字解决布局和缩放时的性能问题,并且对力引导布局的精度做了调整,最终实现了客户的需求。当时我只用了1周多的时间就解决了前人开会讨论了数月的问题,还是很有成就感的。

对echarts源码的研究也让我学习到了很多canvas的性能优化技巧:

  1. 非零绕组的实现;
  2. 分层渲染;
  3. 离屏缓存;
  4. 渐进式渲染;
  5. 使用四叉树减少算法复杂度;
  6. 使用 web worker 处理向量计算。

二、canvas的另一个方向 - openlayers

还是同样的项目,我接触到了 openlayers,一个 Web GIS 的 js 开发引擎。WEB GIS 是个特别专业的方向,专业到这个方向的程序猿不叫前端开发而被称呼为 GIS 开发。

在刚接触 openlayers 的一段时间真的觉得头疼,虽说它的底层还是canvas,但是封装了太多的类,太多的 api,网上的相关文章也基本都是英文的,就这样自己一个人慢慢摸索也实现了需求。在摸索的过程中印象最深的是 openlayers 对于热力图的性能优化,它使用离屏缓存和 imageData 转换的方式实现了用单个阴影数据渲染出整个热力图,这让我对离屏缓存的使用又有了新的认识。

之后,为了解决项目中 openlayers 代码逻辑重复和耦合度高的问题,我针对项目的需求对 openlayers 做了二次封装,开发了 olMap 这个插件(项目地址, demo地址)。

封装插件对能力提升是特别有益的,它能锻炼你的业务抽取能力,架构设计能力,前端工程化能力。我会把 openlayers 当作 echarts 的引擎 zRender,思考如果才能设计出一个具有高度可扩展性以及可复用性的插件。最终的结果也是令人满意的,即使是后端开发人员在完全不理解 openlayers 的情况下也能用该插件快速开发出一个地图页面。

后来又接手了 3d 地图的调研,开始接触 cesium,但是没多久我便离职了。现在细想起来,如果真在 Web GIS 方向深入探索的话,我的职业道路可能是另一个方向吧。

三、回到初心 - fabric

19年4月我来到了现在的公司,或许真的是缘分使然,我又接手了 canvas 的项目,项目用的是 fabric。fabric 的目的是让我们更简单的操作 canvas,而且是使用对象的方式。刚接触它的时候我的第一感觉是,跟 zRender 好像啊,还是那么熟悉的味道,我知道,我又可以开心的写 canvas 了。

总结一下这大半年来我在该项目上的贡献的话,应该是下面几点。

1. fabric 版本升级

之前说的 echarts 那个项目我一直有个遗憾,那就是项目用的是 echarts2,并且由于直接修改了源码(历史遗留问题),导致 echarts 版本很难升级。而现在的这个项目不同,它使用 extend 机制,去 hack 掉原生的方法,从而实现不改源码的一行代码。这种扩展方式让我能够顺利的对 fabric 进行版本升级(1.7 -> 3.4),当然升级的过程中也让我对 fabric 有了更深的理解。

fabric 在升级后最大的变化是 requestRenderAll 方法的出现,这个方法是为了解决重复渲染,升级之后也确实给页面带来了一定的性能提升。

2. 优化表格组件

fabric 本身没有表格,项目中的表格是组内大佬根据项目需求自己开发的。但这个表格有严重的性能问题,在拖动表格和编辑单元格文字时会有明显卡顿,并且用户编辑起来很麻烦,针对以上问题我做了下面几点优化:

  • 给表格组件添加缓存,优化整体渲染性能
  • 优化单元格进入编辑模式的逻辑,解决编辑时的卡顿
  • 优化表格键盘交互(参考 excel)

fabric 使用了一个隐藏的 textarea 来监听键盘输入,我参考这个做法给表格单元格做了一个隐藏的 Textbox, 使得单元格可以在选中时也能输入中文。

3. 解决子集化字体在 ubuntu 环境底部模糊问题

这个问题跟 fabric 无关,但是解决这个问题确实蛮有成就感。由于项目中提供多种字体供用户选择,因此项目中对字体做了子集化处理,但子集化后的字体在 ubuntu 环境下却出现显示异常。我通过层层排查最终确定问题根源是 ubuntu 系统渲染文字时需要根据 'ceosuvxz' 这些字母作为 baseline 的基准,最终解决了这个困扰我们好几个月的问题。

四、未来

可视化领域的未来必定是 Web 3D, 目前的实现方式最有影响力的是 webGL, 但各个大厂对于标准的制定还不统一,如果不是工作需要的话,我还是不会盲目的去深入学习 webGL 的。但不管未来怎样变化,数学基础都会是可视化领域的一项硬性要求,把基本功锻炼好还是最重要的。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改