• Konva离屏缓存


    前言

    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个Star
          let 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);
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    上面的实例就是创建11个Star图形,每个图形都会调用cache实例方法进行缓存。

    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,
        });
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    缓存图形的渲染

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    核心逻辑就是drawImage方法,对于缓存的图形实际上就是使用drawImage将其保存的CachedCanvas绘制到SceneCanvas中,而不是调用Canvas API进行具体的绘制。

    总结

    Konva缓存本质上就是创建位于内存中的Canvas图层,将当前图形绘制到CachedCanvas中,之后渲染时使用drawImage将整个CachedCanvas绘制到场景中,从而减少向CPU发送操作指令进而实现性能的提升。

    从上面梳理逻辑知道每调用一次cache实例方法都会创建三个CachedCanvas并保存到对应属性中,如果图形很多,这是非常大的性能消耗,所以cache不能随便使用。实际上Konva官网也有cache的使用建议,可以去具体看看,这里就不再说明了。

  • 相关阅读:
    CDATA 解决xml 大于小于的转换问题
    【渲染数学-01】如何模拟静态流(上)
    Python -- I/O编程
    JAVA卓越导师双选系统计算机毕业设计Mybatis+系统+数据库+调试部署
    Zabbix监控系统 自定义监控项、自动发现与自动注册
    同步、异步
    学习Hadoop(一)了解Haddop及搭建伪分布式Hadoop1.0
    解码2022中国网安强星丨注重攻防实战化验证,长亭以安全原子能力打造体系化安全
    欧美风商务简约通用PPT模板
    如何在Vim中使用内置的Make命令来编译程序?
  • 原文地址:https://blog.csdn.net/s1879046/article/details/133347072