JSFiddle - React, Tailwind, and code Playground
HTML
<div class="container">
<div class="wrapper">
<div class="image-wrapper">
<img class="viewer-img" src="https://cdn.pixabay.com/photo/2020/06/08/17/54/rain-5275506_960_720.jpg" draggable="false" />
</div>
</div>
</div>
CSS
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
.container {
width: 100%;
height: 100%;
position: relative;
}
.wrapper {
width: 100%;
height: 100%;
overflow: hidden;
transition: all 0.1s;
position: relative;
}
.image-wrapper {
position: absolute;
}
.wrapper img {
position: absolute;
transform-origin: top left;
}
.point {
width: 4px;
height: 4px;
background: #f00;
position: absolute;
}
JavaScript
let wrapper = document.querySelector(".wrapper");
let image = wrapper.querySelector(".image-wrapper");
let img = document.querySelector('img')
let scale = 1;
let accx = 0, accy = 0
image.querySelector("img").addEventListener("wheel", (e) => {
if (e.deltaY < 0) {
scale = Number((scale * 1.2));
accx += Number(e.offsetX * scale/1.2 - e.offsetX * scale)
accy += Number(e.offsetY * scale/1.2 - e.offsetY * scale)
} else {
scale = Number((scale / 1.2));
accx += Number(e.offsetX * scale * 1.2 - e.offsetX * scale)
accy += Number(e.offsetY * scale * 1.2 - e.offsetY * scale)
}
e.target.style.transform = `scale3D(${scale}, ${scale}, ${scale})`
image.style.transform = `translate(${accx}px, ${accy}px)`;
});