You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript图片绘制矩形:onmousemove事件定位异常问题求助

图片上绘制矩形偏移问题的解决方案

问题根源

事件处理中使用的e.offsetX和e.offsetY会随事件目标变化:当鼠标移动到已显示的矩形元素上时,offsetX/Y会以矩形为参照计算,而非外层的wrapper容器,导致矩形位置计算错误。

修复方案

改用clientX/Y结合元素的绝对位置计算,确保始终获取相对于wrapper的坐标。修改后的完整代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title>CSS Units px/in test</title>
        <meta name="description" content="">
        <meta name="viewport"
              content="width=device-width, initial-scale=1, maximum-scale=1">
    </head>


    <body>
        <style>
            .wrapper {
                position:relative;
            }

            .boxOnImage {
                display: none;
                position:absolute;
                border:2px solid #ff6666;
                background-color:transparent
            }
        </style>

        <div id="imageMeasurement" class="wrapper">
            <img id="innerImage" src="https://www.w3schools.com/html/img_chania.jpg"/>
            <div id="boxOnImage" class="boxOnImage"></div>
        </div>
        <script>
            (function () {
                var xs = -1;
                var ys = -1;
                var xe = -1;
                var ye = -1;
                var imageMeasurement = document.getElementById("imageMeasurement");
                var box = document.getElementById("boxOnImage");
                
                function getRelativeCoords(e) {
                    const rect = imageMeasurement.getBoundingClientRect();
                    return {
                        x: e.clientX - rect.left,
                        y: e.clientY - rect.top
                    };
                }

                function isInImage(x, y) {
                    var innerImage = document.getElementById("innerImage");
                    return x <= innerImage.offsetWidth && y <= innerImage.offsetHeight;
                }

                imageMeasurement.addEventListener("mousemove", function (e) {
                    const {x, y} = getRelativeCoords(e);
                    if (isInImage(x, y)) {
                        if ((xe == -1 && ye == -1) && (xs != -1 && ys != -1)) {
                            createRectangleOnImage(xs, x, ys, y);
                        }
                    }
                });

                imageMeasurement.addEventListener("click", function (e) {
                    const {x, y} = getRelativeCoords(e);
                    if (isInImage(x, y)) {
                        if (xs == -1 && ys == -1) {
                            xs = x;
                            ys = y;
                        } else if (xe == -1 && ye == -1) {
                            xe = x;
                            ye = y;
                            createRectangleOnImage(xs, xe, ys, ye);
                        } else {
                            xe = x;
                            ye = y;
                            createRectangleOnImage(xs, xe, ys, ye);
                        }
                    }
                });

                document.addEventListener("keyup", function (e) {
                    if (e.keyCode == 27) {
                        xs = -1;
                        ys = -1;
                        xe = -1;
                        ye = -1;
                        removeRectangleOnImage();
                    }
                });

                function createRectangleOnImage(xs, xe, ys, ye) {
                    if (box.style.display != 'block') {
                        box.style.display = 'block';
                    }

                    var top = Math.min(ys, ye);
                    var left = Math.min(xs, xe);
                    var width = Math.abs(xe - xs);
                    var height = Math.abs(ye - ys);

                    box.style.top = `${top}px`;
                    box.style.left = `${left}px`;
                    box.style.width = `${width}px`;
                    box.style.height = `${height}px`;
                }

                function removeRectangleOnImage() {
                    box.style.display = "none";
                }
            })();
        </script>
    </body>
</html>

关键改动说明

  1. 新增getRelativeCoords函数:通过getBoundingClientRect()获取wrapper的视口位置,用clientX/Y减去偏移量,得到稳定的相对坐标。
  2. 替换所有e.offsetX/Y的使用:统一调用getRelativeCoords获取坐标,避免事件目标变化导致的偏移。
  3. 简化矩形计算逻辑:用Math.min和Math.abs替代原有的分支判断,代码更简洁易读。

内容的提问来源于stack exchange,提问作者FarHooD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 06:42:27