这段代码实现了一个简单的图像标注工具,允许用户在加载的图像上进行点选标注,并且通过右键确认一个点序列来形成一个多边形。
标注效果如下
实现代码如下
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Image Annotation</title><style>canvas {border: 1px solid black; /* 给画布添加边框 */}</style>
</head>
<body><!-- 文件输入控件 -->
<input type="file" id="file-input">
<!-- 用于显示图像和标注的画布 -->
<canvas id="image-canvas"></canvas><script>const fileInput = document.getElementById('file-input'); // 获取文件输入元素const canvas = document.getElementById('image-canvas'); // 获取画布元素const ctx = canvas.getContext('2d'); // 获取画布的2D渲染上下文let drawing = false; // 标记是否正在绘图let ix = -1, iy = -1; // 当前鼠标位置的坐标let points = []; // 当前正在绘制的点列表let pointList = []; // 已完成的点列表// 当选择文件时触发fileInput.addEventListener('change', function (event) {const file = event.target.files[0]; // 获取选择的文件const reader = new FileReader(); // 创建文件读取器// 文件读取完成后执行reader.onload = function (event) {const img = new Image(); // 创建图像对象img.src = event.target.result; // 将读取的数据赋值给图像源// 图像加载完成后执行img.onload = function () {canvas.width = img.width; // 设置画布宽度为图像宽度canvas.height = img.height; // 设置画布高度为图像高度ctx.drawImage(img, 0, 0); // 在画布上绘制图像};};reader.readAsDataURL(file); // 开始读取文件});// 右键菜单处理canvas.addEventListener('contextmenu', (event) => {event.preventDefault(); // 阻止默认的右键菜单// 创建自定义菜单const menu = document.createElement('div');menu.style.position = 'absolute';menu.style.left = event.clientX + 'px';menu.style.top = event.clientY + 'px';menu.style.backgroundColor = 'white';menu.style.border = '1px solid black';// 清空画布菜单项const clearItem = document.createElement('div');clearItem.textContent = '清空画布';clearItem.style.padding = '5px';clearItem.addEventListener('click', () => {//ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布// 恢复绘图状态ctx.restore();menu.remove(); // 移除菜单});//menu.appendChild(clearItem);// 复制坐标菜单项const copyItem = document.createElement('div');copyItem.textContent = '复制坐标';copyItem.style.padding = '5px';copyItem.addEventListener('click', () => {if (pointList.length > 0) {navigator.clipboard.writeText("(" + pointList[pointList.length - 1].join('),(') + ")");alert('坐标已复制到剪贴板');}menu.remove(); // 移除菜单});//menu.appendChild(copyItem);document.body.appendChild(menu); // 将菜单添加到页面return false;});// 鼠标按下事件canvas.addEventListener('mousedown', function (event) {if (event.button === 0) { // 左键点击drawing = true;[ix, iy] = [event.offsetX, event.offsetY]; // 获取鼠标位置points.push([ix, iy]); // 添加到点列表drawCircle(ix, iy); // 绘制点drawText(ix, iy); // 绘制点坐标文本} else if (event.button === 2) { // 右键点击if (points.length > 1) {ctx.beginPath();ctx.moveTo(points[points.length - 1][0], points[points.length - 1][1]);ctx.lineTo(points[0][0], points[0][1]);ctx.strokeStyle = 'green';ctx.lineWidth = 2;ctx.stroke();pointList.push([...points]);console.log(points);//navigator.clipboard.writeText("(" + points.join('),(') + ")");points = [];}ctx.drawImage(canvas, 0, 0);}});// 鼠标抬起事件canvas.addEventListener('mouseup', function (event) {if (event.button === 0) {drawing = false;if (points.length > 1) {ctx.beginPath();ctx.moveTo(points[points.length - 2][0], points[points.length - 2][1]);ctx.lineTo(points[points.length - 1][0], points[points.length - 1][1]);ctx.strokeStyle = 'green';ctx.lineWidth = 2;ctx.stroke();}ctx.drawImage(canvas, 0, 0);}});// 鼠标移出画布事件canvas.addEventListener('mouseout', function () {drawing = false;});// 绘制点函数function drawCircle(x, y) {ctx.beginPath();ctx.arc(x, y, 3, 0, Math.PI * 2);ctx.fillStyle = 'blue';ctx.fill();}// 绘制点坐标文本函数function drawText(x, y) {ctx.font = '16px Arial';ctx.fillStyle = 'red';let text = "(" + x + "," + y + ")";ctx.fillText(text, x, y);}</script></body>
</html>
代码中还包含了创建右键菜单的功能,但相关的菜单项(清空画布和复制坐标)被注释掉了。如果想启用这些功能,只需取消注释相应的代码行即可。
自己动手实现业务代码,这只是代码片段,具体实现还需要根据业务需要做相应的更改;