完整代码
以下是完整代码,从本实践中了解 Konva 的多事件处理,以及灵活运用 Konva 的 API。打破被文档从上到下的基础知识浅层了解,以实践达到灵活地对 Konva 的使用。
<body>
<div id="container"></div>
</body>
<script>
const stage = new Konva.Stage({
container: "container",
width: window.innerWidth,
height: window.innerHeight
});
const layer = new Konva.Layer();
let lastLine,
isPainting = false;
stage.on("mousedown touchstart", function (e) {
const pos = stage.getPointerPosition();
isPainting = true;
lastLine = new Konva.Line({
stroke: "#df4b26",
strokeWidth: 5,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
// 添加两次 x 和 y,否则绘制的 Line 不会显示
points: [pos.x, pos.y, pos.x, pos.y]
});
layer.add(lastLine);
});
stage.on("mouseup touchup", function () {
isPainting = false;
});
stage.on("mousemove touchmove", function (e) {
e.evt.preventDefault();
if (lastLine && isPainting) {
const pos = stage.getPointerPosition();
// 在这个 Line 的 points 数组中,拼接数组,并覆盖原本的 points,从而实现线条绘制功能。
// const newPos = lastLine.points().concat([pos.x, pos.y]);
// lastLine.points(newPos);
lastLine.points([...lastLine.points(), ...[pos.x, pos.y]]);
}
});
stage.add(layer);
</script>
业务分析
- 鼠标点击之后创建一个
Konva.Line
类。 - 鼠标在
Konva.Stage
上移动,更行 Line 的 points。 - 由,1 和 2 点得出,每一次鼠标点击之后的 Line 都是一个新的 Line,在鼠标点击之后移动是一个连续的过程,因此,需要记录在点击的回调函数中的 Line,以便于在移动事件回调函数中可以修改本次创建的 Line 的 points。
- points 是一个数组,记录了一条线从开始到结束的连续的点信息,因此,在每一次移动过后的区域,将原有的数组与鼠标最新的点数组合并起来。
代码分析
创建 Stage
Stage 是 Konva 一切的开始,它是一个容器,装载所有的图层(Layer),图层中装载许许多多的图形(Shape)。具体阅读博文:初入 H5 Canvas 框架 Konva.js。
const stage = new Konva.Stage({
container: "container",
width: window.innerWidth,
height: window.innerHeight
});
const layer = new Konva.Layer();
实际上 stage 相对于一个 div,div 下面是一个个 canvas 标签,即 layer。
定义全局变量
let lastLine,
isPainting = false;
- lastLine:一个绘制线条的整个流程所对应的 Line 对象,鼠标松开之后再次点击 stage 是重新创建一个新的 Line 对象,即一个流程结束。
- isPainting:表示一个线条绘制的流程是否结束,以便于下次移动时是否断开本次绘制,从而等待进入下一个绘制流程。
鼠标按下事件
Konva 支持一个 on 函数中添加多个事件,因此,为了适配多端,所以鼠标按下事件代码如下:
stage.on("mousedown touchstart", function (e) {
const pos = stage.getPointerPosition();
isPainting = true;
lastLine = new Konva.Line({
stroke: "#df4b26",
strokeWidth: 5,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
// 添加两次 x 和 y,否则绘制的 Line 不会显示
points: [pos.x, pos.y, pos.x, pos.y]
});
layer.add(lastLine);
});
stage.getPointerPosition()
:获取 stage(整个屏幕)的鼠标的坐标(x 和 y)。points: [pos.x, pos.y, pos.x, pos.y]
:点击之后,如果没有移动鼠标,至少留下一个点代表这一个线条绘制结束,但是没有移动,需要添加开始和结尾(即便是同一个位置),以便于 Konva 会渲染这一个 Line。layer.add(lastLine);
:这个 Line 要加入到 layer(图层)中才会被渲染到 H5 Canvas 中进行显示。
鼠标移动事件
stage.on("mousemove touchmove", function (e) {
e.evt.preventDefault();
if (lastLine && isPainting) {
const pos = stage.getPointerPosition();
// 在这个 Line 的 points 数组中,拼接数组,并覆盖原本的 points,从而实现线条绘制功能。
// const newPos = lastLine.points().concat([pos.x, pos.y]);
// lastLine.points(newPos);
lastLine.points([...lastLine.points(), ...[pos.x, pos.y]]);
}
});
lastLine.points([...lastLine.points(), ...[pos.x, pos.y]]);
:把原本的数组的 point 点信息与鼠标最新移动到的位置的 x 和 y 信息合并起来,并重新设置(覆盖)线条原本的 points 属性,从而实现和完成一条线的绘制流程。