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

需求:基于React实现获取图片原始尺寸对应的坐标点

实现基于图片原始尺寸的坐标点获取

核心思路

要获取不依赖CSS显示尺寸的原始坐标,关键是计算显示尺寸与原始尺寸的缩放比例,再将点击的显示坐标转换为原始坐标:

  • 利用图片原生属性naturalWidth/naturalHeight获取原始尺寸
  • 通过getBoundingClientRect()获取图片当前的显示尺寸
  • 计算缩放比例:scaleX = 原始宽度 / 显示宽度,scaleY = 原始高度 / 显示高度
  • 最终原始坐标 = 点击的显示坐标 × 对应缩放比例

修改后的完整代码

import React, { useState } from 'react';
import src from "../assets/testCoordinate.jpeg";
import ReactPlayer from 'react-player'
import Select from "react-select"

const ImageDetection = () => {
    const [isSelecting, setIsSelecting] = useState(false);
    // 显示坐标:用于页面上标记点的定位
    const [startX, setStartX] = useState(null);
    const [startY, setStartY] = useState(null);
    const [endX, setEndX] = useState(null);
    const [endY, setEndY] = useState(null);
    // 原始尺寸坐标:最终需要的目标结果
    const [startOriginalX, setStartOriginalX] = useState(null);
    const [startOriginalY, setStartOriginalY] = useState(null);
    const [endOriginalX, setEndOriginalX] = useState(null);
    const [endOriginalY, setEndOriginalY] = useState(null);
    const [imageWidth, setImageWidth] = useState(null);
    const [imageHeight, setImageHeight] = useState(null);

    const handleClick = (event) => {
        const { offsetX, offsetY } = event.nativeEvent;
        const { width: displayWidth, height: displayHeight } = event.currentTarget.getBoundingClientRect();
        const { naturalWidth: originalWidth, naturalHeight: originalHeight } = event.currentTarget;

        // 计算显示尺寸到原始尺寸的缩放比例
        const scaleX = originalWidth / displayWidth;
        const scaleY = originalHeight / displayHeight;

        // 转换为原始尺寸下的坐标
        const originalX = offsetX * scaleX;
        const originalY = offsetY * scaleY;

        if (isSelecting) {
            setEndX(offsetX);
            setEndY(offsetY);
            setEndOriginalX(Math.round(originalX));
            setEndOriginalY(Math.round(originalY));
            setIsSelecting(false);
            console.log(`原始终点坐标: (${originalX.toFixed(2)}, ${originalY.toFixed(2)})`);
        } else {
            setStartX(offsetX);
            setStartY(offsetY);
            setStartOriginalX(Math.round(originalX));
            setStartOriginalY(Math.round(originalY));
            setIsSelecting(true);
            console.log(`原始起点坐标: (${originalX.toFixed(2)}, ${originalY.toFixed(2)})`);
        }
    };

    const startMarkerStyle = {
        position: 'absolute',
        left: `${startX}px`,
        top: `${startY}px`,
        width: '10px',
        height: '10px',
        backgroundColor: 'green',
        borderRadius: '50%',
        zIndex: 2,
    };

    const endMarkerStyle = {
        position: 'absolute',
        left: `${endX}px`,
        top: `${endY}px`,
        width: '10px',
        height: '10px',
        backgroundColor: 'red',
        borderRadius: '50%',
        zIndex: 2,
    };

    const lineStyle = {
        position: 'absolute',
        zIndex: 1,
        left: 0,
        top: 0,
        width: '100%',
        height: '100%',
    };

    const handleImageLoad = (event) => {
        const { naturalWidth, naturalHeight } = event.target;
        setImageWidth(naturalWidth);
        setImageHeight(naturalHeight);
    };

    return (
        <div style={{ position: 'relative', }} >
            <img
                src={src}
                alt="Test Image"
                onClick={handleClick}
                className='w-[740px] h-[540px]'
                onLoad={handleImageLoad}
                style={{ display: 'block' }} // 消除行内元素默认留白,避免坐标计算偏差
            />
            {startX !== null && (
                <div style={startMarkerStyle}></div>
            )}
            {endX !== null && (
                <div style={endMarkerStyle}></div>
            )}
            {startX !== null && endX !== null && (
                <svg style={lineStyle}>
                    <line x1={startX} y1={startY} x2={endX} y2={endY} stroke="blue" strokeWidth="2" />
                </svg>
            )}
            {imageWidth && imageHeight && (
                <p>图片原始尺寸: {imageWidth} x {imageHeight}</p>
            )}
            {startOriginalX !== null && (
                <p>原始起点坐标: ({startOriginalX}, {startOriginalY})</p>
            )}
            {endOriginalX !== null && (
                <p>原始终点坐标: ({endOriginalX}, {endOriginalY})</p>
            )}
        </div>
    );
};

export default ImageDetection;

关键修改说明

  • 新增原始坐标状态变量,专门存储转换后的目标结果
  • 在点击事件中完成显示坐标到原始坐标的比例转换
  • 给标记点添加zIndex,确保标记点在SVG线条上方显示
  • 给图片设置display: block,避免默认行内元素留白影响坐标计算
  • 用Math.round()和toFixed(2)优化坐标的显示精度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:07:34