canvas 元素
<!--画布-->
<canvas
id="myCanvas"
:height="canvasSize.height"
:width="canvasSize.width"
:style="{
cursor: isDragging ? 'grab' : 'default',
top: canvasPosition.y + 'px',
left: canvasPosition.x + 'px',
'-webkit-filter': 'grayscale(' + shading + '%)'
}"
@mousewheel="handleMouseWheel"
@contextmenu="handleContextmenu"
@mousedown="handleMouseStart"
@mousemove="handleMouseMove"
@mouseup="handleMouseEnd"
></canvas>
定义画布变量以及其它变量
<script>
let ctx = ''
export default {
data(){
return{
imgSize: { height: "", width: "" }, //图片原始尺寸
imgZoom: 1, //图片缩放倍数(默认一倍)
canvasSize: { height: "", width: "" }, //画布尺寸
canvasPosition: { x: "", y: "" }, //画布位置
canvasMouseStart: { x: "", y: "" }, //画布中鼠标开始点击位置
isMouseDown: false, //鼠标按下状态
dragStart: { x: "", y: "" }, //开始拖拽的位置
currentDrawData: {}, // 当前绘图数据
currentBgImg: "", // 当前加载的背景图
}
}
}
</script>
获取画布地址且初始化画布
// 必须异步加载图片
loadBgImg(markImg) {
let img = new Image(); //创建img标签
img.src = markImg; // 后台返回完成地址
// img.src = this.baseUrl + markImg; // 需要手动添加服务器地址
return new Promise((resolve, reject) => {
img.onload = () => {
resolve(img); //返回标签
};
img.onerror = (err) => {
reject(err);
};
});
},
// 获取所有的图片以及当前图片
getPhoto() {
this.resetData(); // 重置
this.canvasLoading = true;
this.imgZoom = 1
this.bannerList.map((item, index) => {
if(item.ImgId == this.currentImageId) {
this.curIndex = this.currentImageId;
// 当前canvas图片的全部信息
this.currentData = item;
this.bannerListNew = this.bannerList.slice(index).concat(this.bannerList.slice(0, index)); // 当期激活的
//加载背景图片
this.loadBgImg(this.currentData.ImgPath).then(async (img) => {
this.currentBgImg = img; //存下加载完成后的背景图
await this.initCanvas(img); //图片加载完后初始化画布
await this.getDefectTips(this.currentImageId);
});
this.currentModel = {}; //默认绘图模式
}
})
},
// 初始化画布
async initCanvas(img) {
let width = 0
let height = 0
// 按0.2比例缩放图片
width = img.width * 0.2;
height = img.height * 0.2;
await (this.canvasSize = { height: height, width: width}); //通过图片尺寸设置画布尺寸
this.imgSize = { height: height, width: width }; //记录下图片原始尺寸
ctx = document.getElementById("myCanvas").getContext("2d"); //获取上下文
await ctx.drawImage(img, 0, 0, width, height); //在canvas中绘制图片(图片、起始位置、绘图尺寸)
let canvasDiv = document.getElementsByClassName("canvas-div")[0]; // 画布外层元素
this.canvasPosition = {
x: canvasDiv.offsetWidth / 2 - width / 2,
y: canvasDiv.offsetHeight / 2 - height / 2 - 25,
}; //背景居中
},
// 获取图片上缺陷的坐标
async getDefectTips(id) {
this.tableLoading = true;
this.tableData = [];
await axios({
method: "get",
url: this.baseUrl + "/img/getImgMarks_noPa",
params: {
pageCurrent: this.pageParm.pageIndex,
pageSize: this.pageParm.pageSize,
imgId: id
}
}).then((res) => {
this.canvasLoading = false;
if(res.status == 200 && res.data.success) {
this.tableLoading = false;
this.tableData = res.data.data.records;
this.pageParm.pageIndex = res.data.data.current;
this.pageParm.total = res.data.data.total;
// 整理数据,画框
let obj = {
x: 0,
y: 0,
x1: 0,
y1: 0,
markId: null,
firstLevel: '',
secondary: '',
describe: '',
defectType: "0",
virtualBox: false
}
if(this.tableData.length) {
for (let i = 0; i < this.tableData.length; i++) {
let strObj = JSON.parse(this.tableData[i].data);
let arr = strObj.imgData.split(',');
let item1 = Math.ceil(arr[0]) * 2 / 10;
let item2 = Math.ceil(arr[1]) * 2 / 10;
let item3 = Math.ceil(arr[2]) * 2 / 10;
let item4 = Math.ceil(arr[3]) * 2 / 10;
obj = {
x: item1 - item3 < 0? item1: item3,
y: item2 - item4 < 0? item2: item4,
x1: item3 - item1 > 0? item3: item1,
y1: item4 - item2 > 0? item4: item2,
markId: this.tableData[i].markId,
firstLevel: this.tableData[i].firstLevel,
secondary: this.tableData[i].secondary,
describe: this.tableData[i].describe,
defectType: this.tableData[i].defectType,
virtualBox: this.tableData[i].virtualBox
}
this.drawRectangle(obj);
// 判断markIdSel是否为空,如果有值且有相等的,则回显
if((this.markIdSel !== '') && (this.markIdSel === obj.markId)) {
let activeObj = {
type: 'rectangle',
color: 'red',
data: [
[obj.x, obj.y],
[obj.x1, obj.y1]
],
markId: obj.markId,
firstLevel: obj.firstLevel,
secondary: obj.secondary,
describe: obj.describe,
defectType: obj.defectType,
virtualBox: obj.virtualBox
}
// 表格高亮
let row = this.tableData.filter(item => item.markId === obj.markId)[0]
this.$nextTick(() => {
this.$refs.tableRef.setCurrentRow(row)
})
// 缺陷框高亮
this.selectPoint(activeObj);
}
}
}
}
}).catch(() => {
this.tableLoading = false;
this.canvasLoading = false;
})
},
//生成矩形数据
drawRectangle(obj) {
this.currentDrawData = {
type: "rectangle",
color: 'red',
data: [
[obj.x, obj.y],
[obj.x1, obj.y1],
],
markId: obj.markId,
firstLevel: obj.firstLevel,
secondary: obj.secondary,
describe: obj.describe,
defectType: obj.defectType,
virtualBox: obj.virtualBox
};
this.canvasData.push(this.currentDrawData);
// 矩形绘制
this.drawToArr();
},
// 虚线矩形框
drawDashRect(left, top, width, height, step = 5) {
this.drawDashLine([left, top], [left + width, top], step);
ctx.stroke();
this.drawDashLine([left + width, top], [left + width, top + height], step);
ctx.stroke();
this.drawDashLine([left + width, top + height], [left, top + height], step);
ctx.stroke();
this.drawDashLine([left, top + height], [left, top], step);
ctx.stroke();
},
//通过保存的大列表绘制图形
async drawToArr() {
ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布图形
ctx.drawImage(
this.currentBgImg,
0,
0,
this.canvasSize.width,
this.canvasSize.height
); //重绘背景
for (let i = 0; i < this.canvasData.length; i++) {
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
if(this.canvasData[i].virtualBox) {
// 绘制虚线矩形
this.drawDashRect(this.canvasData[i].data[0][0]*this.imgZoom, this.canvasData[i].data[0][1]*this.imgZoom, this.canvasData[i].data[1][0]*this.imgZoom - this.canvasData[i].data[0][0]*this.imgZoom, this.canvasData[i].data[1][1]*this.imgZoom - this.canvasData[i].data[0][1]*this.imgZoom, 5);
} else {
// 绘制实线矩形
ctx.strokeRect(
this.canvasData[i].data[0][0]*this.imgZoom,
this.canvasData[i].data[0][1]*this.imgZoom,
this.canvasData[i].data[1][0]*this.imgZoom - this.canvasData[i].data[0][0]*this.imgZoom,
this.canvasData[i].data[1][1]*this.imgZoom - this.canvasData[i].data[0][1]*this.imgZoom
);
}
}
}
绘制点、直线、矩形、圆、多边形
// 红外 -- 画基准点
drawPoint(e) {
let offsetX = e.offsetX * this.imgZoom;
let offsetY = e.offsetY * this.imgZoom;
// 四个扇形
let num = 4;
// 一份的弧度
let angle = (Math.PI * 2) / num;
/*上一次绘制的结束弧度等于当前次的起始弧度*/
//var startAngle = 0;
for (let i = 0; i < num; i++) {
let startAngle = i * angle;
let endAngle = (i + 1) * angle;
ctx.beginPath();
if (i == 0) {
ctx.moveTo(offsetX + 3, offsetY + 3);
ctx.arc(offsetX + 3, offsetY + 3, 10, startAngle, endAngle);
/*随机颜色*/
ctx.strokeStyle = 'black';
ctx.lineWidth = 2; // 边框宽度
ctx.stroke();
} else if (i == 1) {
ctx.moveTo(offsetX - 3, offsetY + 3);
ctx.arc(offsetX - 3, offsetY + 3, 10, startAngle, endAngle);
/*随机颜色*/
ctx.strokeStyle = 'black';
ctx.lineWidth = 2; // 边框宽度
ctx.stroke();
} else if (i == 2) {
ctx.moveTo(offsetX - 3, offsetY - 3);
ctx.arc(offsetX - 3, offsetY - 3, 10, startAngle, endAngle);
/*随机颜色*/
ctx.strokeStyle = 'black';
ctx.lineWidth = 2; // 边框宽度
ctx.stroke();
} else {
ctx.moveTo(offsetX + 3, offsetY - 3);
ctx.arc(offsetX + 3, offsetY - 3, 10, startAngle, endAngle);
/*随机颜色*/
ctx.strokeStyle = 'black';
ctx.lineWidth = 2; // 边框宽度
ctx.stroke();
}
}
// 直线
ctx.beginPath(); //新建路径
ctx.moveTo(offsetX - 20, offsetY); //直线起点 x
ctx.lineTo(offsetX + 20, offsetY); //绘直线至(x,y)坐标
ctx.strokeStyle = "black";
ctx.stroke(); //绘制线条
// 竖线
ctx.beginPath(); //新建路径
ctx.moveTo(offsetX, offsetY - 20); //直线起点 x
ctx.lineTo(offsetX, offsetY + 20); //绘直线至(x,y)坐标
ctx.strokeStyle = "black";
ctx.stroke(); //绘制线条
},
// 红外-- 画直线
drawBeeline(e) {
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.moveTo(this.canvasMouseStart.x, this.canvasMouseStart.y); //画笔移动至(x,y)坐标
ctx.lineTo(e.offsetX, e.offsetY); //绘直线至(x,y)坐标
ctx.stroke();
//生成直线绘图数据
this.currentDrawDataNewBeeline = {
type: "beeline",
color: 'black',
data: [
[this.canvasMouseStart.x, this.canvasMouseStart.y],
[e.offsetX, e.offsetY],
],
};
},
//画矩形
drawRectangleNew(e) {
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
//绘制矩形边框
ctx.strokeRect(
this.canvasMouseStart.x,
this.canvasMouseStart.y,
e.offsetX - this.canvasMouseStart.x,
e.offsetY - this.canvasMouseStart.y
);
//生成矩形数据
this.currentDrawData = {
type: "rectangle",
color: 'red',
data: [
[this.canvasMouseStart.x, this.canvasMouseStart.y],
[e.offsetX, e.offsetY],
]
};
},
//画圆
drawCircle(e) {
this.canvasMousePosition = {
x: e.offsetX,
y: e.offsetY
};
let { x, y } = this.canvasMouseStart;
let r = Math.round(
Math.sqrt(
(e.offsetX - x) * (e.offsetX - x) + (e.offsetY - y) * (e.offsetY - y)
)
);
ctx.beginPath(); //新建路径
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.strokeStyle = 'red'; //线条颜色
ctx.stroke(); //绘制线条
//生成点绘图数据
this.currentDrawData = {
type: "circle",
data: [[x, y]],
r: r,
color: this.currentColor.color
};
},
//画多边形
drawPolygon(e) {
ctx.beginPath();
ctx.strokeStyle = this.currentColor.color;
ctx.moveTo(this.canvasMouseStart.x, this.canvasMouseStart.y);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
}
鼠标点击 – 判断是绘制开始选中
//鼠标按下事件
handleMousedown(e) {
if (e.button == 0 && e.ctrlKey == true) {
this.isDrag = true; //左键按下并且按下ctrl键 ,打开拖拽
let el = document.getElementById("myCanvas");
this.dragStart = {
x: el.offsetLeft - e.screenX,
y: el.offsetTop - e.screenY
}; //记录下开始拖拽的偏移量
return;
}else if(e.button == 0 && JSON.stringify(this.currentModel) === "{}" && e.ctrlKey == false){
console.log(this.canvasData);
// 点击区域范围 是否有标注 待优化
for (let index = 0; index < this.canvasData.length; index++) {
if(this.canvasData[index].type == 'point'){ // 点
let dis = Math.sqrt( (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) * (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) + (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom) * (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom))
if(dis <= 10 * this.imgZoom){
this.selectPoint('item')
this.selectPoint(this.canvasData[index])
return
}else{
this.selectPoint('item')
}
}else if(this.canvasData[index].type == 'rectangle'){ // 矩形
// 还要判断最后的对角在哪
// const isInside = (point, rect) => point.x > rect.left && point.x < rect.right && point.y > rect.top && point.y < rect.bottom;
if(e.offsetX > this.canvasData[index].data[0][0] * this.imgZoom
&& e.offsetX < this.canvasData[index].data[0][0] * this.imgZoom + (this.canvasData[index].data[1][0] - this.canvasData[index].data[0][0] * this.imgZoom )
&& e.offsetY > this.canvasData[index].data[0][1] * this.imgZoom
&& e.offsetY < this.canvasData[index].data[0][1] * this.imgZoom + (this.canvasData[index].data[1][1] - this.canvasData[index].data[0][1] * this.imgZoom)){
this.selectPoint('item')
this.selectPoint(this.canvasData[index])
return
}else{
this.selectPoint('item')
}
}else if(this.canvasData[index].type == 'circle'){ // 圆
// 第一种方法
// let ins = Math.sqrt( (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) * (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) + (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom) * (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom))
// if(ins <= this.canvasData[index].r * this.imgZoom){
// this.selectPoint('item')
// this.selectPoint(this.canvasData[index])
// return
// } else {
// this.selectPoint('item')
// }
// 第二种方法
// 判断点击位置是否在圆内
const isInsideCircle = this.isPointInsideCircle(this.canvasData[index].data[0][0] * this.imgZoom, this.canvasData[index].data[0][1] * this.imgZoom, this.canvasData[index].r * this.imgZoom, e.offsetX, e.offsetY);
if (isInsideCircle) {
// 点击位置在圆内
this.selectPoint('item')
this.selectPoint(this.canvasData[index])
return;
} else {
// 点击位置不在圆内,进行相应的处理
this.selectPoint('item')
}
} else if(this.canvasData[index].type == 'beeline') { // 直线
// 判断点击点是否在直线容差范围内
const isWithinToleranceRange = this.isWithinTolerance(
this.canvasData[index].data[0][0] * this.imgZoom,
this.canvasData[index].data[0][1] * this.imgZoom,
this.canvasData[index].data[1][0] * this.imgZoom,
this.canvasData[index].data[1][1] * this.imgZoom,
e.offsetX,
e.offsetY,
2 // 容差值
);
if (isWithinToleranceRange) {
// 点击点在直线容差范围内
this.selectPoint('item')
this.selectPoint(this.canvasData[index])
return;
} else {
// 点击点不在直线容差范围内,进行相应的处理
this.selectPoint('item')
}
} else if(this.canvasData[index].type == 'polygon') {
// 判断点击位置是否在多边形内
const isInsidePolygon = this.isPointInsidePolygon(this.canvasData[index].data, e.offsetX, e.offsetY);
if (isInsidePolygon) {
// 点击位置在多边形内
console.log(this.canvasData[index]);
this.selectPoint('item')
this.selectPoint(this.canvasData[index])
return;
} else {
// 点击位置不在多边形内,进行相应的处理
this.selectPoint('item')
}
}
}
}
if (e.button !== 2) {
return; // 左键绘图
}
this.isMouseDown = true; // 打开鼠标状态
//获取画布中鼠标开始点击位置
this.canvasMouseStart = {
x: e.offsetX,
y: e.offsetY
};
},
鼠标移动 – 绘制
//鼠标移动事件
async handleMousemove(e) {
if (this.isDrag) {
this.mouseDrag(e); //处理拖拽
return;
}
this.isMsg = true;
//获取屏幕中鼠标位置(显示实时坐标)
this.mousePosition = {
x: e.pageX,
y: e.pageY
};
//获取画布中鼠标位置
this.canvasMousePosition = {
x: e.offsetX,
y: e.offsetY
};
//判断是否超出边界
if (e.offsetX < 0 || e.offsetY < 0 || e.offsetX == 0 || e.offsetY == 0) {
this.isMsg = false;
this.isMouseDown = false; //关闭鼠标状态
}
//判断鼠标状态是否打开
if (!this.isMouseDown) {
return;
}
ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布后立刻重新绘制视觉上形成动画
await ctx.drawImage(
this.currentBgImg,
0,
0,
this.canvasSize.width,
this.canvasSize.height
); //在canvas中绘制图片
await this.drawToArr(); //重绘列表数据
//绘制点
if (this.currentModel.model == "point") {
return;
}
//绘制直线
if (this.currentModel.model == "beeline") {
this.drawBeeline(e);
}
//绘制矩形
if (this.currentModel.model == "rectangle") {
this.drawRectangle(e);
}
//绘制圆形
if (this.currentModel.model == "circle") {
this.drawCircle(e);
}
},
鼠标松开 – 还原真实坐标,添加数据到总数居,多边形绘制
//鼠标松开事件
handleMouseup(e) {
if (e.button == 0) {
this.isDrag && (this.isDrag = false); //左键松开关闭拖拽
}
if (e.button !== 2) {
return; // 右键松开
}
//点模式的松开
if (this.currentModel.model == "point") {
this.drawPoint(e); //用鼠标松开时的位置画点
this.currentDrawData.data.forEach((e) => {
e[0] = e[0] / this.imgZoom; //将坐标数据还原至真实数据
e[1] = e[1] / this.imgZoom;
// 添加 直/竖 坐标
});
this.canvasData.push(this.currentDrawData); //添加当前绘图数据至大列表
}
// 矩形
if(this.currentModel.model == "rectangle") {
this.currentDrawData.data.forEach((e) => {
e[0] = e[0] / this.imgZoom; //还原真实坐标
e[1] = e[1] / this.imgZoom;
});
this.canvasData.push(this.currentDrawData); //添加当前绘图数据
}
//线模式、直线模式、圆形
if (
this.currentModel.model == "line" ||
this.currentModel.model == "beeline" ||
this.currentModel.model == "circle"
) {
this.currentDrawData.data.forEach((e) => {
e[0] = e[0] / this.imgZoom; //还原真实坐标
e[1] = e[1] / this.imgZoom;
});
this.currentModel.model == "circle" &&
(this.currentDrawData.r = this.currentDrawData.r / this.imgZoom); //圆形模式需要处理半径
this.canvasData.push(this.currentDrawData); //添加当前绘图数据
}
//多边形模式的松开
if (this.currentModel.model == "polygon") {
this.constructPolygonData(e); //构造多边形数据
this.drawToArr(); //多边形模式中每次鼠标松开后都需要重绘列表数据
//更新多边形画线时起点位置
this.canvasMouseStart = {
x: e.offsetX / this.imgZoom, //还原真实坐标
y: e.offsetY / this.imgZoom
};
}
this.isMouseDown = false; //关闭鼠标状态
this.canvasMousePosition = {
x: e.offsetX, //更新位置
y: e.offsetY
};
},
多边形添加数据
//生成多边形数据
constructPolygonData(e) {
if (this.polygonTempList.data) {
let oldPointX =
this.polygonTempList.data[this.polygonTempList.data.length - 1][0];
let oldPointY =
this.polygonTempList.data[this.polygonTempList.data.length - 1][1];
let newPointX = e.offsetX / this.imgZoom; //计算出真实坐标
let newPointY = e.offsetY / this.imgZoom;
//多边形需防止坐标重复
if (oldPointX !== newPointX || oldPointY !== newPointY) {
//非第一次松开直接push多边形点列表
this.polygonTempList.data.push([newPointX, newPointY]);
}
} else {
//第一次松开则构造完整数据
this.polygonTempList = {
type: "polygon",
color: this.currentColor.color,
data: [[e.offsetX / this.imgZoom, e.offsetY / this.imgZoom]]
};
}
}
选中高亮
// 计算点到直线的距离
calculateDistanceToLine(x1, y1, x2, y2, x, y) {
const A = y2 - y1;
const B = x1 - x2;
const C = x2 * y1 - x1 * y2;
return Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
},
// 判断点击点是否在直线容差范围内 -- 5px
isWithinTolerance(x1, y1, x2, y2, x, y, tolerance) {
const distance = this.calculateDistanceToLine(x1, y1, x2, y2, x, y);
return distance <= tolerance;
},
// 判断是否点中多边形
isPointInsidePolygon(vertices, x, y) {
let intersections = 0;
// 判断射线与多边形的交点数量
for (let i = 0; i < vertices.length; i++) {
const vertex1 = vertices[i];
const vertex2 = vertices[(i + 1) % vertices.length];
if (((vertex1[1] > y) != (vertex2[1] > y)) && (x < (vertex2[0] - vertex1[0]) * (y - vertex1[1]) / (vertex2[1] - vertex1[1]) + vertex1[0])) {
intersections++;
}
}
// 奇数个交点则点在多边形内
return (intersections % 2) === 1;
},
// 判断是否点中圆
isPointInsideCircle(centerX, centerY, radius, x, y) {
const distance = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
return distance <= radius;
},
// 选中标注
selectPoint(item){
if(item == 'item'){
this.drawToArr();
this.isSelect = true;
}else if(this.isSelect){
if(item.type == 'point'){
ctx.beginPath();
ctx.arc(
item.data[0][0] * this.imgZoom,
item.data[0][1] * this.imgZoom,
20 * this.imgZoom,
0 * this.imgZoom,
2 * Math.PI
);
// ctx.strokeStyle = item.color;
ctx.strokeStyle = "yellow";
ctx.stroke();
}else if(item.type == 'rectangle'){
ctx.beginPath();
// ctx.strokeStyle = this.currentColor.color;
ctx.strokeStyle = "yellow"
//绘制矩形边框
ctx.strokeRect(
(item.data[0][0] - 3) * this.imgZoom,
(item.data[0][1] - 3) * this.imgZoom,
(item.data[1][0] - item.data[0][0] + 6) * this.imgZoom,
(item.data[1][1] - item.data[0][1] + 6) * this.imgZoom
);
}else if(item.type == 'beeline'){
ctx.beginPath();
ctx.moveTo(item.data[0][0] * this.imgZoom, item.data[0][1] * this.imgZoom);
ctx.lineTo(item.data[1][0] * this.imgZoom, item.data[1][1] * this.imgZoom);
ctx.strokeStyle = 'yellow';
ctx.stroke();
} else if(item.type == 'circle') {
ctx.beginPath();
ctx.arc(
item.data[0][0] * this.imgZoom,
item.data[0][1] * this.imgZoom,
item.r * this.imgZoom,
0 * this.imgZoom,
2 * Math.PI
);
ctx.strokeStyle = "yellow";
ctx.stroke();
} else if(item.type == 'polygon') {
console.log(item, this.polygonTempList.data);
//判断多边形临时列表是否有数据
if (item.data && item.data.length > 1) {
ctx.beginPath();
ctx.strokeStyle = 'yellow';
ctx.moveTo(
item.data[0][0] * this.imgZoom,
item.data[0][1] * this.imgZoom
); //起始点
//遍历多边形点列表连续绘制
item.data.forEach((p) => {
ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
});
//通过状态判断多边形是否闭合
if (item.isClose) {
ctx.closePath(); //闭合
}
ctx.stroke();
}
}
this.isSelect = false;
}
},
总数据绘制
//通过保存的大列表绘制图形
async drawToArr() {
ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布图形
ctx.drawImage(
this.currentBgImg,
0,
0,
this.canvasSize.width,
this.canvasSize.height
); //重绘背景
//遍历大列表开始绘制
await this.canvasData.forEach((e) => {
//绘制点
// console.log(e)
if (e.type == "point") {
ctx.beginPath();
ctx.arc(
e.data[0][0] * this.imgZoom,
e.data[0][1] * this.imgZoom,
10 * this.imgZoom,
0 * this.imgZoom,
2 * Math.PI
);
// ctx.fillStyle = e.color;
ctx.strokeStyle = e.color;
// ctx.fill();
ctx.stroke();
// let num = 4;
// // 一份的弧度
// let angle = Math.PI * 2 / num;
// /*上一次绘制的结束弧度等于当前次的起始弧度*/
// //var startAngle = 0;
// for (let i = 0; i < num; i++) {
// let startAngle = i * angle;
// let endAngle = (i + 1) * angle;
// ctx.beginPath();
// if(i == 0){
// ctx.moveTo(e.data[0][0] + 3, e.data[0][1] + 3);
// ctx.arc(e.data[0][0] + 3, e.data[0][1] + 3, 10, startAngle, endAngle);
// /*随机颜色*/
// ctx.fillStyle = this.currentColor.color;
// ctx.fill();
// }else if(i == 1){
// ctx.moveTo(e.data[0][0] - 3, e.data[0][1] + 3);
// ctx.arc(e.data[0][0] - 3, e.data[0][1] + 3, 10, startAngle, endAngle);
// /*随机颜色*/
// ctx.fillStyle = this.currentColor.color;
// ctx.fill();
// }else if(i == 2) {
// ctx.moveTo(e.data[0][0] - 3, e.data[0][1] - 3);
// ctx.arc(e.data[0][0] - 3, e.data[0][1] - 3, 10, startAngle, endAngle);
// /*随机颜色*/
// ctx.fillStyle = this.currentColor.color;
// ctx.fill();
// }else{
// ctx.moveTo(e.data[0][0] +3, e.data[0][1] -3);
// ctx.arc(e.data[0][0] + 3, e.data[0][1] - 3, 10, startAngle, endAngle);
// /*随机颜色*/
// ctx.fillStyle = e.color;
// ctx.fill();
// }
// }
// 直线
ctx.beginPath(); //新建路径
ctx.moveTo(e.data[1][0] * this.imgZoom,e.data[1][1] * this.imgZoom); //直线起点 x
ctx.lineTo(e.data[2][0] * this.imgZoom,e.data[2][1] * this.imgZoom); //绘直线至(x,y)坐标
ctx.strokeStyle = e.color;
ctx.stroke(); //绘制线条
// 竖线
ctx.beginPath(); //新建路径
ctx.moveTo(e.data[3][0] * this.imgZoom,e.data[3][1] * this.imgZoom); //直线起点 x
ctx.lineTo(e.data[4][0] * this.imgZoom,e.data[4][1] * this.imgZoom); //绘直线至(x,y)坐标
ctx.strokeStyle = e.color;
ctx.stroke(); //绘制线条
}
//绘制直线
if (e.type == "beeline") {
ctx.beginPath();
ctx.moveTo(e.data[0][0] * this.imgZoom, e.data[0][1] * this.imgZoom);
ctx.lineTo(e.data[1][0] * this.imgZoom, e.data[1][1] * this.imgZoom);
ctx.strokeStyle = e.color;
ctx.stroke();
}
//绘制矩形
if (e.type == "rectangle") {
ctx.beginPath();
ctx.strokeStyle = e.color;
ctx.strokeRect(
e.data[0][0] * this.imgZoom,
e.data[0][1] * this.imgZoom,
e.data[1][0] * this.imgZoom - e.data[0][0] * this.imgZoom,
e.data[1][1] * this.imgZoom - e.data[0][1] * this.imgZoom
); //绘制矩形边框
}
//绘制多边形
if (e.type == "polygon") {
ctx.beginPath();
ctx.strokeStyle = e.color;
ctx.moveTo(e.data[0][0] * this.imgZoom, e.data[0][1] * this.imgZoom); //起始点
//遍历多边形点列表连续绘制
e.data.forEach((p) => {
ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
});
ctx.stroke();
}
//绘制圆形
if (e.type == "circle") {
ctx.beginPath();
ctx.arc(
e.data[0][0] * this.imgZoom,
e.data[0][1] * this.imgZoom,
e.r * this.imgZoom,
0,
2 * Math.PI
);
ctx.strokeStyle = e.color;
ctx.stroke(); //绘制线条
}
});
//判断多边形临时列表是否有数据
if (this.polygonTempList.data && this.polygonTempList.data.length > 1) {
ctx.beginPath();
ctx.strokeStyle = this.polygonTempList.color;
ctx.moveTo(
this.polygonTempList.data[0][0] * this.imgZoom,
this.polygonTempList.data[0][1] * this.imgZoom
); //起始点
//遍历多边形点列表连续绘制
this.polygonTempList.data.forEach((p) => {
ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
});
//通过状态判断多边形是否闭合
if (this.polygonTempList.isClose) {
ctx.closePath(); //闭合
}
ctx.stroke();
}
},
拖拽
//鼠标拖拽
mouseDrag(e) {
this.canvasPosition.x = e.screenX + this.dragStart.x; //计算出画布位置
this.canvasPosition.y = e.screenY + this.dragStart.y;
},
放大缩小
//鼠标滚动事件(wheelDelta值上滚为负下滚为正)
async handleMouseWheel(e) {
let el = document.getElementById("myCanvas");
let oldX = el.offsetLeft; //旧位置
let oldY = el.offsetTop;
await this.changeCanvas(e, oldX, oldY); //改变画布
this.drawToArr(); // 重绘列表数据
},
//滚动时改变画布
changeCanvas(e, oldX, oldY) {
let zoomSpeed = 0.2; //缩放速度
e.wheelDelta > 0 && (zoomSpeed = 2 - zoomSpeed); // 判断放大与缩小
let posX = e.offsetX; //获取鼠标定点的位置(鼠标在图片上的位置)
let posY = e.offsetY;
let oldImgZoom = this.imgZoom; //记录下旧的图片缩放倍数
this.imgZoom = this.imgZoom * zoomSpeed; //更新缩放倍数
let minZoom = 0.3; //最小缩放倍数
let maxZoom = 3; //最大缩放倍数
this.imgZoom > maxZoom && (this.imgZoom = maxZoom); //限制缩放倍数
this.imgZoom < minZoom && (this.imgZoom = minZoom);
this.imgZoom = Number(this.imgZoom.toFixed(2));
zoomSpeed = this.imgZoom / oldImgZoom; //更新缩放速度
let height = Math.round(this.imgSize.height * this.imgZoom); //计算画布新宽高(原始宽高乘缩放倍数)
let width = Math.round(this.imgSize.width * this.imgZoom);
let newX = oldX + Math.round(posX * (1 - zoomSpeed)); //计算画布新位置(旧位置加偏移量)
let newY = oldY + Math.round(posY * (1 - zoomSpeed));
this.canvasSize = { height: height, width: width }; //更新画布尺寸
this.canvasPosition = { x: newX, y: newY }; //更新画布位置
},
明暗度调节 – 动态修改grayscale的值
<el-slider v-model="shading" :show-tooltip="false"></el-slider>