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

<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="
1 year ago
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: [],
1 year ago
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() {
1 year ago
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%;
1 year ago
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%;
1 year ago
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>