如何使用JavaScript缩放点?

时间:2018-01-04 14:38:57

标签: javascript html css

我的网络项目需要在鼠标转动时将鼠标位置周围的div元素缩放为锚点,我受@Tata​​rize在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>

3 个答案:

答案 0 :(得分:3)

真的很不可思议,我确实做到了。

&#13;
&#13;
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;
&#13;
&#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>