方案一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
.container {
width: 600px;
height: 400px;
overflow: hidden;
}
.preview {
display: inline-block;
width: 100%;
height: 100%;
}
.img {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="preview">
<img class="img" src="./test.png" alt="" />
</div>
</div>
</body>
<script>
const img = document.querySelector(".img");
const preview = document.querySelector(".preview");
const container = document.querySelector(".container");
const imageParams = {
naturalHeight: img.naturalHeight,
naturalWidth: img.naturalWidth,
};
let factor = {
translate: {
x: 0,
y: 0,
},
scale: 1,
rotate: 0,
};
let spurs = [];
container.addEventListener("wheel", function (e) {
const previewWidth = container.getBoundingClientRect().width;
const previewHeight = container.getBoundingClientRect().height;
const x = e.clientX - container.getBoundingClientRect().x;
const y = e.clientY - container.getBoundingClientRect().y;
const delta = -e.deltaY;
let scaleVal = delta > 0 ? 0.2 : -0.2;
factor.scale += scaleVal;
if (factor.scale < 1) {
factor = {
translate: {
x: 0,
y: 0,
},
scale: 1,
rotate: 0,
};
}
const m = delta > 0 ? 0.1 : -0.1;
factor.translate.x += -x * m * 2 + previewWidth * m;
factor.translate.y += -y * m * 2 + previewHeight * m;
preview.style.transform = `translate(${factor.translate.x}px, ${factor.translate.y}px) scale(${factor.scale})`;
});
preview.onclick = function (e) {
const needWidth = e.offsetX / (container.clientWidth / img.naturalWidth);
const needHeight =
e.offsetY / (container.clientHeight / img.naturalHeight);
const left = needWidth * (container.clientWidth / img.naturalWidth);
const top = needHeight * (container.clientHeight / img.naturalHeight);
const span = document.createElement("span");
span.style.width = "10px";
span.style.height = "10px";
span.style.borderRadius = "5px";
span.style.background = "red";
span.style.position = "absolute";
span.style.left = left + "px";
span.style.top = top + "px";
span.style.transform = "translate(-50%, -50%)";
preview.appendChild(span);
};
</script>
</html>
方案二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
#container {
width: 500px;
height: 500px;
position: relative;
overflow: hidden;
}
#image {
width: 100%;
height: 100%;
transition: transform 0.2s;
transform-origin: 0 0;
}
</style>
</head>
<body>
<div id="container">
<img src="./test.png" id="image" />
</div>
</body>
<script>
const container = document.getElementById("container");
const image = document.getElementById("image");
let factor = {
scale: 1,
};
container.addEventListener("wheel", (event) => {
event.preventDefault();
const scaleDelta = event.deltaY * -1;
const offsetX = event.offsetX / container.clientWidth;
const offsetY = event.offsetY / container.clientHeight;
const scaleVal = scaleDelta > 0 ? 0.2 : -0.2;
factor.scale += scaleVal;
if (factor.scale < 1) {
factor = {
scale: 1,
};
}
image.style.transformOrigin = `${offsetX * 100}% ${offsetY * 100}%`;
image.style.transform = `scale(${factor.scale})`;
});
</script>
</html>
方案三
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
#container {
width: 500px;
height: 500px;
position: relative;
overflow: hidden;
}
#preview {
width: 100%;
height: 100%;
}
#image {
width: 100%;
height: 100%;
transition: transform 0.2s;
transform-origin: 0 0;
}
</style>
</head>
<body>
<div id="container">
<div id="preview">
<img src="./test.png" id="image" />
</div>
</div>
</body>
<script>
const preview = document.querySelector("#preview");
const container = document.getElementById("container");
const image = document.getElementById("image");
let factor = {
scale: 1,
};
const imageParams = {
naturalHeight: image.naturalHeight,
naturalWidth: image.naturalWidth,
};
preview.addEventListener("wheel", (event) => {
event.preventDefault();
const scaleDelta = event.deltaY * -1;
const offsetX = event.offsetX / preview.clientWidth;
const offsetY = event.offsetY / preview.clientHeight;
const scaleVal = scaleDelta > 0 ? 0.2 : -0.2;
factor.scale += scaleVal;
if (factor.scale < 1) {
factor = {
scale: 1,
};
}
preview.style.transformOrigin = `${offsetX * 100}% ${offsetY * 100}%`;
preview.style.transform = `scale(${factor.scale})`;
});
preview.onclick = function (e) {
const needWidth =
e.offsetX / (container.clientWidth / image.naturalWidth);
const needHeight =
e.offsetY / (container.clientHeight / image.naturalHeight);
const left = needWidth * (container.clientWidth / image.naturalWidth);
const top = needHeight * (container.clientHeight / image.naturalHeight);
const span = document.createElement("span");
span.style.width = "10px";
span.style.height = "10px";
span.style.borderRadius = "5px";
span.style.background = "red";
span.style.position = "absolute";
span.style.left = left + "px";
span.style.top = top + "px";
span.style.transform = "translate(-50%, -50%)";
span.onwheel = function (e) {
e.stopPropagation();
};
preview.appendChild(span);
};
</script>
</html>