vue+konva.js图片数据标注多边形矩形---demo2.0。添加了其他功能和完善了代码。
vue+konva.js图片数据标注多边形矩形---demo2.0。添加了其他功能和完善了代码。
·
文章目录
前言
vue+konva.js(未使用vue-konva),实现数据标注矩形和多边形功能
demo2添加功能如下:
- 自适应画布
- 新矩形和多边形(顶点已经约束不能拖拽出画布)
- ctrl+z撤销和del删除
- 鼠标滚轮放大和缩小
- 检查图形是否规范
计划添加:约束图形不能拖拽出画布功能
一、 自适应画布
二、新矩形和多边形
三、ctrl+z撤销和del删除
四、鼠标滚轮放大和缩小
五、检查图形是否规范
六、代码
<!--
* @Descripttion:
* @version:
* @Author: yangxing
* @Date: 2022-07-14 11:49:34
* @LastEditors: yangxing
* @LastEditTime: 2022-08-13 15:22:02
-->
<template>
<div style="width: 80vw">
<el-button-group>
<el-button size="mini" @click="selectTool(0)">矩形</el-button>
<el-button size="mini" @click="selectTool(1)">多边形</el-button>
</el-button-group>
<div id="map" ref="map"></div>
</div>
</template>
<script>
import { text } from "body-parser";
import Konva from "konva";
export default {
name: "MyKonva",
data() {
return {
rect: false,
poly: false,
stage: null,
layer: null,
shape: null,
image: { src: null },
currentTool: "",
toolObject: [
{
name: "rect",
type: "rect",
/* 矩形颜色 */ color: "#75fb4c",
/* 边框颜色 */ lineColor: "#75fb4c",
/* 顶点颜色 */ anchorColor: "green",
},
{
name: "poly",
type: "poly",
/* 矩形颜色 */ color: "#E63F00",
/* 边框颜色 */ lineColor: "#E63F00 ",
/* 顶点颜色 */ anchorColor: "red",
},
],
drawing: false, //一开始不能绘画
currentDrawingShape: null, //现在绘画的图形
rectPoints: [], //存储矩形的各个顶点的数组
polygonPoints: [], //存储绘画多边形各个顶点的数组
stageWidth: 0, //舞台宽
stageHeight: 0, //舞台高
scale: 1, //窗口变化的缩放比例
currentDel: null, //删除对象
currentCancel: null, //删除对象
mouseOffsetX: 0,
mouseOffsetY: 0,
mouseOffsetList: [],
label: "label", //标注
};
},
methods: {
//选择工具
selectTool(index) {
//如果还在绘画,但选择工具,则将正在绘画的图形删除
if (this.drawing) {
this.currentDrawingShape.getParent().destroy();
this.rectPoints = [];
this.polygonPoints = [];
this.drawing = false;
this.layer.draw();
}
this.currentTool = this.toolObject[index];
},
//重新调整画布
resizeStage() {
this.scale = this.$refs.map.clientWidth / this.stageWidth;
this.stage.width(this.stageWidth * this.scale);
this.stage.height(this.stageHeight * this.scale);
this.stage.scale({ x: this.scale, y: this.scale });
//维持原来大小
this.layer.find("Circle").forEach((element) => {
element.setAttr("radius", 5 / this.scale / this.layer.scaleX());
});
this.layer.find("Label").forEach((element) => {
element.getText().setAttrs({
fontSize: 16 / this.scale / this.layer.scaleX(),
padding: 1 / this.scale / this.layer.scaleX(),
});
});
this.stage.draw();
},
/**
*初始化konva舞台
*/
initKonvaStage() {
//1实例化stage层
this.stageWidth = this.$refs.map.clientWidth;
this.stageHeight = this.$refs.map.clientHeight;
this.stage = new Konva.Stage({
container: "map",
width: this.stageWidth,
height: this.stageHeight,
ignoreStroke: true,
});
this.stage.container().style.cursor = "crosshair";
var vc_this = this;
//2实例化layer层
this.layer = new Konva.Layer();
//3添加layer层
this.stage.add(this.layer);
var imageObj = new Image();
imageObj.onload = function () {
vc_this.shape = new Konva.Image({
image: imageObj,
width: vc_this.stageWidth,
height: vc_this.stageHeight,
});
vc_this.layer.add(vc_this.shape);
};
imageObj.src = require("../assets/dog.jpeg");
//给***舞台***绑定事件
this.stageBindEvent(this);
},
/**
* 舞台绑定的事件
* @param vc_this
*/
stageBindEvent(vc_this) {
//鼠标按下
this.stage.on("mousedown", (e) => {
//鼠标左键开始
if (e.evt.button == 0) {
if (e.target === vc_this.stage) {
vc_this.$message({
message: "请选择图片!",
type: "warning",
center: true,
duration: 1000,
});
return;
}
//图形起始点只能在图片层上
if (e.target === vc_this.shape) {
//开始初始绘画
vc_this.stageMousedown(vc_this.currentTool, e);
return;
}
//允许后续点绘画在其他图形上
if (vc_this.drawing) {
vc_this.stageMousedown(vc_this.currentTool, e);
return;
}
} else if (e.evt.button == 2) {
if (vc_this.polygonPoints.length != 0) {
//最好使用konva提供的鼠标xy点坐标
var mousePos = vc_this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / vc_this.scale - vc_this.layer.getAttr("x")) /
vc_this.layer.scaleX(),
y =
(mousePos.y / vc_this.scale - vc_this.layer.getAttr("y")) /
vc_this.layer.scaleY();
//group继续添加多边形的点
vc_this.drawCircle(
vc_this.currentTool,
x,
y,
vc_this.currentDrawingShape.getParent(),
vc_this.polygonPoints
);
vc_this.polygonPoints.push(x);
vc_this.polygonPoints.push(y);
//绘画多边形
vc_this.currentDrawingShape.setAttr("points", vc_this.polygonPoints);
//group继续添加多边形的边
vc_this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === vc_this.currentTool.name + "line";
})[0]
.setAttr("points", vc_this.polygonPoints);
//判断是否是只有两个点的多边形,如果起点和终点相同,不允许绘画
if (
vc_this.currentDrawingShape.points().length == 2 ||
vc_this.currentDrawingShape.points().length == 4
) {
vc_this.drawing = false;
vc_this.currentDrawingShape.getParent().destroy();
vc_this.polygonPoints = [];
vc_this.$message({
message: "顶点数必须大于2个!",
type: "warning",
center: true,
duration: 1000,
});
return;
}
e.cancelBubble = true;
this.drawing = false;
}
}
});
//鼠标移动
this.stage.on("mousemove", (e) => {
if (vc_this.currentTool && vc_this.drawing) {
//绘画中
vc_this.stageMousemove(vc_this.currentTool);
}
});
//鼠标放开
vc_this.stage.on("mouseup", (e) => {
if (e.evt.button == 0) {
if (vc_this.currentTool && vc_this.drawing) {
vc_this.stageMouseup(vc_this.currentTool, e);
}
} else if (e.evt.button == 2) {
if (
vc_this.currentTool &&
!vc_this.drawing &&
vc_this.polygonPoints.length != 0
) {
vc_this.stageMouseup(vc_this.currentTool, e);
}
}
});
//鼠标滚轮事件
vc_this.stage.on("wheel", (e) => {
if (vc_this.shape) {
var step = 0.03; // 每次缩放的比例
var mousePos = vc_this.stage.getPointerPosition();
var x = mousePos.x / vc_this.scale,
y = mousePos.y / vc_this.scale;
if (e.evt.wheelDelta > 0) {
vc_this.mouseOffsetX = x * step;
vc_this.mouseOffsetY = y * step;
// 放大
vc_this.layer.scaleX(vc_this.layer.scaleX() + step);
vc_this.layer.scaleY(vc_this.layer.scaleY() + step);
vc_this.layer.move({ x: -vc_this.mouseOffsetX, y: -vc_this.mouseOffsetY });
vc_this.mouseOffsetList.push(vc_this.mouseOffsetX, vc_this.mouseOffsetY);
//维持原来大小
vc_this.layer.find("Circle").forEach((element) => {
element.setAttr("radius", 5 / vc_this.scale / vc_this.layer.scaleX());
});
vc_this.layer.find("Label").forEach((element) => {
element.getText().setAttrs({
fontSize: 16 / vc_this.scale / vc_this.layer.scaleX(),
padding: 1 / vc_this.scale / vc_this.layer.scaleX(),
});
});
vc_this.stage.draw();
} else if (e.evt.wheelDelta < 0 && vc_this.mouseOffsetList.length != 0) {
vc_this.layer.scaleX(vc_this.layer.scaleX() - step);
vc_this.layer.scaleY(vc_this.layer.scaleY() - step);
vc_this.mouseOffsetY = vc_this.mouseOffsetList.pop();
vc_this.mouseOffsetX = vc_this.mouseOffsetList.pop();
vc_this.layer.move({ x: vc_this.mouseOffsetX, y: vc_this.mouseOffsetY });
//维持原来大小
vc_this.layer.find("Circle").forEach((element) => {
element.setAttr("radius", 5 / vc_this.scale / vc_this.layer.scaleX());
});
vc_this.layer.find("Label").forEach((element) => {
element.getText().setAttrs({
fontSize: 16 / vc_this.scale / vc_this.layer.scaleX(),
padding: 1 / vc_this.scale / vc_this.layer.scaleX(),
});
});
vc_this.stage.draw();
}
}
});
//舞台快捷键
var container = this.stage.container();
container.tabIndex = 1;
container.focus();
container.addEventListener("keydown", (e) => {
//删除的快捷键
if (e.keyCode === 46) {
if (this.currentDel) {
this.currentDel.destroy();
this.currentDel = null;
this.$message({
message: "删除成功!",
type: "success",
center: true,
duration: 1000,
});
}
}
vc_this.stage.container().style.cursor = "crosshair";
e.preventDefault();
vc_this.layer.draw();
});
container.addEventListener("keydown", (e) => {
//撤销的快捷键(ctrl+z)
if (e.ctrlKey == true && e.keyCode == 90) {
switch (this.currentTool.type) {
case "rect":
//正在绘画,直接删除group
if (this.drawing) {
this.currentDrawingShape.getParent().destroy();
this.rectPoints = [];
this.drawing = false;
} else {
//绘画完成,直接删除group
this.currentCancel.destroy();
this.rectPoints = [];
this.drawing = false;
}
break;
case "poly":
//删除点
var y = this.polygonPoints.pop();
var x = this.polygonPoints.pop();
//如果撤销的是第一个点,直接删除group
if (this.drawing && this.polygonPoints.length == 0) {
this.currentCancel.destroy();
this.drawing = false;
} //如果是已绘画完的多边形
else if (!this.drawing && this.polygonPoints.length == 0) {
if (this.currentCancel) {
this.currentCancel.destroy();
this.currentCancel = null;
this.$message({
message: "删除成功!",
type: "success",
center: true,
duration: 1000,
});
}
} else {
this.currentCancel
.getChildren((node) => {
return node.x() == x && node.y() == y;
})[0]
.destroy();
//重新绘画多边形
//最好使用konva提供的鼠标xy点坐标
var mousePos = this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) /
this.layer.scaleX(),
y =
(mousePos.y / this.scale - this.layer.getAttr("y")) /
this.layer.scaleY();
var tempPoints = this.polygonPoints.concat();
tempPoints.push(x);
tempPoints.push(y);
//修改多边形的点
this.currentCancel
.find("." + this.currentTool.name + "poly")[0]
.setAttr("points", tempPoints);
//重新绘画多边形的边
this.currentCancel
.find("." + this.currentTool.name + "line")[0]
.setAttr("points", tempPoints);
}
break;
}
}
vc_this.stage.container().style.cursor = "crosshair";
e.preventDefault();
vc_this.layer.draw();
});
},
/**
* 在舞台上鼠标点下发生的事件
* @param currentTool 当前选择的工具
* @param e 传入的event对象
*/
stageMousedown(currentTool, e) {
if (currentTool.type == null) {
this.$message({
message: "请选择标注工具!",
type: "warning",
center: true,
duration: 1000,
});
return;
}
switch (currentTool.type) {
case "rect":
//最好使用konva提供的鼠标xy点坐标
var mousePos = this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) / this.layer.scaleX(),
y = (mousePos.y / this.scale - this.layer.getAttr("y")) / this.layer.scaleY();
//拖拽组
var group = new Konva.Group({
name: currentTool.name + "group",
draggable: true,
});
//添加矩形的初始点
var rectTopLeft = this.drawCircle(currentTool, x, y, group, this.rectPoints);
//修改矩形顶点名称
rectTopLeft.name("rectTopLeft");
//绘制矩形
this.drawRect(currentTool, x, y, group);
//添加矩形的边
this.rectPoints.push(x);
this.rectPoints.push(y);
this.drawLine(currentTool, this.rectPoints, group);
this.layer.add(group);
this.currentCancel = group;
this.layer.draw();
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
break;
case "poly":
//如果数组长度小于2,初始化多边形和顶点,使它们成为一组,否则什么都不做
if (this.polygonPoints.length < 2) {
//最好使用konva提供的鼠标xy点坐标
var mousePos = this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) / this.layer.scaleX(),
y =
(mousePos.y / this.scale - this.layer.getAttr("y")) / this.layer.scaleY();
//拖拽组
var group = new Konva.Group({
name: currentTool.name + "group",
draggable: false,
});
this.polygonPoints = [x, y];
//添加多边形的点
this.drawCircle(currentTool, x, y, group, this.polygonPoints);
//绘画多边形
this.drawPolygon(currentTool, this.polygonPoints, group);
//添加多边形的边
this.drawLine(currentTool, this.polygonPoints, group);
this.layer.add(group);
this.currentCancel = group;
//添加标签
var label = this.drawLabel(currentTool, x, y, group, this.label);
label.hide();
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
this.layer.draw();
} //多边形增加顶点
else {
//最好使用konva提供的鼠标xy点坐标
var mousePos = this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) / this.layer.scaleX(),
y =
(mousePos.y / this.scale - this.layer.getAttr("y")) / this.layer.scaleY();
//group继续添加多边形的点
this.drawCircle(
currentTool,
x,
y,
this.currentDrawingShape.getParent(),
this.polygonPoints
);
this.polygonPoints.push(x);
this.polygonPoints.push(y);
//绘画多边形
this.currentDrawingShape.setAttr("points", this.polygonPoints);
//group继续添加多边形的边
this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "line";
})[0]
.setAttr("points", this.polygonPoints);
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
this.layer.draw();
}
break;
default:
break;
}
this.drawing = true;
},
/**
* 鼠标在舞台上移动事件
* @param currentTool 当前选择的工具
* @param e 传入的event对象
*/
stageMousemove(currentTool) {
switch (currentTool.type) {
case "rect":
this.stage.container().style.cursor = "crosshair";
//矩形初始化,鼠标移动操作
//最好使用konva提供的鼠标xy点坐标
var mousePos = this.stage.getPointerPosition();
//考虑鼠标缩放
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) / this.layer.scaleX(),
y = (mousePos.y / this.scale - this.layer.getAttr("y")) / this.layer.scaleY();
var point1 = [this.rectPoints[0], this.rectPoints[1]];
var point2 = [x, this.rectPoints[1]];
var point3 = [x, y];
var point4 = [this.rectPoints[0], y];
//如果矩形顶点不足创建顶点
if (this.rectPoints.length < 8) {
this.rectPoints = point1.concat(point2, point3, point4);
//删除第一个顶点
this.currentDrawingShape
.getParent()
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.destroy();
var rectTopLeft = this.drawCircle(
currentTool,
point1[0],
point1[1],
this.currentDrawingShape.getParent(),
this.rectPoints
);
rectTopLeft.name("rectTopLeft");
//添加标签
var label = this.drawLabel(
currentTool,
point1[0],
point1[1],
this.currentDrawingShape.getParent(),
this.label
);
label.hide();
var rectTopRight = this.drawCircle(
currentTool,
point2[0],
point2[1],
this.currentDrawingShape.getParent(),
this.rectPoints
);
rectTopRight.name("rectTopRight");
var rectBottomRight = this.drawCircle(
currentTool,
point3[0],
point3[1],
this.currentDrawingShape.getParent(),
this.rectPoints
);
rectBottomRight.name("rectBottomRight");
var rectBottomLeft = this.drawCircle(
currentTool,
point4[0],
point4[1],
this.currentDrawingShape.getParent(),
this.rectPoints
);
rectBottomLeft.name("rectBottomLeft");
}
//修改矩形的顶点
this.rectPoints[2] = point2[0];
this.rectPoints[3] = point2[1];
this.rectPoints[4] = point3[0];
this.rectPoints[5] = point3[1];
this.rectPoints[6] = point4[0];
this.rectPoints[7] = point4[1];
this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === "rectTopRight";
})[0]
.setAttrs({
x: point2[0],
y: point2[1],
});
this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === "rectBottomRight";
})[0]
.setAttrs({
x: point3[0],
y: point3[1],
});
this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === "rectBottomLeft";
})[0]
.setAttrs({
x: point4[0],
y: point4[1],
});
//添加矩形的边
this.currentDrawingShape
.getParent()
.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "line";
})[0]
.setAttr("points", this.rectPoints);
this.currentDrawingShape.setAttrs({
width: x - this.rectPoints[0],
height: y - this.rectPoints[1],
});
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
break;
case "poly":
this.stage.container().style.cursor = "crosshair";
//多边形初始化后,如果数组长度大于2,鼠标移动时,实时更新下一个点
if (this.polygonPoints.length >= 2) {
var mousePos = this.stage.getPointerPosition();
var x =
(mousePos.x / this.scale - this.layer.getAttr("x")) / this.layer.scaleX(),
y =
(mousePos.y / this.scale - this.layer.getAttr("y")) / this.layer.scaleY();
var tempPoints = this.polygonPoints.concat([]);
tempPoints.push(x);
tempPoints.push(y);
//更新多边形的线
this.currentDrawingShape
.getParent()
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "line";
})[0]
.setAttr("points", tempPoints);
//更新多边形
this.currentDrawingShape.setAttr("points", tempPoints);
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
}
break;
default:
break;
}
this.layer.draw();
},
/**
* 鼠标在舞台弹起
* @param currentTool 当前选择的工具
* @param e 传入的event对象
*/
stageMouseup(currentTool, e) {
switch (currentTool.type) {
case "rect":
this.currentDrawingShape = this.currentDrawingShape.getParent();
if (
this.currentDrawingShape.getChildren((element) => {
return element.getClassName() === "Circle";
}).length < 4
) {
this.drawing = false;
this.currentDrawingShape.destroy();
this.rectPoints = [];
this.$message({
message: "矩形过小!",
type: "warning",
center: true,
duration: 1000,
});
return;
} else {
//显示标签
this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "label";
})[0]
.show();
this.rectPoints = [];
this.drawing = false;
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
}
break;
case "poly":
if (e.evt.button == 2) {
this.currentDrawingShape = this.currentDrawingShape.getParent();
//显示标签
this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "label";
})[0]
.show();
//形成多边形直接发送数据
this.$message({
message: "成功!",
type: "success",
center: true,
duration: 1000,
});
//右键弹起
this.polygonPoints = [];
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
}
break;
default:
break;
}
this.layer.draw();
},
/**
* 多边形圆形
* @param //x x坐标
* @param //y y坐标
*/
drawCircle(currentTool, x, y, group, shapePoints) {
var vc_this = this;
var circle = new Konva.Circle({
name: currentTool.name + "circle",
x: x,
y: y,
radius: 5 / this.scale / this.layer.scaleX(),
visible: true, //是否显示
fill: currentTool.anchorColor,
stroke: currentTool.anchorColor,
draggable: false,
strokeWidth: 0.5,
strokeScaleEnabled: false,
//增加点击区域
hitStrokeWidth: 8 / this.scale / this.layer.scaleX(),
//设置拖动区域,不能超过舞台大小
dragBoundFunc: function (pos) {
//左上角
if (pos.x < 0 && pos.y < 0) {
return {
x: 0,
y: 0,
};
} //左侧
else if (pos.x <= 0 && 0 <= pos.y && pos.y <= vc_this.stage.height()) {
return {
x: 0,
y: pos.y,
};
}
//左下角
else if (pos.x < 0 && pos.y > vc_this.stage.height()) {
return {
x: 0,
y: vc_this.stage.height(),
};
} //下侧
else if (
0 <= pos.x &&
pos.x <= vc_this.stage.width() &&
pos.y > vc_this.stage.height()
) {
return {
x: pos.x,
y: vc_this.stage.height(),
};
} //右下角
else if (pos.x > vc_this.stage.width() && pos.y > vc_this.stage.height()) {
return {
x: vc_this.stage.width(),
y: vc_this.stage.height(),
};
}
//右侧
else if (
pos.x > vc_this.stage.width() &&
0 <= pos.y &&
pos.y <= vc_this.stage.height()
) {
return {
x: vc_this.stage.width(),
y: pos.y,
};
}
//右上角
else if (pos.x > vc_this.stage.width() && pos.y < 0) {
return {
x: vc_this.stage.width(),
y: 0,
};
} //上侧
else if (0 <= pos.x && pos.x <= vc_this.stage.width() && pos.y < 0) {
return {
x: pos.x,
y: 0,
};
}
},
});
group.add(circle);
var xChange, yChange;
circle.on("mouseover", (e) => {
vc_this.stage.container().style.cursor = "pointer";
});
circle.on("mousedown", (e) => {
if (!vc_this.drawing) {
circle.draggable(true);
//将现在绘画的对象改为group
vc_this.currentDrawingShape = circle.getParent();
} else {
circle.draggable(false);
}
e.cancelBubble = true;
});
circle.on("mouseleave", (e) => {
vc_this.stage.container().style.cursor = "crosshair";
});
circle.on("dragstart", (e) => {
switch (currentTool.type) {
case "rect":
vc_this.currentDrawingShape = circle.getParent();
break;
case "poly":
//查找拖拽了多边形的哪个点
for (var i = 0; i < shapePoints.length; i += 2) {
if (
circle.getAttr("x") == shapePoints[i] &&
circle.getAttr("y") == shapePoints[i + 1]
) {
xChange = i;
yChange = i + 1;
break;
}
}
break;
default:
break;
}
});
circle.on("dragmove", (e) => {
switch (currentTool.type) {
case "rect":
//查找拖拽了多边形的哪个点
var circleName = circle.name();
//修改点位置
var anchorX = circle.getX();
var anchorY = circle.getY();
switch (circleName) {
case "rectTopLeft":
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopRight";
})[0]
.y(anchorY);
//修改线
shapePoints[3] = anchorY;
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectBottomLeft";
})[0]
.x(anchorX);
shapePoints[6] = anchorX;
//更改拖拽点的位置来改变线段
shapePoints[0] = anchorX;
shapePoints[1] = anchorY;
break;
case "rectTopRight":
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.y(anchorY);
shapePoints[1] = anchorY;
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectBottomRight";
})[0]
.x(anchorX);
shapePoints[4] = anchorX;
//更改拖拽点的位置来改变线段
shapePoints[2] = anchorX;
shapePoints[3] = anchorY;
break;
case "rectBottomRight":
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectBottomLeft";
})[0]
.y(anchorY);
shapePoints[7] = anchorY;
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopRight";
})[0]
.x(anchorX);
shapePoints[2] = anchorX;
//更改拖拽点的位置来改变线段
shapePoints[4] = anchorX;
shapePoints[5] = anchorY;
break;
case "rectBottomLeft":
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectBottomRight";
})[0]
.y(anchorY);
shapePoints[5] = anchorY;
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.x(anchorX);
shapePoints[0] = anchorX;
//更改拖拽点的位置来改变线段
shapePoints[6] = anchorX;
shapePoints[7] = anchorY;
break;
}
//隐藏label
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "label";
})[0]
.hide();
//修改矩形位置和大小
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "rect";
})[0]
.position(
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.position()
);
var width =
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopRight";
})[0]
.getX() -
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.getX();
var height =
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectBottomLeft";
})[0]
.getY() -
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === "rectTopLeft";
})[0]
.getY();
if (width && height) {
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "rect";
})[0]
.width(width);
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "rect";
})[0]
.height(height);
}
break;
case "poly":
//隐藏label
vc_this.currentDrawingShape
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "label";
})[0]
.hide();
var x = circle.x();
var y = circle.y();
//更改拖拽点的位置
shapePoints[xChange] = x;
shapePoints[yChange] = y;
break;
default:
break;
}
});
circle.on("dragend", (e) => {
switch (currentTool.type) {
case "rect":
//修改标签位置
var rect = vc_this.currentDrawingShape.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "rect";
})[0];
var label = vc_this.currentDrawingShape.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "label";
})[0];
label.setAttrs({
x:
(rect.getClientRect().x / vc_this.scale - vc_this.layer.getAttr("x")) /
vc_this.layer.scaleX(),
y:
(rect.getClientRect().y / vc_this.scale - vc_this.layer.getAttr("y")) /
vc_this.layer.scaleX(),
visible: true,
});
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
circle.draggable(false);
break;
case "poly":
//修改标签位置
var poly = vc_this.currentDrawingShape.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "poly";
})[0];
var label = vc_this.currentDrawingShape.getChildren((node) => {
return node.getAttr("name") === currentTool.name + "label";
})[0];
label.setAttrs({
x: poly.points()[0],
y: poly.points()[1],
visible: true,
});
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
circle.draggable(false);
break;
default:
break;
}
vc_this.$message({
message: "修改成功!",
type: "success",
center: true,
duration: 1000,
});
e.cancelBubble = true;
});
return circle;
},
drawLabel(currentTool, x, y, group, labelText) {
var label = new Konva.Label({
x: x,
y: y,
name: currentTool.name + "label",
visible: true,
opacity: 1,
});
var tag = new Konva.Tag({
fill: currentTool.color,
});
var text = new Konva.Text({
text: labelText,
fontFamily: "Calibri",
fontSize: 16 / this.scale / this.layer.scaleX(),
padding: 1 / this.scale / this.layer.scaleX(),
fill: "#fff",
});
label.add(tag);
label.add(text);
group.add(label);
return label;
},
/**
* 线
* @param //points 坐标数组
*/
drawLine(currentTool, points, group) {
var line = new Konva.Line({
name: currentTool.name + "line",
points: points,
stroke: currentTool.lineColor,
strokeWidth: 1,
visible: true,
draggable: false,
closed: true,
strokeScaleEnabled: false,
opacity: 1, //透明度
});
group.add(line);
return line;
},
/**
*多边形
@param currentTool
* @param points 多边形绘画的各个顶点,类型数组
*/
drawPolygon(currentTool, points, group) {
var poly = new Konva.Line({
name: currentTool.name + "poly",
points: points,
/* fill: currentTool.color, */
stroke: currentTool.color,
strokeWidth: 1,
draggable: false,
opacity: 0.5,
lineCap: "round",
lineJoin: "round",
closed: true,
strokeScaleEnabled: false,
});
this.currentDrawingShape = poly;
group.add(poly);
var vc_this = this;
poly.getParent().on("mouseleave", (e) => {
vc_this.stage.container().style.cursor = "crosshair";
});
poly.getParent().on("mousedown", (e) => {
if (e.evt.button == 0) {
//绘画结束
if (!vc_this.drawing) {
vc_this.stage.container().style.cursor = "move";
//设置现在绘画节点的对象为该多边形和顶点的组
vc_this.currentDrawingShape = poly.getParent();
// 如果要让顶点和多边形一起拖拽,必须设置,多边形不能被拖拽
poly.setAttr("draggable", false);
poly.getParent().setAttr("draggable", true);
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
//添加删除撤销对象
this.currentDel = vc_this.currentDrawingShape;
this.currentCancel = vc_this.currentDrawingShape;
vc_this.layer.draw();
} else {
vc_this.stage.container().style.cursor = "crosshair";
poly.getParent().setAttr("draggable", false);
}
}
});
poly.getParent().on("dragend", (e) => {
if (currentTool.name === vc_this.toolObject[1].name) {
var updatePoints = [];
var polyPoints = poly.points();
for (var i = 0; i < polyPoints.length / 2; i++) {
updatePoints.push(polyPoints[i * 2] + poly.getParent().x());
updatePoints.push(polyPoints[i * 2 + 1] + poly.getParent().y());
}
poly.getParent().destroy();
vc_this.currentDrawingShape = vc_this.drawGroup(
updatePoints,
vc_this.toolObject[1]
);
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
//添加删除撤销对象
this.currentDel = vc_this.currentDrawingShape;
this.currentCancel = vc_this.currentDrawingShape;
vc_this.layer.draw();
/* vc_this.setMaskData(); */
}
vc_this.$message({
message: "修改成功!",
type: "success",
center: true,
duration: 1000,
});
vc_this.stage.container().style.cursor = "crosshair";
//设置组不能拖动
vc_this.currentDrawingShape.setAttr("draggable", false);
});
return poly;
},
/**
*矩形
* @param (currentTool, x, y, group)
*/
drawRect(currentTool, x, y, group) {
var rect = new Konva.Rect({
name: currentTool.name + "rect",
x: x,
y: y,
width: 0,
height: 0,
opacity: 0.5,
/* fill: currentTool.color, */
stroke: currentTool.color,
strokeScaleEnabled: false,
strokeWidth: 1,
});
this.currentDrawingShape = rect;
group.add(rect);
var vc_this = this;
rect.getParent().on("mouseleave", () => {
vc_this.stage.container().style.cursor = "crosshair";
});
rect.getParent().on("mousedown", (e) => {
if (e.evt.button == 0) {
//如果不是正在绘画图形时
if (!vc_this.drawing) {
vc_this.stage.container().style.cursor = "move";
//设置现在绘画节点的对象为该多边形和顶点的组
vc_this.currentDrawingShape = rect.getParent();
// 如果要让顶点和多边形一起拖拽,必须设置,多边形不能被拖拽
rect.setAttr("draggable", false);
rect.getParent().setAttr("draggable", true);
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
//添加删除撤销对象
this.currentDel = vc_this.currentDrawingShape;
this.currentCancel = vc_this.currentDrawingShape;
vc_this.layer.draw();
} else {
vc_this.stage.container().style.cursor = "crosshair";
rect.getParent().setAttr("draggable", false);
}
}
});
rect.getParent().on("dragend", (e) => {
if (currentTool.name === vc_this.toolObject[0].name) {
var updatePoints = [];
var rectPoints = rect
.getParent()
.getChildren((element) => {
return element.getAttr("name") === currentTool.name + "line";
})[0]
.points();
for (var i = 0; i < rectPoints.length / 2; i++) {
updatePoints.push(rectPoints[i * 2] + rect.getParent().x());
updatePoints.push(rectPoints[i * 2 + 1] + rect.getParent().y());
}
rect.getParent().destroy();
vc_this.currentDrawingShape = vc_this.drawGroup(
updatePoints,
vc_this.toolObject[0]
);
//添加删除撤销对象
this.currentDel = vc_this.currentDrawingShape;
this.currentCancel = vc_this.currentDrawingShape;
vc_this.layer.draw();
/* vc_this.setMaskData(); */
}
//使所有顶点在顶层显示
vc_this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
vc_this.$message({
message: "修改成功!",
type: "success",
center: true,
duration: 1000,
});
vc_this.stage.container().style.cursor = "crosshair";
//设置组不能拖动
vc_this.currentDrawingShape.setAttr("draggable", false);
});
return rect;
},
/**
*多边形组
* @param points 多边形绘画的各个顶点,类型数组
*/
drawGroup(points, currentTool) {
//拖拽组
var group = new Konva.Group({
name: currentTool.name + "Group",
draggable: false,
});
switch (currentTool.type) {
case "poly":
for (var i = 0; i < points.length / 2; i++) {
var p = {
x: points[i * 2],
y: points[i * 2 + 1],
};
if (i == 0) {
//添加标签
this.drawLabel(currentTool, p.x, p.y, group, this.label);
}
//添加多边形的点
this.drawCircle(currentTool, p.x, p.y, group, points);
}
//绘画多边形
var poly = this.drawPolygon(currentTool, points, group);
//添加多边形的边
var polyline = this.drawLine(currentTool, points, group);
poly.moveToBottom();
polyline.moveToBottom();
this.layer.draw();
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
break;
case "rect":
//添加矩形的点
for (var i = 0; i < points.length / 2; i++) {
var p = {
x: points[i * 2],
y: points[i * 2 + 1],
};
//添加矩形的点
this.drawCircle(currentTool, p.x, p.y, group, points);
}
//修改顶点的名字
group
.getChildren((node) => {
return node.getClassName() === "Circle";
})[0]
.name("rectTopLeft");
group
.getChildren((node) => {
return node.getClassName() === "Circle";
})[1]
.name("rectTopRight");
group
.getChildren((node) => {
return node.getClassName() === "Circle";
})[2]
.name("rectBottomRight");
group
.getChildren((node) => {
return node.getClassName() === "Circle";
})[3]
.name("rectBottomLeft");
//绘制矩形
var rect = this.drawRect(currentTool, points[0], points[1], group);
this.currentDrawingShape.setAttrs({
width: points[4] - points[0],
height: points[5] - points[1],
});
//添加矩形的边
this.drawLine(currentTool, points, group);
//添加标签
this.drawLabel(
currentTool,
rect.getClientRect().x,
rect.getClientRect().y,
group,
this.label
);
//使所有顶点在顶层显示
this.stage.find("Circle").forEach((element) => {
element.moveToTop();
});
break;
default:
break;
}
this.layer.add(group);
this.layer.draw();
return group;
},
},
mounted() {
this.initKonvaStage();
this.$nextTick(() => {
window.addEventListener("resize", this.resizeStage);
});
//禁止浏览器右击菜单
document.oncontextmenu = function (e) {
return false;
};
},
destroyed() {
window.removeEventListener("resize", this.resizeStage);
this.stage.destroy();
}
};
</script>
<style scoped>
#map {
background: #ddd;
width: 100%;
aspect-ratio: 16/9;
}
</style>
七、源码下载
https://download.csdn.net/download/u011472784/86399863
更多推荐
已为社区贡献2条内容
所有评论(0)