用JavaScript实现了一个简单的图像坐标点标注工具

这段代码实现了一个简单的图像标注工具,允许用户在加载的图像上进行点选标注,并且通过右键确认一个点序列来形成一个多边形。

标注效果如下

实现代码如下

<!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>

代码中还包含了创建右键菜单的功能,但相关的菜单项(清空画布和复制坐标)被注释掉了。如果想启用这些功能,只需取消注释相应的代码行即可。

自己动手实现业务代码,这只是代码片段,具体实现还需要根据业务需要做相应的更改;

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值