一个超好用的前端Canvas库-Konva

16,393 阅读4分钟

一个超好用的前端Canvas库-Konva

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

之前写过几篇关于Canvas的文章,一份八千字的Canvas入门指南,和Phaser入门,相对于这两个框架来说,直接使用Canvas对于初学者还是很麻烦,要考虑画笔的位置,什么时候要闭合路径,什么时候要保存状态,而Phaser又比较偏于游戏,这时候一个超级好用的Canvas库就出现了,Konva文档,你可以像操作Dom元素一样操作Canvas,下面我们来看看他的基础用法。

一、安装和使用

1. 安装

两种方式:

  • 可以通过npm进行安装,npm install konva
  • 通过script标签直接引入使用:<script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>

2. 层级关系

Konva有点类似于游戏开发中的场景搭建,根节点是一个Stage元素,Stage下面有许多Layer,Layer大的在上面,Layer下面可以放Group,大家可以理解为Div元素,Group下面就可以放我们绘制的图形等一些其他的元素,具体层级关系如下图:

image.png

3. 使用

  • 首先要创建一个根Dom节点,这代表这你所绘制的所有的图形都在这个Dom下面
<div id="app"></div>
  • 创建stage舞台
const stage = new Konva.Stage({
  container: 'app',
  width: 500,
  height: 500
});

在这里你可以自定义传入这个Canvas的大小,以及渲染Dom

  • 创建一个Layer,把这个Layer加入到Stage里面
const layer1 = new Konva.Layer();
stage.add(layer1);
  • 创建一个图形或者Group,把这个图形或者Group加入到Layer里面
const circle = new Konva.Circle({
  x: 200,
  y: 200,
  radius: 70,
  fill: 'red',
  stroke: 'black',
  strokeWidth: 4
})
layer1.add(circle)

总的来说,绘制流程就是:创建Stage->创建Layer->把Layer加入到Stage;创建图形或者Group->把图形或者Group加入到Layer里面,不断循环这一步

二、图形绘制

Konva不禁内置了原生Canvas的图形,还扩展了一些其它的图形,比如说椭圆、扇形、星形、环形、标签、箭头等

  • 椭圆
const ellipse = new Konva.Ellipse({
  x: 200,
  y: 200,
  radiusX: 100, // 椭圆的长轴
  radiusY: 50, // 椭圆的短轴
  stroke: 'red'
})
  • 环形
const ring = new Konva.Ring({
  x: 300,
  y: 300,
  stroke: 'red',
  innerRadius: 50,
  outerRadius: 70
})

image.png

是不是很方便,Konva内部还集成了很多图形,都是通过简单的调用就可以创建出来,大家可以去官方文档查看。

三、事件监听

我们正常的dom元素监听很简单:dom.addEventListener 就可以监听点击,等事件,Konva内部也封装了同样的方法,去像操作dom一样操作Canvas。

1. 监听点击事件

const rect = new Konva.Rect({
  x: 300,
  y: 300,
  width: 100,
  height: 80,
  stroke: 'red',
})

rect.on('click', function(e) {
  console.log(e);
})

我们可以看见打印输出可以拿到当前图形的信息,以及是什么事件触发:

image.png

2. 移入移出事件

rect.on('mouseover', function(e) {
  rect.fill('yellow');
})
rect.on('mouseleave', function(e) {
  rect.fill('white');
})

captured.gif

Konva还支持mouseovermouseoutmouseentermouseleavemousemovemousedownmouseupwheelclickdblclickdragstartdragmove,dragend 等事件,大家可以自己尝试。

四、拖拽

拖拽只需要给图形设置一个draggable: true就可以

1. 设置拖拽属性

const rect = new Konva.Rect({
  x: 300,
  y: 300,
  width: 100,
  height: 80,
  fill: '#00D2FF',
  stroke: 'black',
  draggable: true
})

captured (1).gif

  • 也可以拖拽一个组
const layer1 = new Konva.Layer();
stage.add(layer1);

const group = new Konva.Group({
  draggable: true
})
const rect1 = new Konva.Rect({
  x: 300,
  y: 300,
  width: 100,
  height: 80,
  fill: '#00D2FF',
  stroke: 'black'
})
const rect2 = new Konva.Rect({
  x: 400,
  y: 400,
  width: 50,
  height: 50,
  fill: 'red',
  stroke: 'black',
})

group.add(rect1)
group.add(rect2)

layer1.add(group)

captured (2).gif

大家就记住在Konva中万物皆可拽

2. 设置拖拽区域

我们可以使用 dragBoundFunc 属性定义一个区域,限制节点只能在这个区域内拖拽。

const rect1 = new Konva.Rect({
  x: 0,
  y: 0,
  width: 200,
  height: 200,
  fill: '#00D2FF',
  stroke: 'black'
})
const rect2 = new Konva.Rect({
  x: 0,
  y: 0,
  width: 50,
  height: 50,
  fill: 'red',
  stroke: 'black',
  draggable: true,
  dragBoundFunc(currentPos) {
    return {
       // 限制rect2只能在rect1内部拖拽
      x: currentPos.x > 150 ? 150 : currentPos.x,
      y: currentPos.y > 150 ? 150 : currentPos.y
    }
  }
})

layer1.add(rect1)
layer1.add(rect2)

dragBoundFunc 的形参是当前拖拽物体的坐标,并且限制区域也不一定是矩形,也可以是原型,椭圆等等。

captured (3).gif

Konva 还有很多好用的功能,大家可以去官网查看,比如颜色混合,滤镜功能,补间动画等等。