1. Konva
konva是什么?根据官方文档描述:
Konva
是一个HTML5 Canvas JavaScript 框架,它通过对 2d context 的扩展实现了在桌面端和移动端的可交互性。Konva 提供了高性能的动画,补间,节点嵌套,布局,滤镜,缓存,事件绑定(桌面/移动端)等等功能。你可以使用 Konva 在舞台上绘制图形,给图形添加事件,移动、缩放和旋转图形并且支持高性能的动画即使包含数千个图形。
基础 | Konva 中文文档 中文API (bluehymn.com)
也就是说,konva是一个canvas库,方便我们在项目中快速构建canvas图形,以实现高质量的图形效果。下面我将演示konva的基础用法。
2. Konva工作原理
Konva 的对象是以一颗树的形式保存的,
Konva.Stage
是树的根节点,Stage
子节点是用户创建的图层 (Konva.Layer
)。每一个 layer 有两个
渲染器: 场景渲染器 和 图像命中检测渲染器。场景渲染器输出你所看见的内容,图像命中渲染器在隐藏的 canvas 里用于高性能的检测事件。
图层可以包含图形、嵌套图形的组、嵌套组的组。
Stage
(舞台),layers
(图层),groups
(组),和shapes
(图形) 都是虚拟节点,类似于 HTML 的 DOM 节点。
节点结构图1-1:
Stage
|
+------+------+
| |
Layer Layer
| |
+-----+-----+ Shape
| |
Group Group
| |
+ +---+---+
| | |
Shape Group Shape
|
+
|
Shape
3. 创建stage
// (1)创建舞台stage[作为一个容器,承载图层layer]
var stage = new Konva.Stage({
container: 'container', // id of container
width: 500, height: 500 }); // (2)创建图层layer,用来盛放group&shape var layer = new Konva.Layer(); // (3)创建组group,group可以盛放shape作为一个整体操作 var group = new Konva.Group({ x: 0, y: 0, draggable: true }) // (4)创建图形shape,图形作为konva中的最基本的单位 // [如 rect/circle/ellipse/line/image/text等] var circle = new Konva.Circle({ x: stage.width() / 2, y: stage.height() / 2, radius: 70, fill: ‘red’, stroke: ‘black’, strokeWidth: 4 }); //(5) // 添加circle到group中 layer.add(circle); // 添加group到layer中 layer.add(circle); // 最后添加layer到stage中 stage.add(layer); // 执行绘制 layer.draw();
[注*]图层layer、组group、和图形shape可以有多个,可以不创建组,把图形直接添加到图层中,也可以有多个组,组和组可以是并列关系,也可以是嵌套关系。
4. 拖拽功能
托拽功能是本人最近项目使用konva的主要原因,我们项目想实现一个类似与华容道游戏的拖拽功能。
// (1)以rect为例,添加draggable属性并设置为true即可实现元素的拖拽,默认值false
// (2)然后给box[rect]添加事件监听,这样在触发拖拽、悬停等事件是可以监听到,并执行相应的回调
var box = new Konva.Rect({
x: rectX,
y: rectY,
width: 100,
height: 50,
fill: '#00D2FF',
draggable: true
});
// 鼠标悬停修改鼠标样式
box.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
box.on('mouseout', function() {
document.body.style.cursor = 'default';
});
可设置拖拽属性的元素有很多,比如图形、组、图层、甚至舞台都可以设置拖拽属性。合同拽相关的属性,还有一个拖拽区域,通常是限制在父级元素一定范围内拖动(也就是设置边界)。根据我的实践,图形的拖拽区域可以设置dragBoundFunc来实现,但是,组group是无法通过设置dragBoundFunc来实现拖拽区域限制的(虽然我看文档里面是支持的),通常是dragBoundFunc添加上去了,但是没有效果,因此我用另外的方式限制组的拖拽区域————事件绑定(dragmove/dragend)。
// (1)以下示例演示,text元素可以在水平区域拖拽
var vbox = new Konva.Text({
x: 150,
y: 70,
draggable: true,
fontSize: 24,
fontFamily: 'Calibri',
text: 'horizontal',
fill: 'black',
padding: 15,
dragBoundFunc: function(pos) {
return {
x: pos.x,
y: this.absolutePosition().y
};
}
});
// (2)group的拖拽区域限制
var group = new Konva.Group({
x: 0,
y: 0,
draggable: true
})
// 根据group和其父元素的坐标、宽高,分别限制其对应的上下左右边界,
// 以达到限制区域的目的
group.on('dragmove', function (e) {
var target = e.target
var targetRect = e.target.getClientRect()
// 限制左边界&上边界
targetRect.x
!!!
划重点,关于拖拽重叠判断:
Konva对重叠的判断仅限与基础图形shape,并且通过shape.getClientRect()方法获取元素的外轮廓,该外轮廓会被简化成长方形(reat),即便原来的图形是圆形、椭圆、多边形。同理,group判断重叠也会被简化成长方体,因此导致重叠判断不准确。有待konva进一步完善,或者项目引入其他插件的帮忙,实现想要的效果(粗略知道有几种插件,还有待继续探索)。
// 启用元素拖拽
rect.draggable(true);
// 监听元素拖拽事件
rect.on('dragmove', () => {
console.log('Rect is being dragged');
});
// 判断元素是否重叠
const isOverlap = Konva.Util.haveIntersection(rect.getClientRect(), circle.getClientRect());
console.log('Rect and Circle are overlapping:', isOverlap);
5. 写在最后
Konva这小东西挺有意思,在一些特殊业务需求下显得十分好用,同时上手也不难,文档十分丰富,希望看懂本文的朋友们能激起一些学习兴趣,或者帮助你解决一些小问题,那便是这篇分享文的意义。
最后最后:我是菜鸟,轻点喷我,最好不喷,友好交流哈~同时以上内容除官方文档外都是本人短时间内浅显的理解,有不足之处欢迎朋友指出,必会第一时间改正。
第一次掘金发文,诚惶诚恐~ see you~
彩蛋
chatGpt帮我写博客 ×
chatGpt帮我博客取标题 √
文章来源于互联网:释放KonvaJS的创造力:从画布到杰作
1. Konva2. Konva工作原理3. 创建stage4. 拖拽功能5. 写在最后