You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

860 lines
26 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="drawPicBox">
<div class="pointBox">
<h3>
标注数据
<el-button
type="danger"
icon="el-icon-delete"
@click="deletePic"
></el-button>
<el-button type="primary" @click="savePointer"></el-button>
</h3>
<div class="picRow">
<p v-for="(item, index) in recArrs" :key="index">
<span
>{{ item.text }}
<el-select
size="mini"
v-model="item.type"
placeholder="请选择标注名称"
>
<el-option
v-for="(label, value, index) in markOptions"
:key="value"
:label="label"
:value="index"
>
</el-option>
</el-select>
</span>
</p>
<!-- <span>图片的宽:{{ imgWidth }}px</span>
<span>图片的高:{{ imgHeight }}px</span>
<span>宽:{{ (item.w / imgWidth).toFixed(2) }}</span>
<span>高:{{ (item.h / imgHeight).toFixed(2) }}</span>
<span>X{{ ((item.x + item.w) / 2 / imgWidth).toFixed(2) }}</span>
<span>Y{{ ((item.y + item.h) / 2 / imgHeight).toFixed(2) }}</span> -->
</div>
</div>
<div class="picCanvans">
<div class="wrap">
<img
@load="onImageLoad"
:src="
hostName + '/images/' + parentdata.name + '/' + currentNodeData.name
"
alt=""
class="img"
ref="imgDiv"
/>
<canvas
class="canvas_dom"
id="canvasDom"
:width="imgWidth"
:height="imgHeight"
@mousemove="moveFunction"
@mousedown="downFunction"
@mouseup="upFunction"
@mouseout="outFunction"
@contextmenu="contextMenuFunction"
>
</canvas>
</div>
</div>
</div>
</template>
<script>
import EventBus from "@/utils/event-bus";
import { getTypesApi, saveLabelsApi, deleteApi } from "@/utils/api/index";
export default {
components: {},
data() {
return {
markOptions: {}, //获取标注列表
currentNodeData: "",
parentdata: "",
imgWidth: 0,
imgHeight: 0,
typeMap: {
0: "挖掘机",
1: "塔吊",
2: "吊车",
3: "水泥泵车",
4: "山火",
5: "烟雾",
},
// 保存矩形数据
recArrs: [],
curObj: {
isRightClick: false, // 鼠标右键按下标识
radious: 4, // 范围误差值
recSize: 5, // 移动小框的大小
index: -1, // 当前矩形框的index
side: 0, // 边界值
resize: false, // 是否拖拽大小
draw: false, // 是否画图
drag: false, // 是否拖动
x: 0, // 画图的起始x
y: 0, // 画图的起始y
startX: 0, // x轴开始位置
startY: 0, // y轴开始位置
centerX: 0, //矩形中心点x
centerY: 0, //矩形中心点y
},
//获取的矩形数据
labelMarkArrs: [],
hostName: "",
};
},
created() {
EventBus.$on("currentNodeData", (value) => {
//console.log(value); // 输出 value
this.currentNodeData = value;
});
EventBus.$on("perentNode", (value) => {
//console.log(value); // 输出 value
this.parentdata = value;
});
EventBus.$on("labelMark", (value) => {
//console.log(value); // 输出 value
this.labelMarkArrs = value;
console.log(this.labelMarkArrs);
this.clearCanvas();
this.recArrs = [];
for (var i = 0; i < this.labelMarkArrs.length; i++) {
console.log(this.labelMarkArrs[i]);
//获取的数据转化一下
this.recArrs.push({
x:
this.labelMarkArrs[i].centerX * this.imgWidth -
(this.labelMarkArrs[i].width * this.imgWidth) / 2,
y:
this.labelMarkArrs[i].centerY * this.imgHeight -
(this.labelMarkArrs[i].height * this.imgHeight) / 2,
w: this.labelMarkArrs[i].width * this.imgWidth,
h: this.labelMarkArrs[i].height * this.imgHeight,
text: this.typeMap[this.labelMarkArrs[i].type],
type: this.labelMarkArrs[i].type,
});
}
console.log("aaaaaaaaaaaaaaaaa");
console.log(this.recArrs);
this.drawOldRect();
});
},
mounted() {
console.log(window.location.host);
const isProduction = process.env.NODE_ENV === "production";
if (isProduction) {
// 使用服务器IP或域名作为图片地址
this.hostName = window.location.origin;
console.log("aaaaaaaaaaaa");
} else {
// 使用代理的 target 作为图片地址(开发环境)
this.hostName = "http://192.168.1.190:88"; // 这里使用你的本地 target 地址
}
this.$nextTick(() => {
window.addEventListener("resize", this.updateImageSize);
});
this.getTypes();
},
beforeDestroy() {
window.removeEventListener("resize", this.updateImageSize);
},
computed: {},
methods: {
getTypes() {
getTypesApi()
.then((res) => {
console.log(res);
this.markOptions = res.data;
})
.catch((err) => {});
},
//获取图片的宽高
onImageLoad() {
this.updateImageSize();
},
updateImageSize() {
const img = this.$refs.imgDiv;
this.imgWidth = img.offsetWidth;
this.imgHeight = img.offsetHeight;
console.log(this.imgWidth, this.imgHeight);
this.clearCanvas();
this.recArrs = [];
for (var i = 0; i < this.labelMarkArrs.length; i++) {
console.log(this.labelMarkArrs[i]);
//获取的数据转化一下
this.recArrs.push({
x:
this.labelMarkArrs[i].centerX * this.imgWidth -
(this.labelMarkArrs[i].width * this.imgWidth) / 2,
y:
this.labelMarkArrs[i].centerY * this.imgHeight -
(this.labelMarkArrs[i].height * this.imgHeight) / 2,
w: this.labelMarkArrs[i].width * this.imgWidth,
h: this.labelMarkArrs[i].height * this.imgHeight,
text: this.typeMap[this.labelMarkArrs[i].type],
type: this.labelMarkArrs[i].type,
});
}
console.log("aaaaaaaaaaaaaaaaa");
console.log(this.recArrs);
this.drawOldRect();
},
// // 拖动图片
// move(e) {
// e.preventDefault();
// // 获取元素
// var left = document.querySelector(".wrap");
// var img = document.querySelector(".img");
// var x = e.pageX - img.offsetLeft;
// var y = e.pageY - img.offsetTop;
// // 添加鼠标移动事件
// left.addEventListener("mousemove", move);
// function move(e) {
// img.style.left = e.pageX - x + "px";
// img.style.top = e.pageY - y + "px";
// }
// // 添加鼠标抬起事件,鼠标抬起,将事件移除
// img.addEventListener("mouseup", function () {
// left.removeEventListener("mousemove", move);
// });
// // 鼠标离开父级元素,把事件移除
// left.addEventListener("mouseout", function () {
// left.removeEventListener("mousemove", move);
// });
// },
// // 缩放图片
// rollImg() {
// /* 获取当前页面的缩放比 若未设置zoom缩放比则为默认100%即1原图大小 */
// var zoom = parseInt(this.$refs.imgDiv.style.zoom) || 100;
// /* event.wheelDelta 获取滚轮滚动值并将滚动值叠加给缩放比zoom wheelDelta统一为±120其中正数表示为向上滚动负数表示向下滚动 */
// zoom += event.wheelDelta / 12;
// /* 最小范围 和 最大范围 的图片缩放尺度 */
// if (zoom >= 100 && zoom < 400) {
// this.$refs.imgDiv.style.zoom = zoom + "%";
// }
// return false;
// },
// 禁止鼠标右键
contextMenuFunction(e) {
e.preventDefault();
return false;
},
// 鼠标移动事件
moveFunction(e) {
// console.log('鼠标移动', e);
// 需要清除之前的辅助线
this.clearCanvas();
// 画辅助线
this.drawRuler(e);
// // 清空辅助线和矩形数据后,这里重绘
this.drawOldRect();
// 画矩形
this.drawRect(e);
// // 移动或缩放
this.moveOrScale(e);
},
// 移动矩形框/缩放矩形框
moveOrScale(e) {
let index = this.getEventIndex(e.offsetX, e.offsetY);
let side = 0;
if (index > -1) {
side = this.getEventArea(index, e.offsetX, e.offsetY);
// 画移动小框
if (side > 0) {
this.drawLitRecs(index);
}
}
// 鼠标样式
this.changeResizeCursor(side);
// 如果在移动
this.moveRec(e);
// 如果在缩放
this.reSizeRec(e);
},
// 移动
moveRec(e) {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
if (this.curObj.drag && this.recArrs[this.curObj.index]) {
let x = this.curObj.startX + e.offsetX - this.curObj.x;
let y = this.curObj.startY + e.offsetY - this.curObj.y;
let minX = canvasDom.offsetLeft;
let maxX =
canvasDom.offsetLeft +
canvasDom.offsetWidth -
this.recArrs[this.curObj.index].w;
let minY = canvasDom.offsetTop;
let maxY =
canvasDom.offsetTop +
canvasDom.offsetHeight -
this.recArrs[this.curObj.index].h;
if (x < minX) {
x = minX;
}
if (x > maxX) {
x = maxX;
}
if (y < minY) {
y = minY;
}
if (y > maxY) {
y = maxY;
}
this.recArrs[this.curObj.index].x = x;
this.recArrs[this.curObj.index].y = y;
}
},
//缩放
reSizeRec(e) {
const { side, index, recSize } = this.curObj;
const rec = this.recArrs[index];
if (this.curObj.resize && rec) {
const temX = rec.x;
const temY = rec.y;
const ex = e.offsetX;
const ey = e.offsetY;
if (side < 4 && temX + rec.w - ex > recSize) {
rec.x = ex;
}
if (
(side == 1 || side == 4 || side == 7) &&
temY + rec.h - ey > recSize
) {
rec.y = ey;
}
if (side < 4) {
if (temX + rec.w - ex > recSize) {
rec.w = temX + rec.w - ex;
}
} else if (side < 7) {
if (ex - temX > recSize) {
rec.w = ex - temX;
}
}
if (side == 1 || side == 4 || side == 7) {
if (temY + rec.h - ey > recSize) {
rec.h = temY + rec.h - ey;
}
} else if (side == 3 || side == 6 || side == 8) {
if (ey - temY > recSize) {
rec.h = ey - temY;
}
}
}
},
// 鼠标移出画布
outFunction(e) {
let canvasDom = document.getElementById("canvasDom");
let x = e.clientX;
let y = e.clientY;
let left = canvasDom.offsetLeft;
let top = canvasDom.offsetTop;
let width = canvasDom.offsetWidth;
let height = canvasDom.offsetHeight;
let limitX = left + width;
let limitY = top + height;
if (x < left || x > limitX || y < top || y > limitY) {
console.log("鼠标移出范围, 清除canvas重新绘制");
this.clearCanvas();
this.drawOldRect();
}
},
// 鼠标移动,画辅助线
drawRuler(e) {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
const canvasHeight = canvasDom.offsetWidth;
const canvasWidth = canvasDom.offsetWidth;
//console.log(canvasDom);
// 开始一条路径
ctx2d.beginPath();
// 填充色
ctx2d.strokeStyle = "red";
// 路径宽度
ctx2d.lineWidth = 1;
// 移动到 鼠标的 x位置 y位置 0竖线的起点
ctx2d.moveTo(e.offsetX, 0);
// lineTo() 方法添加一个新点,(竖线的终点)
ctx2d.lineTo(e.offsetX, canvasHeight);
// 移动到(x: 0, y鼠标的位置)(横线的起点)
ctx2d.moveTo(0, e.offsetY);
// lineTo() 方法添加一个新点,(横线的终点)
ctx2d.lineTo(canvasWidth, e.offsetY);
ctx2d.stroke();
},
// 清除canvas
clearCanvas() {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
const canvasHeight = canvasDom.width;
const canvasWidth = canvasDom.height;
ctx2d.clearRect(0, 0, canvasHeight, canvasWidth);
},
// 鼠标按下并移动,画矩形
drawRect(e) {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
if (this.curObj.draw) {
ctx2d.strokeRect(
this.curObj.x,
this.curObj.y,
e.offsetX - this.curObj.x,
e.offsetY - this.curObj.y
);
}
},
// 画初始数据
drawOldRect() {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
const canvasHeight = canvasDom.width;
const canvasWidth = canvasDom.height;
if (!this.recArrs.length) return;
for (var i = 0; i < this.recArrs.length; i++) {
// >2的判断是为了防止误触画出来的数据
if (this.recArrs[i].w > 2 && this.recArrs[i].h > 2) {
ctx2d.beginPath();
ctx2d.lineWidth = 2; // 矩形框的线条宽度
ctx2d.strokeStyle = "rgb(255, 0, 0)"; // 矩形框的线条颜色
// 设置填充样式
ctx2d.fillStyle = "rgba(22, 158, 140, 0.4)"; // 蓝色,半透明
ctx2d.strokeRect(
this.recArrs[i].x,
this.recArrs[i].y,
this.recArrs[i].w,
this.recArrs[i].h
); // 矩形框
ctx2d.fillRect(
this.recArrs[i].x,
this.recArrs[i].y,
this.recArrs[i].w,
this.recArrs[i].h
); // 填充矩形
// 如果有文本信息,填充文本信息
if (this.recArrs[i].text) {
ctx2d.font = "100 18px 微软雅黑";
ctx2d.lineWidth = 1;
ctx2d.strokeStyle = "rgb(255,0,0)";
ctx2d.strokeText(
this.recArrs[i].text,
this.recArrs[i].x +
this.recArrs[i].w / 2 -
(this.recArrs[i].text.length / 2) * 16,
this.recArrs[i].y - 20 < 0
? this.recArrs[i].y + this.recArrs[i].h + 20
: this.recArrs[i].y - 10
);
}
}
}
},
writeMarkHandle() {
this.dialogFormVisible = false;
this.drawRect();
},
// 鼠标按下事件
downFunction(e) {
console.log("鼠标按下", e); // e.button 0 鼠标左键 1 鼠标滚轮 2 鼠标右键
this.curObj.isRightClick = e.button > 1;
console.log("是否右键", this.curObj.isRightClick);
// 赋值 x,y 轴起始数据
this.curObj.x = e.offsetX;
this.curObj.y = e.offsetY;
// 判断是否落在的矩形框上
//得到落点所在框的序数
this.curObj.index = this.getEventIndex(this.curObj.x, this.curObj.y);
console.log("落点矩形", this.curObj.index);
// 如果是鼠标右键 TODO...
if (this.curObj.isRightClick) {
} else {
// 鼠标左键
// 如果鼠标落点不在矩形内,画矩形
if (this.curObj.index === -1) {
this.curObj.draw = true;
} else {
// 落点在矩形内
//移动或者放缩
this.curObj.startX = this.recArrs[this.curObj.index].x;
this.curObj.startY = this.recArrs[this.curObj.index].y;
//得到落点在一个框中的区域
this.curObj.side = this.getEventArea(
this.curObj.index,
this.curObj.x,
this.curObj.y
);
console.log("this.curObj.side", this.curObj.side);
if (this.curObj.side < 9) {
//准备缩放
console.log("在缩放");
this.curObj.resize = true;
} else {
//准备拖动
console.log("在拖动");
this.curObj.drag = true;
}
// 画移动小框
this.drawLitRecs(this.curObj.index);
}
}
//判断小框类型
this.changeResizeCursor(this.curObj.side);
},
//画移动时的小框,data为矩形框9个点的坐标
drawLitRecs(index) {
let canvasDom = document.getElementById("canvasDom");
let ctx2d = canvasDom.getContext("2d");
const data = this.prepareLitRecs(index);
const { recSize } = this.curObj;
for (var i = 0; i < data.length; i++) {
ctx2d.strokeRect(
data[i][0] - recSize / 2,
data[i][1] - recSize / 2,
recSize,
recSize
);
}
},
//把一个框的左上角坐标和宽高输入得到8个坐标左3右3中2
prepareLitRecs(index) {
const data = this.recArrs[index];
var li = [];
li[0] = [data.x, data.y];
li[1] = [data.x, data.y + data.h / 2];
li[2] = [data.x, data.y + data.h];
li[3] = [data.x + data.w, data.y];
li[4] = [data.x + data.w, data.y + data.h / 2];
li[5] = [data.x + data.w, data.y + data.h];
li[6] = [data.x + data.w / 2, data.y];
li[7] = [data.x + data.w / 2, data.y + data.h];
return li;
},
// 修改鼠标样式
changeResizeCursor(side) {
let canvasDom = document.getElementById("canvasDom");
switch (side) {
case 0:
canvasDom.style.cursor = "crosshair";
break;
case 1:
canvasDom.style.cursor = "se-resize";
break;
case 2:
canvasDom.style.cursor = "e-resize";
break;
case 3:
canvasDom.style.cursor = "ne-resize";
break;
case 4:
canvasDom.style.cursor = "sw-resize";
break;
case 5:
canvasDom.style.cursor = "w-resize";
break;
case 6:
canvasDom.style.cursor = "nw-resize";
break;
case 7:
canvasDom.style.cursor = "s-resize";
break;
case 8:
canvasDom.style.cursor = "n-resize";
break;
case 9:
canvasDom.style.cursor = "move";
break;
default:
canvasDom.style.cursor = "default";
}
},
//得到落点在一个框中的区域
getEventArea(index, x, y) {
const data = this.recArrs[index];
// console.log("this.recArrs", this.recArrs);
// console.log("data", data);
if (
x > data.x - this.curObj.radious &&
x < data.x + this.curObj.radious
) {
if (
y > data.y - this.curObj.radious &&
y < data.y + this.curObj.radious
) {
return 1;
} else if (
y > data.y + this.curObj.radious &&
y < data.y + data.h - this.curObj.radious
) {
return 2;
} else if (
y > data.y + data.h - this.curObj.radious &&
y < data.y + data.h + this.curObj.radious
) {
return 3;
}
} else if (
x > data.x + data.w - this.curObj.radious &&
x < data.x + data.w + this.curObj.radious
) {
if (
y > data.y - this.curObj.radious &&
y < data.y + this.curObj.radious
) {
return 4;
} else if (
y > data.y + this.curObj.radious &&
y < data.y + data.h - this.curObj.radious
) {
return 5;
} else if (
y > data.y + data.h - this.curObj.radious &&
y < data.y + data.h + this.curObj.radious
) {
return 6;
}
} else {
if (
y > data.y - this.curObj.radious &&
y < data.y + this.curObj.radious &&
x > data.x + this.curObj.radious &&
x < data.x + data.w - this.curObj.radious
) {
return 7;
} else if (
y > data.y + data.h - this.curObj.radious &&
y < data.y + data.h + this.curObj.radious &&
x > data.x + this.curObj.radious &&
x < data.x + data.w - this.curObj.radious
) {
return 8;
} else {
return 9;
}
}
},
// 获取鼠标落点所在矩形的index, -1 表示没有落在任何框内
getEventIndex(x, y) {
if (!this.recArrs.length) return -1;
for (var i = 0; i < this.recArrs.length; i++) {
const limitX = x > this.recArrs[i].x - this.curObj.radious;
const limitW =
x < this.recArrs[i].x + this.recArrs[i].w + this.curObj.radious;
const limitY = y > this.recArrs[i].y - this.curObj.radious;
const limitH =
y < this.recArrs[i].y + this.recArrs[i].h + this.curObj.radious;
// 有在范围内的返回index
if (limitX && limitY && limitW && limitH) {
return i;
}
// 没有返回 -1
if (i == this.recArrs.length - 1) {
return -1;
}
}
},
// 鼠标抬起事件
upFunction(e) {
console.log("鼠标抬起", e);
if (this.curObj.isRightClick) {
if (this.curObj.index !== -1) {
// 删除,重绘
this.recArrs.splice(this.curObj.index, 1);
this.clearCanvas();
this.drawOldRect();
}
this.curObj.isRightClick = false;
return;
}
this.curObj.resize = false;
this.curObj.drag = false;
// 如果是画图
if (this.curObj.draw) {
this.addToRecs(e);
this.curObj.draw = false;
}
console.log("鼠标抬起-当前矩形框", this.recArrs);
},
// 添加矩形
addToRecs(e) {
let rec = {
x: this.curObj.x > e.offsetX ? e.offsetX : this.curObj.x, // x点
y: this.curObj.y > e.offsetY ? e.offsetY : this.curObj.y, // y点
w: Math.abs(e.offsetX - this.curObj.x), // 宽
h: Math.abs(e.offsetY - this.curObj.y), // 高
text: "矩形框" + this.recArrs.length, // 默认填充文本
type: 0, // 类型
// 其他需要的数据自行添加...
};
// 防止误触
if (rec.w > 2 && rec.h > 2) {
this.recArrs.push(rec);
console.log("recArrs", this.recArrs);
}
},
//保存图片和数据
savePointer() {
let params = {
labels: [],
path: this.parentdata.name + "/" + this.currentNodeData.name,
};
for (var i = 0; i < this.recArrs.length; i++) {
params.labels.push({
centerX: (this.recArrs[i].x + this.recArrs[i].w / 2) / this.imgWidth,
centerY: (this.recArrs[i].y + this.recArrs[i].h / 2) / this.imgHeight,
width: this.recArrs[i].w / this.imgWidth,
height: this.recArrs[i].h / this.imgHeight,
type: this.recArrs[i].type,
});
}
console.log(params);
saveLabelsApi(params)
.then((res) => {
console.log(res);
if (res.success) {
this.$message({
showClose: true,
duration: 1500,
message: res.data,
type: "success",
});
EventBus.$emit("treeHandleNode", this.currentNodeData);
EventBus.$emit("treelist");
this.recArrs = [];
this.clearCanvas();
this.drawOldRect();
} else {
this.$message({
showClose: true,
duration: 1500,
message: "保存失败",
type: "error",
});
}
})
.catch((err) => {});
},
//删除图片和数据
deletePic() {
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
deleteApi({
path: this.parentdata.name + "/" + this.currentNodeData.name,
})
.then((res) => {
console.log(res);
this.$message({
type: "success",
message: "删除成功!",
});
EventBus.$emit("treelist");
localStorage.removeItem("currentData");
})
.catch((err) => {});
})
.catch(() => {});
},
},
};
</script>
<style lang="less">
.drawPicBox {
width: 100%;
height: 100%;
position: relative;
.pointBox {
//background: #fcc;
right: 14px;
border-radius: 4px;
//border: 1px solid #dcdfe6;
z-index: 22;
margin-bottom: 12px;
h3 {
margin-bottom: 12px;
font-size: 14px;
line-height: 24px;
align-items: center;
display: flex;
.el-button--danger {
padding: 4px 8px;
margin-left: 14px;
}
}
.picRow {
display: flex;
align-items: center;
//height: 32px;
p {
line-height: 32px;
// height: 32px;
margin-bottom: 8px;
font-size: 14px;
margin-right: 12px;
span {
margin-right: 8px;
}
}
.el-select {
width: 140px;
.el-input--suffix .el-input__inner {
padding-right: 12px;
}
}
}
}
.picCanvans {
width: 100%;
height: calc(100% - 87px);
overflow: auto;
h3 {
margin-bottom: 12px;
font-size: 14px;
}
.wrap {
width: 100%;
height: 100%;
position: relative;
//border: 1px solid #dcdfe6;
// background: rgba(0, 0, 0, 0.3);
img {
position: absolute;
max-width: 100%;
max-height: calc(100% - 10px);
cursor: move;
-moz-user-select: none; /**/
-webkit-user-select: none; /*webkit*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /**/
user-select: none;
}
.canvas_dom {
position: absolute;
}
}
}
}
</style>