Return 屏幕调整大小后 JavaScript 中的图像坐标完全相同

Return Exact Same Image Coordinates in JavaScript After Screen Resize

我想检索足球场 png 上的确切坐标。我可以使用 offsetLeftoffsetTop 获得一些坐标,但不幸的是,一旦调整图像大小,或者在不同的分辨率或设备上打开页面,这些坐标就会开始变化。

Code Sandbox here

无论屏幕分辨率或设备如何,我都需要坐标完全相同,因为我想向用户打印用户点击的球场上的确切码数。在 JavaScript 中有没有办法做到这一点?我查看了 this answer,但有些内容有点令人困惑,我无法得到我想要的内容。

这是我的 React 代码:

import React, { useState } from "react";
import "./App.css";
import { Col, Container, Row } from "react-bootstrap";

import footballField from "./resources/images/AmFBfield.png";

function App() {
  const [x, setX] = useState(0);
  const [y, setY] = useState(0);
  const printCoordinates = (e) => {
    const x = e.pageX - e.currentTarget.offsetLeft;
    const y = e.pageY - e.currentTarget.offsetTop;

    setX(x);
    setY(y);
  };

  return (
    <Row>
      <Col sm={4}>
        {x}:{y}
      </Col>
      <Col sm={8}>
        <Container>
          <img
            id="football-field"
            src={footballField}
            alt="football-field"
            style={{ width: "80%", height: "80%" }}
            onClick={(e) => printCoordinates(e)}
          />
        </Container>
      </Col>
    </Row>
  );
}

export default App;

如果您只想在图像边界内保持一致的点击位置而不关心图像的内容,您可以简单地将点击相对于图像框架的 xy 偏移量转换为基于所显示图像的高度和宽度的百分比。

此处使用 MouseEvent.offsetX/Y to return the offset of the click relative to the image element directly (you can access this via the nativeEvent property of React's synthetic event),and element.getBoundingRect() 检索元素的高度和宽度。

const printCoordinates = (e) => {
  const { width, height } = e.target.getBoundingClientRect();
  const { offsetX, offsetY } = e.nativeEvent

  setX(Math.round((offsetX / width) * 100));
  setY(Math.round((offsetY / height) * 100));
};

但是,如果您想要相对于图像内容(即点击的实际码线)的坐标,则有两个选项。

最简单的方法是用多个部分创建 'pitch' 图像,将边界、端区和码数分成单独的图像,并对每个组件使用上述方法。

或者,要使用您拥有的单个图像,您需要通过从单击然后将这些校正后的单击偏移映射到实际间距在图像中占总图像的百分比。

这是一个粗略的图像百分比映射示例,其中边框+端区是图像宽度的 10%,上边框是图像高度的 5%。

const printCoordinates = (e) => {
  const { width, height } = e.target.getBoundingClientRect();
  const { offsetX, offsetY } = e.nativeEvent;

  // calculate percentage, subtract border/endzone percentage(10), map 80% to 100%, calculate yardage
  setX(Math.round(((((offsetX / width) * 100) - 10) / 80) * 100));
  // calculate percentage, subtract top-border percentage(5), map 90% to 100%, calculate yardage (53.3 yards total width)
  setY(Math.round(((((offsetY / height) * 100) - 5) / 90) * 53.3));
};

参见:codesandbox