前言
cache实例方法定义在Node基类上,通过该方法可以实现图形缓存,在Konva中Stage、Layer、Group、Shape等所有容器类和图形类都直接或间接继承了Node基类,故而都可以使用缓存方法。本篇文章就是探讨Konva背后的缓存机制,版本是v9.2.1。
Konva离屏缓存
就以下面的实例进行整体过程的分析:
const stage = new Konva.Stage({container: 'root',width: window.innerWidth,height: window.innerHeight,});const layer = new Konva.Layer();const star = new Konva.Star({innerRadius: 20,outerRadius: 50,fill: 'red',stroke: 'black',strokeWidth: 5,numPoints: 5,x: 60,y: 60,shadowOffset: { x: 5, y: 5 },shadowColor: 'black',shadowBlur: 5,shadowOpacity: 0.5,shadowForStrokeEnabled: false,});star.cache()layer.add(star);stage.add(layer);// 创建10个Starlet clone;for (var n = 0; n < 10; n++) {clone = star.clone({x: Math.random() * stage.width(),y: Math.random() * stage.height(),});clone.cache();layer.add(clone);}
上面的实例就是创建11个Star图形,每个图形都会调用cache实例方法进行缓存。
cache处理流程
cache实例方法的处理逻辑如下:
当图形对象调用缓存方法cache时,其逻辑总结如下:
- 首先内部会计算当前图形的包围框信息(大小以及位置),通过包围框的大小信息创建cachedSceneCanvas、cachedFilterCanvas、cachedHitCanvas三个Canvas图层,这三个图层不会挂载在页面上仅仅位于内存中
- 然后将当前图形绘制到CachedSceneCanvas、CachedHitCanvas中
- 最后会将相关包围框位置信息以及CachedCanvas保存到_cache实例属性中,用于后续的逻辑处理
需要注意的是总会保存最新信息到_cache实例属性中,如果多次调用cache实例方法时会先删除_cache中存在的key,然后重新添加,逻辑如下:
cache() {...this._cache.delete(CANVAS);...this._cache.set(CANVAS, {scene: cachedSceneCanvas,ilter: cachedFilterCanvas,hit: cachedHitCanvas,x: x,y: y,});...
缓存图形的渲染
Konva是批量渲染图形的,在之前
Konva批量渲染文章中就有较为详细的处理逻辑,缓存图形的渲染逻辑也包含在其中,只是之前并没有具体说明。实际上针对缓存图形的渲染处理具体逻辑如下:
_drawCachedSceneCanvas(context) {context.save();...var cacheCanvas = this._getCachedSceneCanvas();var ratio = cacheCanvas.pixelRatio;context.drawImage(cacheCanvas._canvas, 0, 0, cacheCanvas.width / ratio, cacheCanvas.height / ratio);context.restore();
}
drawScene(can, top) {...if (cachedSceneCanvas) {context.save();...this._drawCachedSceneCanvas(context);context.restore();} else {this._drawChildren('drawScene', canvas, top);}return this;
}
核心逻辑就是drawImage方法,对于缓存的图形实际上就是使用drawImage将其保存的CachedCanvas绘制到SceneCanvas中,而不是调用Canvas API进行具体的绘制。
总结
Konva缓存本质上就是创建位于内存中的Canvas图层,将当前图形绘制到CachedCanvas中,之后渲染时使用drawImage将整个CachedCanvas绘制到场景中,从而减少向CPU发送操作指令进而实现性能的提升。
从上面梳理逻辑知道每调用一次cache实例方法都会创建三个CachedCanvas并保存到对应属性中,如果图形很多,这是非常大的性能消耗,所以cache不能随便使用。实际上Konva官网也有cache的使用建议,可以去具体看看,这里就不再说明了。