原理
在画布上遍历数据画框,如果是两个有关系的数组,存一个 A 数组,遍历另一个的同时取之前存好的 A 数组的数据,根据 canvas api 画线。
效果图
返回值示例
具体实现
drawAlarmBox(row) { //row是后端返回的值,是一组对象
this.bigCanvas = true;
this.$nextTick(() => {
var canvas = document.getElementById("alarmBigCanvas");
let arrFrame = [];
let centerPoint = []; //底边中心
let frames = [];
if (row.frame.startsWith("[")) {
frames = JSON.parse(row.frame); //得到需要画框的点的数组
} else {
frames = [row.frame];
}
var context = canvas.getContext("2d"); //建立一个 CanvasRenderingContext2D 二维渲染上下文。
var ratioX = "";
var ratioY = "";
context.clearRect(0, 0, 900, 500);
var newImg = new Image(); //创建图片对象
// newImg.crossOrigin = 'anonymous';
newImg.setAttribute("crossOrigin", "*");
newImg.src = row.alarmPicture;
arrFrame = row.frame.split("-");
newImg.onload = () => {
ratioX = div.accDiv(canvas.width, row.width); //精确除出画布和图片的宽高比例
ratioY = div.accDiv(canvas.height, row.height);
context.drawImage(newImg, 0, 0, canvas.width, canvas.height);//在画布上画图
context.beginPath();
context.font = "24px sans-serif"; //文字大小
context.fillStyle = "red"; //文字颜色
context.fillText("文字描述", 10, 25); //文字位置
frames.forEach((ele, i) => { //遍历出每个报警框
arrFrame = ele.split("-"); //根据指定符号拆分字符串
if (arrFrame.length === 4) {
let width = arrFrame[3] - arrFrame[2];
let height = arrFrame[1] - arrFrame[0];
let left = mul.accMul(ratioX, arrFrame[2]); //左
let top = mul.accMul(ratioY, arrFrame[0]);
let ratioWidth = mul.accMul(ratioY, width); //精确将画布比例和点之间的宽高相乘,得出相对宽高
let ratioHeight = mul.accMul(ratioY, height); //高
context.rect(left, top, ratioWidth, ratioHeight); //在画布上连出四个点的相对位置,即报警框
context.font = "18px sans-serif"; //报警框内文字大小
context.fillStyle = "#fff";//报警框内文字颜色
context.strokeStyle = "red"; //报警框线的颜色
context.fillText(i, left, top + 18);//报警框内文字位置
centerPoint.push({ //※※将所有框的中心点存为对象数组,以便在遍历框和框之间关系时取值
left: left + ratioWidth / 2,
top: top + ratioHeight //这里高度也/2,得到的就是重心点
});
}
});
// console.log("中心", centerPoint);
context.lineWidth = 2;
context.stroke();
context.closePath();
let relationMapping =
row.releationMapping && JSON.parse(row.releationMapping); //判断是否有框的关系字段,如果没有,不往下走
for (let key in relationMapping) { //※※遍历框之间的关系,同时取出每两个有关系的中心点连线
let arrIndex = key.split("-");
var point1 = centerPoint[arrIndex[0]]; //第一个点
var point2 = centerPoint[arrIndex[1]]; //第二个点
if (point1 && point2) {
//如果按index获取不到点,就不画了,画能画的关系,防止一个报错,全部画不出来
context.fillText(
relationMapping[key].toFixed(2) + "米",
point1.left + (point2.left - point1.left) / 2 - 24,
point1.top + (point2.top - point1.top) / 2 - 18
); //根据中心点确定距离文字的左上角坐标,标记距离
context.beginPath();
context.moveTo(point1.left, point1.top); //线起始位置
context.lineTo(point2.left, point2.top); //线停止位置
context.stroke();
}
}
// 清空新创建的canvas
this.canvasLength = 0;
};
});
}
// 浮点数精确计算除
module.exports = {
accDiv: function(num1, num2) {
var t1, t2, r1, r2;
try {
t1 = num1.toString().split(".")[1].length;
} catch (e) {
t1 = 0;
}
try {
t2 = num2.toString().split(".")[1].length;
} catch (e) {
t2 = 0;
}
r1 = Number(num1.toString().replace(".", ""));
r2 = Number(num2.toString().replace(".", ""));
return (r1 / r2) * Math.pow(10, t2 - t1);
}
// 浮点数精确计算乘
module.exports = {
accMul: function(num1, num2) {
var m = 0,
s1 = num1.toString(),
s2 = num2.toString();
try {
m += s1.split(".")[1].length;
} catch (e) {}
try {
m += s2.split(".")[1].length;
} catch (e) {}
return (
(Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
Math.pow(10, m)
);
}
};