• konva系列教程3:自定义图形


    大家好,我是前端西瓜哥。

    我们来看下怎么用 kanva 绘制自定义图形。

    现在我们要绘制一个菱形。所谓菱形,就是所有边相等的四边形。

    我们需要传入 (x, y) 设置菱形的左上角,并用 widthheight 设置菱形的宽高。

    图片

    Konva.Shape 类

    我们需要 new 一个 Konva.Shape 对象,并编写 senceFunc 函数,来描述图形。

    const diamond = new Konva.Shape({
      sceneFunc(ctx, shape) {
        // 绘制你自己自定义的形状
      },
      width: 60,
      height: 100
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    senceFunc 函数接收 konva 传入的 canva 上下文 ctx,和一个 shape 对象。

    ctx 是对 canvas 的 2d context 的增强,除了原本的属性和方法,还提供了 konva 专用的一些方法。我们需要用这个 ctx 来绘制一些东西。

    shape 则是一个形状实例,可以通过它获取一些属性值(比如宽高值),用来计算我们要绘制的图形的各点的坐标位置。

    菱形的绘制

    function sceneFunc(ctx, shape) {
      const w = shape.getAttr('width');
      const h = shape.getAttr('height');
    
      ctx.beginPath();
      ctx.moveTo(w / 2, 0);
      ctx.lineTo(w, h / 2);
      ctx.lineTo(w / 2, h);
      ctx.lineTo(0, h / 2);
      ctx.closePath();
     
      ctx.fillStrokeShape(shape);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    首先我们计算出菱形的各个端点位置,用 canvas 原生的 ctx.moveToctx.lineTo 依次相连,然后再调用 konva 增强的 ctx.fillStrokeShape(shape) 方法,对路径先进行填充,再描边。

    需要注意的是,x 和 y 不能参与计算,因为 konva 会做额外的位置偏移操作。如果你在这里的计算考虑了 x 和 y,就会导致实际的位置变成了预期的两倍。同样,scale 缩放值也不要参与计算。

    完整的写法为:

    const diamond = new Konva.Shape({
      x: 200,
      y: 20,
      width: 60,
      height: 100,
      fill: '#0288d1',
      sceneFunc(ctx, shape) {
        const w = shape.getAttr('width');
        const h = shape.getAttr('height');
        ctx.beginPath();
        ctx.moveTo(w / 2, 0);
        ctx.lineTo(w, h / 2);
        ctx.lineTo(w / 2, h);
        ctx.lineTo(0, h / 2);
        ctx.closePath();
    
        ctx.fillStrokeShape(shape);
      }
    });
    layer.add(diamond);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    我们可以简单封装一下,写一个 createDiamond 方法,方便多次调用。

    const createDiamond = (props) => {
      return new Konva.Shape({
        ...props,
        sceneFunc(ctx, shape) {
          const w = shape.getAttr('width');
          const h = shape.getAttr('height');
          ctx.beginPath();
          ctx.moveTo(w / 2, 0);
          ctx.lineTo(w, h / 2);
          ctx.lineTo(w / 2, h);
          ctx.lineTo(0, h / 2);
          ctx.closePath();
    
          ctx.fillStrokeShape(shape);
        }
      });
    };
    
    // 用法
    const diamond2 = createDiamond({
      x: 30,
      y: 30,
      width: 120,
      height: 100,
      fill: '#fff'
    });
    layer.add(diamond2);
    
    
    • 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

    sceneFunc 可能会在一秒内调用多次,最好不要做一些损耗性能的操作,比如创建一个很大的 image 对象。

    此外,scenceFunc 应该只做和绘制相关的操作,不建议在里面做一些其他的操作,比如绑定事件。

    我是前端西瓜哥,欢迎关注我,一起学习前端知识。

  • 相关阅读:
    【目标检测】Fast R-CNN论文详细解读
    【Python】解决CNN中训练权重参数不匹配size mismatch for fc.weight,size mismatch for fc.bias
    elment以及elementPlus选中组件出现黑框问题解决!!
    代码随想录算法训练营第62天|503.下一个更大元素II、42. 接雨水
    Hive学习(待续)
    Java设计模式-活动对象与访问者
    大数据在电力行业的应用案例100讲(二十六)-分布式ID微服务实现及应用
    Leetcode 2926. Maximum Balanced Subsequence Sum
    gRPC:一个性能强到爆的RPC框架
    C++ Reference: Standard C++ Library reference: Containers: array: array
  • 原文地址:https://blog.csdn.net/fe_watermelon/article/details/125472927