I have an image. for this i would like to get the touch events start, move and end. I need the exact image-pixel of the touch.
The Problem is that the actual image is smaller than the HTMLImageElement.
(css style object-fit: scale-down
)
I don't need the touch events for the HTMLImageElement but the actual image itself.
How do I archive this?
btw. I use React (if this helps) but I can (hopefully) adapt the answer myself.
Current Attempt:
<img ...
onTouchStart={(event) => {
const touch = event.changedTouches[0];
const rect = event.currentTarget.getBoundingClientRect();
const pxlX = touch.screenX - rect.left;
const pxlY = touch.screenY - rect.top;
// other stuff with (pxlX, pxlY)
}} />
My Solution in the end
import { useState } from "react";
import ImageSrc from "./assets/image.png";
export default function App() {
const [text, setText] = useState("undefined");
return <div className="w-screen h-screen overflow-hidden">
<img src={ImageSrc} alt="" className="object-scale-down w-full h-full" onMouseMove={(event) => {
const {x, y} = getXY(event);
setText(`${x}/${y}`);
}} />
<span className="fixed top-0 left-0 pointer-events-none">{text}</span>
</div>;
}
function getXY(event: React.MouseEvent<HTMLImageElement, MouseEvent>): {x: number, y: number} {
const img = event.currentTarget;
const [imgWidth, imgHeight] = [img.naturalWidth, img.naturalHeight];
const [boxWidth, boxHeight] = [img.width, img.height];
const imgRatio = imgWidth / imgHeight;
const boxRatio = boxWidth / boxHeight;
if (imgRatio < boxRatio) {
const x0 = (boxWidth - boxHeight * imgWidth/imgHeight) / 2;
const x = Math.round(event.nativeEvent.offsetX - x0);
return {x: x, y: event.nativeEvent.offsetY};
} else {
const y0 = (boxHeight - boxWidth * imgHeight/imgWidth) / 2;
const y = Math.round(event.nativeEvent.offsetY - y0);
return {x: event.nativeEvent.offsetX, y: y};
}
}
Use img.naturalHeight and img.naturalWidth to determine the position at which the effective image starts.
Briefly, the following quantity will be negative if the Y of the event is relative to a point above the image, so capture it in your event and check:
y0 = (400 - 400*mainImg.naturalHeight/mainImg.naturalWidth)/2;
var effectiveY = event.offsetY - y0;
A little math is involved here, feel free to ask if you need a general description when the image can be a portrait, or if you still need help detecting events below the image.
var y0;
window.addEventListener("load", function(ev) {
y0 = (400 - 400*mainImg.naturalHeight/mainImg.naturalWidth)/2;
});
mainImg.addEventListener("mousemove", function(ev) {
infoDiv.innerText = ev.offsetY - y0;
});
img {
object-fit: scale-down;
border: 1px solid #AAA;
}
effectiveY is:
<span id="infoDiv"></span>
<br>
<img id="mainImg" src="https://st.hzcdn.com/simgs/pictures/gardens/garden-with-oval-lawns-fenton-roberts-garden-design-img~1971dc9307c80c73_4-8900-1-60a5647.jpg" width=400 height=400>