实现一个可缩放并支持滚动的图片容器
在这篇博客中,我将介绍如何实现一个简单的交互功能:在一个 div 中放置一张图片,通过鼠标拖动操作实现图片缩放,并且在图片放大后,滚动条能够调整位置以查看被放大的部分。
以下是具体实现的代码和步骤。
功能概述
- 鼠标交互:当按下鼠标时记录初始位置;松开鼠标时,根据鼠标的移动方向和距离来决定图片的缩放系数。
- 缩放中心:缩放以鼠标按下位置为基准。
- 滚动支持:图片放大后,容器的滚动条会调整位置,保证缩放基准点的位置始终保持相对稳定。
为什么这里要通过移动滚动条的位置,而不是直接通过计算鼠标按下点的横纵轴比例使用transformOrigin属性变换图片,是因为scale放大图片的时候,如果不是以(0,0)作为基点,那么上下左右都可能超出容器,而滚动条只有在右边和下边超出容器的时候才会出现,而且初始滚动条位置是0的位置,那么就会导致图片的左上部分可能出现被裁剪的情况。(还有一种方式是直接通过修改图片的宽高,这时候因为是图片的实际尺寸变化了,所以滚动条是可以显示全部图片的,这种相比transform的性能开销更大,因为浏览器需要重新计算布局)
HTML 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Zoom with Scroll</title>
<style>
body {
margin: 0;
overflow: hidden;
}
.container {
position: relative;
width: 1200px;
height: auto;
overflow: auto;
background: #f0f0f0;
cursor: grab;
}
img {
display: block;
transform-origin: center;
transition: transform 0.1s ease;
}
</style>
</head>
<body>
<div class="container" id="zoomContainer">
<img src="C:\Users\27643\Pictures\Screenshots\スクリーンショット 2024-05-14 014320.png" alt="Zoomable Image"
id="zoomImage" draggable="false">
</div>
<script>
const container = document.getElementById('zoomContainer');
const image = document.getElementById('zoomImage');
let scale = 1;
let isMouseDown = false;
let startX, startY;
let endX, endY;
image.addEventListener('mousedown', (e) => {
e.preventDefault();
isMouseDown = true;
startX = e.clientX - container.offsetLeft;
startY = e.clientY - container.offsetTop;
console.log("start: " + startX + " " + startY);
});
image.addEventListener('mousemove', (e) => {
if (!isMouseDown) return;
endX = e.clientX - container.offsetLeft;
endY = e.clientY - container.offsetTop;
console.log("end: " + endX + " " + endY);
});
image.addEventListener('mouseup', () => {
if (!isMouseDown) return;
isMouseDown = false;
if (startX === undefined || startY === undefined || endX === undefined || endY === undefined) {
return;
}
const deltaX = endX - startX;
const deltaY = endY - startY;
const movementMagnitude = Math.sqrt(deltaX ** 2 + deltaY ** 2);
const movementDirection = deltaX + deltaY; // Positive: zoom in, Negative: zoom out
const zoomFactor = 1 + (movementDirection > 0 ? 1 : -1) * movementMagnitude * 0.001;
const newScale = Math.min(10, Math.max(0.3, scale * zoomFactor));
console.log(newScale);
const cursorX = startX + container.scrollLeft;
const cursorY = startY + container.scrollTop;
const cursorRatioX = cursorX / (image.offsetWidth * scale);
const cursorRatioY = cursorY / (image.offsetHeight * scale);
scale = newScale;
const newCursorX = cursorRatioX * (image.offsetWidth * scale);
const newCursorY = cursorRatioY * (image.offsetHeight * scale);
image.style.transform = `scale(${scale})`;
image.style.transformOrigin = "0 0";
container.scrollLeft = newCursorX - startX;
container.scrollTop = newCursorY - startY;
startX = undefined;
startY = undefined;
endX = undefined;
endY = undefined;
});
container.addEventListener('mouseleave', () => {
isMouseDown = false;
});
</script>
</body>
</html>
实现细节
样式部分
容器 .container
设置 position: relative 和 overflow: auto,保证图片可以超出容器并通过滚动条查看。
使用固定宽度和自适应高度。
图片样式
通过 transform-origin: center 控制缩放的基准点。
transition: transform 0.1s ease 用于增加平滑的缩放过渡效果。
脚本部分
鼠标事件监听
mousedown:记录鼠标按下时的坐标。
mousemove:跟踪鼠标移动(可选,仅用于调试)。
mouseup:计算鼠标的位移,决定缩放方向和缩放比例。
缩放基准点
使用 transform-origin 属性,使图片基于左上顶点变换,从而能够让滚动条显示完整图片
计算容器滚动条的位置,保证缩放后鼠标位置相对于容器保持不变。
滚动条调整
根据鼠标点击点与图片的相对位置,调整滚动条的 scrollLeft 和 scrollTop,保证用户能查看到缩放后的区域。
缩放逻辑
计算鼠标移动的方向和距离:
const deltaX = endX - startX;
const deltaY = endY - startY;
const movementMagnitude = Math.sqrt(deltaX ** 2 + deltaY ** 2);
const movementDirection = deltaX + deltaY;
根据 movementDirection 决定是放大还是缩小。
限制缩放比例在合理范围内(0.3 到 10 倍):
const newScale = Math.min(10, Math.max(0.3, scale * zoomFactor));
总结
这段代码实现了图片的基于鼠标交互的缩放功能,并且通过合理调整滚动条位置,让用户能够查看被放大图片的细节区域。如果你有类似的需求,可以直接复用或根据自己的场景进一步优化!
浙公网安备 33010602011771号