核心原理就是推算出放大或者缩小后,鼠标位置相对于原本位置的偏移量,这个自己画个图,以x轴与轴的偏移量,算一下就能得到这个公式:
// 相对偏移量left= 盒子(图片)距离浏览器最左侧距离 - (鼠标位置 - 盒子(图片)距离浏览器最左侧距离)* 倍率
// 相对偏移量top= 盒子(图片)距离浏览器最上侧距离 - (鼠标位置 - 盒子(图片)距离浏览器最上侧距离)* 倍率
效果演示:(鼠标位置没被录制下来,实际操作鼠标在哪就应该以哪里为中心放大,图片以鼠标为中心,向四周放大延申不同的距离)
附源代码:也就不到 100行,两个功能,一个是 跟随鼠标移动,一个是放大缩小
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
position: absolute;
background-image: url('../images/0.jpg');/* 图片自己换一下*/
background-size: contain;
background-repeat: no-repeat;
/* transform: scale(1,1); */
/* transform: translate(45px, 25px); */
}
.mywarp {
width: 1000px;
height: 500px;
overflow: hidden;
position: relative;
}
</style>
</head>
<body>
<div class="mywarp">
<div id="box" class="box"></div>
</div>
<script>
let box = document.getElementById('box');
// 只负责移动,这个是可以随意移动盒子的代码,不需要可以不要
box.onmousedown = function (e) {
// 先跟随鼠标移动
var mouseDownX = e.clientX;//鼠标x轴位置
var mouseDownY = e.clientY;//鼠标y轴位置
//getComputedStyle 是浏览器自带的一个方法,用于获取节点的所有style属性
var boxDownTop = parseFloat(getComputedStyle(box).top);
var boxDownLeft = parseFloat(getComputedStyle(box).left);
console.log(mouseDownX, mouseDownY)
function mouseMove(e) {
e.stopPropagation();
e.preventDefault();
// 触发移动事件
let mouseX = e.clientX;//鼠标x轴位置
let mouseY = e.clientY;//鼠标y轴位置
//获取点击位置必须是这个box 的距离最左侧与最上方可视区域位置
let boxTop = parseFloat(getComputedStyle(box).top);
let boxLeft = parseFloat(getComputedStyle(box).left);
// 用鼠标位置 减去 盒子的 上左距离就是 实际鼠标在盒子内部的偏差值
let wantX = mouseX - boxLeft;
let wantY = mouseY - boxTop;
//让盒子跟随鼠标动,x,y值立刻改变,但是默认状态是0,所以,第一步盒子的x,y是等于鼠标位置的
// 第二步的时候,盒子更新位置,是第一次的位置,导致了始终无法同步位置
// 鼠标点击位置,记录下来,用于计算偏移量
box.style.top = mouseY - (mouseDownY - boxDownTop) + 'px';
box.style.left = mouseX - (mouseDownX - boxDownLeft) + 'px';
}
function mouseUp(e) {
document.removeEventListener('mousemove', mouseMove, {passive: false})
}
document.addEventListener('mousemove', mouseMove, {passive: false})
document.addEventListener('mouseup', mouseUp, {passive: false})
}
let scale = 1;
// 只负责 在盒子(图片)上放大缩小
var mouseWheelStatus = true;//这个参数用与防抖控制,因为鼠标滚一下,实际上会被触发几十次,加个50毫秒延时,可以有效阻止
box.onmousemove = function (e) {
if (mouseWheelStatus) {
mouseWheelStatus = false;
function onWheel (e) {
setTimeout(() => {
if (e.altKey) {
let thatWidth = box.getBoundingClientRect().width;
let thatHeight = box.getBoundingClientRect().height;
// 放大与缩小 的标志
var delta = e.deltaY > 0 ? -0.1 : 0.1;
var maxScale = 3, minScale = 0.05;
var x = e.clientX, y = e.clientY;
var bound = box.getBoundingClientRect();
var imgX = x - bound.left, imgY = y - bound.top;
scale = Math.min(maxScale, Math.max(minScale, scale * (1 + delta)));
var newWidth = 640 * scale;
var newHeight = 480 * scale;
var perX = imgX / thatWidth, perY = imgY / thatHeight;
resize(newWidth, newHeight, perX, perY);
e.stopPropagation();
e.preventDefault();
mouseWheelStatus = true;
}
}, 50);
}
}
box.addEventListener('mousewheel', onWheel, {passive: false})
};
var resize = function (width, height, perX, perY) {
var that = this;
var boxWarp = box;
var bound = boxWarp.getBoundingClientRect();
boxWarp.style.height = width + 'px';
boxWarp.style.width = width + 'px';
boxWarp.width = width;
boxWarp.height = height;
var style = getComputedStyle(boxWarp);
var marginLeft = parseFloat(style.marginLeft);
var marginTop = parseFloat(style.marginTop);
boxWarp.style.width = width + 'px';
boxWarp.style.height = height + 'px';
var newBound = boxWarp.getBoundingClientRect();
//这段是核心,原理差不多,根据缩放比列来完成图像的位置控制,保证缩放后鼠标还在原地
boxWarp.style.marginLeft = marginLeft - perX * (newBound.right - bound.right) - (1 - perX) * (newBound.left - bound.left) + 'px';
boxWarp.style.marginTop = marginTop - perY * (newBound.bottom - bound.bottom) - (1 - perY) * (newBound.top - bound.top) + 'px';
}
</script>
</body>
</html>