G2(图表引擎) 4.0 和 G6(图分析引擎) 3.4版本已经替换了 G(2D 渲染引擎)4.0,这个版本最大的改进是支持了局部渲染,在一些场景下例如节点的状态改变、图形的个体动画等方面性能提高巨大。G 4.0 从开始重构到如今稳定经历了半年的不断完善,遇到了各类各样的问题,本文将对 Canvas 的局部渲染作一个总结,给后来者一些帮助。 javascript
因为 Canvas 的绘制方式是画笔式的,在 Canvas 上绘图时每调用一次 API 就会在画布上进行绘制一次,一旦绘制图形就成为画布的一部分。绘制图形时并无对象保存下来,一旦图形须要更新,须要清除整个画布从新绘制。
java
仅仅缩小刷新时的范围从而提高性能并不够,以右图为例,若是咱们要刷新图形 2 将图形变成红色。这时候若是仅仅清理掉图形 2 ,从新绘制则:
git
咱们来思考 Canvas 局部渲染方案时,须要看 Canvas 的 API 给咱们提供了什么样的接口,这里主要用到两个方法:github
经过这两个 API 咱们能够获得 Canvas 局部刷新的方案:canvas
真实的在 G 4.0 中实现局部渲染时遇到的问题比上面的案例复杂的多:浏览器
这些问题在 1-2 周内都解决了,可是在接入 G2 和 G6的过程当中遇到了一些彻底没想过的问题持续了半年的时间,主要体如今两个方面:安全
首先咱们来看画布上的两条线,一样都是 1 像素颜色 #333 的线,有什么差异?
markdown
因为屏幕的分辨率只能在整数的点上绘制颜色,线段 1 一半绘制在 (10, 99)-(200, 99) 一半绘制在 (10, 101 )-(200 101)上,因此浏览器会自动的把落到半个像素上的点扩展成一个点,颜色变淡,就变成了下图的示例(示例中画布进行放大,每一个单元格表明一像素)。
app
咱们在绘制图形时不少图形属性是自动计算出来的,例如:oop
这时候图形绘制的区域同数学计算出来的并不一致,这就会致使局部刷新时清空的区域不足,会留下一些残影。
因为 Canvas 在实现折线时,在线段的交接处作了处理,会附加额外的像素,使得折线更美观,咱们来看下单独绘制两条线段,和一条折线的差异:
在 Canvas 上绘制图形时能够指定阴影,有四个参数关系到阴影的设置:
shadowColor | 设置或返回用于阴影的颜色 |
---|---|
shadowBlur | 设置或返回用于阴影的模糊级别 |
shadowOffsetX | 设置或返回阴影距形状的水平距离 |
shadowOffsetY | 设置或返回阴影距形状的垂直距离 |
下面两个圆,若是不考虑阴影进行局部刷新时会出现下面的状况:
// 若是存在 shadow 则计算 shadow if (attrs.shadowColor) { const { shadowBlur = 0, shadowOffsetX = 0, shadowOffsetY = 0 } = attrs; const shadowLeft = minX - shadowBlur + shadowOffsetX; const shadowRight = maxX + shadowBlur + shadowOffsetX; const shadowTop = minY - shadowBlur + shadowOffsetY; const shadowBottom = maxY + shadowBlur + shadowOffsetY; minX = Math.min(minX, shadowLeft); maxX = Math.max(maxX, shadowRight); minY = Math.min(minY, shadowTop); maxY = Math.max(maxY, shadowBottom); } 复制代码
在线上增长箭头是个常见需求,可是因为箭头是附加在线上的,计算包围盒未计算在其中,这就致使刷新时箭头未被清除,同时箭头又有多种状况,还要考虑箭头的自定义:
你能看清楚下面的文本发生了什么吗?若是仔细观察会发现文本左侧被裁剪掉了一像素,这种状况在多个场景下都存在
G2 4.0 和 G6 3.4 发布后,有用户反馈在页面上进行操做时,出现一些线的划痕
// 附加 0.5 像素,会解决1px 变成 2px 的问题,不管 pixelRatio 的值是多少 // 真实测试的环境下,发如今 1-2 之间时会出现 >2 和 <1 的状况下未出现,可是为了安全,统一附加 0.5 const appendPixel = 0.5; if (region) { region.minX = Math.floor(region.minX - appendPixel); region.minY = Math.floor(region.minY - appendPixel); region.maxX = Math.ceil(region.maxX + appendPixel); region.maxY = Math.ceil(region.maxY + appendPixel); } 复制代码
若是同时有多个图形进行刷新,为了减小包围盒的计算,咱们会把全部刷新的图形的包围盒进行合并,可是会出现一些特殊状况,致使局部渲染的性能降低,例如:
经历了半年的改造,G 4.0 的局部渲染方案已经经历了 G2 和 G6 的考验,在局部刷新的场景下在交互和性能等方面提高了 7-10 倍,可是依然存在一些特殊场景上的性能问题,还在持续优化中。渲染的一分提高,上层都会有十分的收获。
AntV 官网:antv.vision/
2D 绘图引擎 G:github.com/antvis/g