Canvas 划线段,多边形,对其添加删除
目的:
最近需要做一个鼠标在图片上画框或者线段,获取当前多边形或者线段的在图片上的相对值坐标并且给框或者线段附以属性值存储起来,而且可以单个删除操作。
看效果图,鼠标移动到区域1,画布上的框会变成白色(提示你目前的),点击删除按钮,
区域1会删除,区域2变成区域1,鼠标移动到画布,画布上红色多边形会清除,只留下线段
大致思路:
对两个画布进行操作,一个用来监听获取当前点击画布的坐标,另一个把保存的左边连接起来展示多边形或线段。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<style>
#canvas {
text-align: center;
position: absolute;
left: 0;
top: 0;
z-index: 1;
cursor: crosshair;
}
#canvasImg {
position: absolute;
left: 0;
top: 0;
}
#operation {
text-align: center;
position: absolute;
right: 0;
top: 0;
z-index: 1;
cursor: crosshair;
width: 300px;
height: 600px;
}
</style>
<body>
<div style="height: 25rem;background-color: burlywood;">
<canvas id="canvas" width="800px" height="300px"></canvas>
<canvas id="canvasImg" width="600px" height="300px"></canvas>
</div>
<div id="operation">
<div id="polygons">
</div>
<button onclick="validBox()" type="button">清除</button>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="js/images-grid.js"></script>
<script>
// let deviceId= local_cam1;
let img = new Image();
let can = document.getElementById("canvas");
let context = can.getContext("2d");
let canImg = document.getElementById("canvasImg");
let contextImg = canImg.getContext("2d");
let width = $("#canvas").width();
let height = $("#canvas").height();
let originPoint = -1; //判let断鼠标是否移动到起始点处,-1为否,1为是
let pointArrays = []; //存放坐标的数组
let lineArrays = []; //存放线段的数组
let coordinateArrays = [];
let coordinateArraysCopy = [];
let pic = [];
let property, analysisTypeName, analysisType, threshold, time, pointX, pointY;
$(function() {
let result="{\"msg\":\"操作成功\",\"code\":0,\"data\":[{\"lineId\":1622094235739,\"coord\":\"93.0,40.0;159.0,33.0;148.0,102.0;94.0,86.0;93.0,40.0;800.0,600.0;\",\"threshold\":22,\"time\":2000,\"property\":\"向右街道\"}]}";
let res = JSON.parse(result);
if (res.code === 0) {
if (res.data.length > 0) {
for (var i = 0; i < res.data.length; i++) {
for (var f = 0; f < res.data[i].coord.split(";").length - 2; f++) {
if (res.data[i].coord.split(";")[f].split(",") === "") {
continue;
}
lineArrays.push({
x: res.data[i].coord.split(";")[f].split(",")[0],
y: res.data[i].coord.split(";")[f].split(",")[1]
});
};
lineArrays.push({
x: res.data[i].coord.split(";")[0].split(",")[0],
y: res.data[i].coord.split(";")[0].split(",")[1]
});
pic.push(lineArrays);
if (lineArrays.length > 0) {
coordinateArrays.push({
"id": res.data[i].lineId,
"points": lineArrays,
"property": res.data[i].property,
"analysisTypeName": res.data[i].alarmTypeName,
"analysisType": res.data[i].alarmType,
"threshold": res.data[i].threshold,
"time": res.data[i].time
});
}
lineArrays = [];
//画点
}
}
img.onload = function() {
// 将图片画到canvas上面上去!
contextImg.drawImage(img, 0, 0, width, height);
for (var i = 0; i < pic.length; i++) {
if (pic[i].length > 0) {
for (let f = 0; f < pic[i].length; f++) {
contextImg.lineTo(pic[i][f].x, pic[i][f].y);
contextImg.stroke(); //绘制
}
}
}
};
img.src =
'https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=233301930,3031623456&fm=11&gp=0.jpg';
} else {
let img = new Image();
img.onload = function() {
// 将图片画到canvas上面上去!
contextImg.drawImage(img, 0, 0, width, height);
};
img.src =
'https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=233301930,3031623456&fm=11&gp=0.jpg';
}
showArea();
listen();
})
function validBox(event) {
$("#canvas").unbind("click");
$("#canvas").unbind("mousemove");
contextImg.strokeStyle = 'red'; //线条颜色
context.strokeStyle = 'red'; //线条颜色
listen();
}
function listen() {
contextImg.strokeStyle = 'red'; //线条颜色
context.strokeStyle = 'red'; //线条颜色
document.oncontextmenu = function(e) {
e.preventDefault();
};
let pix, piy;
document.getElementById("canvas").onmousedown = function(e) {
if (e.button == 2) {
pointX = e.offsetX === undefined ? e.layerX : e.offsetX;
pointY = e.offsetY === undefined ? e.layerY : e.offsetY;
if (pointArrays.length > 1) {
pix = pointArrays[0].x;
piy = pointArrays[0].y;
//画点
makearc(context, pointX, pointY, GetRandomNum(5, 5), 0, 180, 'red');
pointArrays.push({
x: pix,
y: piy
});
canSaveTocanImg(pointArrays); //保存点线同步到canvasImg
saveCanvas();
showArea();
}
} else if (e.button == 0) {
if (e.offsetX || e.layerX) {
pointX = e.offsetX === undefined ? e.layerX : e.offsetX;
pointY = e.offsetY === undefined ? e.layerY : e.offsetY;
let pix, piy;
if (originPoint > 0 && pointArrays.length > 0) {
pix = pointArrays[0].x;
piy = pointArrays[0].y;
//画点
makearc(context, pointX, pointY, GetRandomNum(5, 5), 0, 180, 'red');
pointArrays.push({
x: pix,
y: piy
});
canSaveTocanImg(pointArrays); //保存点线同步到canvasImg
saveCanvas();
showArea();
} else {
piX = pointX;
piY = pointY;
makearc(context, pointX, pointY, GetRandomNum(5, 5), 0, 180, 'red');
pointArrays.push({
x: piX,
y: piY
});
canSaveTocanImg(pointArrays); //保存点线同步到canvasImg
}
}
}
}
$(can).mousemove(function(e) {
if (e.offsetX || e.layerX) {
pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
let piX, piY;
/*清空画布*/
context.clearRect(0, 0, can.width, can.height);
/*鼠标下跟随的圆点*/
makearc(context, pointX, pointY, GetRandomNum(4, 4), 0, 180, 'red');
if (pointArrays.length > 0) {
if ((pointX > pointArrays[0].x - 15 &&
pointX < pointArrays[0].x + 15) &&
(pointY > pointArrays[0].y - 15 && pointY < pointArrays[0].y + 15)) {
if (pointArrays.length > 1) {
context.clearRect(0, 0, can.width, can.height);
piX = pointArrays[0].x;
piY = pointArrays[0].y;
originPoint = 1;
}
} else {
piX = pointX;
piY = pointY;
originPoint = -1;
}
/*开始绘制*/
context.beginPath();
context.moveTo(pointArrays[0].x, pointArrays[0].y);
if (pointArrays.length > 1) {
for (let i = 1; i < pointArrays.length; i++) {
context.lineTo(pointArrays[i].x, pointArrays[i].y);
}
}
context.lineTo(piX, piY);
context.stroke(); //绘制
}
}
});
}
// 存储已生成的点线到图片contextImg
function canSaveTocanImg(pointArrays) {
contextImg.clearRect(0, 0, contextImg.width, contextImg.height);
contextImg.beginPath();
if (pointArrays.length > 0) {
contextImg.moveTo(pointArrays[0].x, pointArrays[0].y);
for (let i = 0; i < pointArrays.length - 1; i++) {
contextImg.lineTo(pointArrays[i].x, pointArrays[i].y);
contextImg.stroke(); //绘制
}
contextImg.closePath();
}
}
function makearc(context, x, y, r, s, e, color) {
context.beginPath();
context.fillStyle = color;
context.arc(x, y, r, s, e);
context.fill();
}
/*canvas生成圆点*/
function GetRandomNum(Min, Max) {
let Range = Max - Min;
let Rand = Math.random();
return (Min + Math.round(Rand * Range));
}
/*生成画布 结束绘画*/
function saveCanvas() {
// context.clearRect(0, 0, can.width, can.height);
contextImg.closePath(); //结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
contextImg.stroke(); //绘制calibration
for (let i = 0; i < pointArrays.length - 1; i++) {
lineArrays.push(
pointArrays[i]
)
}
if (pointArrays.length > 0) {
let obj = {
"id": new Date().getTime(),
"points": lineArrays,
"property": property,
"analysisTypeName": analysisTypeName,
"analysisType": analysisType,
"threshold": threshold
};
coordinateArrays.push(obj);
}
pointArrays = [];
lineArrays = [];
let obj = {};
obj.width = $("#canvas").width();
obj.height = $("#canvas").height();
obj.list = coordinateArrays;
console.log(JSON.stringify(coordinateArrays))
}
function saveCanvasNew() {
context.clearRect(0, 0, can.width, can.height);
contextImg.closePath(); //结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
contextImg.stroke(); //绘制calibration
for (let i = 0; i < pointArrays.length - 1; i++) {
lineArrays.push(
pointArrays[i]
)
}
if (pointArrays.length > 0) {
let obj = {
"points": lineArrays,
};
coordinateArrays.push(obj);
}
pointArrays = [];
lineArrays = [];
}
function showArea() {
$("#polygons").empty();
if (coordinateArrays.length === 0) {
deviceInfo(coordinateArraysCopy)
} else {
if (coordinateArraysCopy.length > 0) {
coordinateArrays = coordinateArraysCopy;
}
deviceInfo(coordinateArrays);
}
}
function deviceInfo(coordinateArrays) {
for (let i = 1; i <= coordinateArrays.length; i++) {
let html = '<input type="hidden" class="selector-id" id="event-id' + i +
'"><div style="border: 1px solid white" class="area" id="area' + i +
'"><label>区域' + i + ':';
html += "<br>";
html +=
'<label>街道名称:</label><input type="text" placeholder="请输入街道名称" class="selector-property" id="event-property' +
i +
'" style="width:65%;color:black;margin-left:2%" />';
html +=
'<label>阈 值:</label><input type="text" placeholder="请输入阈值" class="selector-input" id="event-threshold' +
i +
'" style="width:65%;color:black;margin-left:2%" />';
html +=
'<label>时 间:</label><input type="text" placeholder="请输入时间(按秒计算)" class="selector-time" id="event-time' +
i +
'" style="width:65%;color:black;margin-left:2%" /><button οnclick="delPoints()">删除</button>';
$("#polygons").append(html);
// 设置默认选中值
$("#event-property" + i).val(coordinateArrays[i - 1].property);
$("#event-threshold" + i).val(coordinateArrays[i - 1].threshold);
$("#event-time" + i).val(coordinateArrays[i - 1].time);
$("#event-id" + i).val(coordinateArrays[i - 1].time);
}
//添加事件
$(".area").hover(function() {
context.strokeStyle = '#ffffff';
context.lineWidth = 2;
let i = $(this).attr("id").split("ea")[1];
highlightPoint(coordinateArrays[i - 1].points);
}, function() {
context.strokeStyle = '#ffffff'; //线条颜色
context.lineWidth = 1; //线条粗细
context.clearRect(0, 0, 800, 600);
});
//街道名称
$(".selector-property").change(function() {
let id = $(this).attr("id");
let i = id.split("-property")[1] - 1;
coordinateArrays[i].property = $(this).val();
});
//阈值
$(".selector-threshold").change(function() {
let id = $(this).attr("id");
let i = id.split("-threshold")[1] - 1;
coordinateArrays[i].threshold = $(this).val();
});
//间隔时间
$(".selector-time").change(function() {
let id = $(this).attr("id");
let i = id.split("-time")[1] - 1;
coordinateArrays[i].time = $(this).val();
});
}
//画框变白
function highlightPoint(point) {
context.beginPath();
context.moveTo(point[0].x, point[0].y);
for (let i = 1; i < point.length; i++) {
context.lineTo(point[i].x, point[i].y);
}
context.lineTo(point[0].x, point[0].y);
context.stroke(); //绘制
context.closePath();
}
//删除线段
function delPoints() {
contextImg.clearRect(0, 0, canImg.width, canImg.height);
img.src =
'https://dss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=233301930,3031623456&fm=11&gp=0.jpg';;
$(".area").hover(function() {
let num = $(this).attr("id").split("ea")[1];
coordinateArrays.splice(num - 1, 1);
coordinateArraysCopy = coordinateArrays;
coordinateArrays = [];
console.log(JSON.stringify(coordinateArraysCopy))
cleanCoordinatePoints();
showArea();
});
pic = [];
}
function cleanCoordinatePoints() {
for (let i = 0; i < coordinateArraysCopy.length; i++) {
for (var n = 0; n < coordinateArraysCopy[i].points.length; n++) {
pointArrays.push({
x: coordinateArraysCopy[i].points[n].x,
y: coordinateArraysCopy[i].points[n].y
})
}
pointArrays.push({
x: coordinateArraysCopy[i].points[0].x,
y: coordinateArraysCopy[i].points[0].y
})
//画点
context.strokeStyle = "red";
contextImg.strokeStyle = 'red'; //线条颜色
canSaveTocanImg(pointArrays); //保存点线同步到canvasImg
saveCanvasNew();
context.stroke();
}
}
</script>
</html>
当前这个没达到我的预期效果,我想着是可以对线段或多边形进行拖拽和某个点位拖拽,不用删除重新画,但是目前没有思路。因为项目功能临时要求只能先做成这样。
代码可直接食用