我的网络项目需要在鼠标转动时将鼠标位置周围的div
元素缩放为锚点,我受@Tatarize在Zoom in on a point (using scale and translate)的回答的启发,但我无法完全实现它,它无法缩放和平移鼠标位置,任何人都可以帮忙吗?
window.onload = function() {
const STEP = 0.05;
const MAX_SCALE = 10;
const MIN_SCALE = 0.01;
const red = document.getElementById('red');
const yellow = red.parentNode;
let scale = 1;
yellow.onmousewheel = function (event) {
event.preventDefault();
let mouseX = event.clientX - yellow.offsetLeft - red.offsetLeft;
let mouseY = event.clientY - yellow.offsetTop - red.offsetTop;
const factor = event.wheelDelta / 120;
const oldScale = scale;
scale = scale + STEP * factor;
scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
const scaleChanged = scale - oldScale;
const offsetX = -(mouseX * scaleChanged);
const offsetY = -(mouseY * scaleChanged);
console.log(offsetX, offsetY);
red.style.transform = 'translate(' + offsetX + 'px, ' + offsetY + 'px)' + 'scale(' + scale + ')';
}
}
.yellow {
background-color: yellow;
width: 400px;
height: 200px;
}
.red {
background-color: red;
width: 100px;
height: 50px;
}
<div class="yellow">
<div id="red" class="red"></div>
</div>
答案 0 :(得分:3)
真的很不可思议,我确实做到了。
window.onload = () => {
const STEP = 0.99;
const MAX_SCALE = 5;
const MIN_SCALE = 0.01;
const red = document.getElementById("red");
const yellow = red.parentNode;
let scale = 1;
const rect = red.getBoundingClientRect();
const originCenterX = rect.x + rect.width / 2;
const originCenterY = rect.y + rect.height / 2;
yellow.onwheel = (event) => {
event.preventDefault();
const factor = event.deltaY;
// If current scale is equal to or greater than MAX_SCALE, but you're still zoom in it, then return;
// If current scale is equal to or smaller than MIN_SCALE, but you're still zoom out it, then return;
// Can not use Math.max and Math.min here, think about it.
if ((scale >= MAX_SCALE && factor < 0) || (scale <= MIN_SCALE && factor > 0)) return;
const scaleChanged = Math.pow(STEP, factor);
scale *= scaleChanged;
const rect = red.getBoundingClientRect();
const currentCenterX = rect.x + rect.width / 2;
const currentCenterY = rect.y + rect.height / 2;
const mousePosToCurrentCenterDistanceX = event.clientX - currentCenterX;
const mousePosToCurrentCenterDistanceY = event.clientY - currentCenterY;
const newCenterX = currentCenterX + mousePosToCurrentCenterDistanceX * (1 - scaleChanged);
const newCenterY = currentCenterY + mousePosToCurrentCenterDistanceY * (1 - scaleChanged);
// All we are doing above is: getting the target center, then calculate the offset from origin center.
const offsetX = newCenterX - originCenterX;
const offsetY = newCenterY - originCenterY;
// !!! Both translate and scale are relative to the original position and scale, not to the current.
red.style.transform = 'translate(' + offsetX + 'px, ' + offsetY + 'px)' + 'scale(' + scale + ')';
}
}
&#13;
.yellow {
background-color: yellow;
width: 200px;
height: 100px;
margin-left: 50px;
margin-top: 50px;
position: absolute;
}
.red {
background-color: red;
width: 200px;
height: 100px;
position: absolute;
}
&#13;
<div class="yellow">
<div id="red" class="red"></div>
</div>
&#13;
答案 1 :(得分:1)
.onmousewheel 。请改用 .onwheel 。
此外, onwheel 事件没有 wheelDelta 属性。使用 deltaY 。
答案 2 :(得分:1)
我给出的代码是关于缩放点更改视图框。您正在根据一些不适合该情况的数学运动矩形。
想法是根据比例的变化平移缩放框。您正在更改矩形的位置和位置。也就是说你需要模拟红色矩形的新位置,就像黄色矩形是一个视口一样。这意味着当我们放大时,我们会放大特定比例因子的translateX translateY位置。然后,我们需要将缩放点的值转换为正确的场景空间。然后调整红色矩形的位置,就好像它在那个场景空间中一样。
这里的代码有一些更正,但我显然缺少一些元素。最重要的是缺乏translateX translateY的保存。你覆盖它所以最终只保留缩放并拧紧translateX,当它是视口的相对偏移时,将它转换回零。
在功能代码中,放大矩形将使红色矩形填满整个场景空间。
window.onload = function() {
const STEP = 0.05;
const MAX_SCALE = 10;
const MIN_SCALE = 0.01;
const red = document.getElementById('red');
const yellow = document.getElementById('yellow');
const svgArea = document.getElementById('svgArea');
let viewportTranslateX = 0;
let viewportTranslateY = 0;
let viewportScale = 1;
svgArea.onwheel = function (event) {
event.preventDefault();
console.log("mouse coords", event.clientX, event.clientY);
let zoompointX = (event.clientX + (viewportTranslateX / viewportScale)) * viewportScale;
let zoompointY = (event.clientY + (viewportTranslateY / viewportScale)) * viewportScale;
console.log("zoom point prezoom", zoompointX, zoompointY);
const factor = event.deltaY / 120;
const oldScale = viewportScale;
viewportScale = viewportScale * (1 + STEP * factor);
viewportScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, viewportScale));
const scaleChanged = viewportScale - oldScale;
const offsetX = -(zoompointX * scaleChanged);
const offsetY = -(zoompointY * scaleChanged);
console.log("scale", scaleChanged, offsetX, offsetY);
viewportTranslateX += offsetX;
viewportTranslateY += offsetY;
zoompointX = (event.clientX + (viewportTranslateX / viewportScale)) * viewportScale;
zoompointY = (event.clientY + (viewportTranslateY / viewportScale)) * viewportScale;
console.log("zoompoint postzoom", zoompointX, zoompointY);
var x = viewportTranslateX;
var y = viewportTranslateY;
var width = (svgArea.getAttribute("width") * viewportScale);
var height = (svgArea.getAttribute("height") * viewportScale);
svgArea.setAttribute("viewBox", x + " " + y + " " + width + " " + height);
console.log("viewport", x, y, width, height, viewportScale);
}
}
<svg id="svgArea" width=400 height=200 viewBox="0,0,400,200">
<rect id="yellow" width=400 height=200 fill="yellow"/>
<rect id="red" width=100 height=50 fill="red"/>
</svg>