如何使用 JavaScript 放大一个点?

Sug*_*uge 1 html javascript css

我的 web 项目需要div在鼠标滚轮时将鼠标位置周围的元素缩放为锚点,我的灵感来自 @Tata​​rize 在Zoom in 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 + ')';
    }
}
Run Code Online (Sandbox Code Playgroud)
.yellow {
    background-color: yellow;
    width: 400px;
    height: 200px;
}

.red {
    background-color: red;
    width: 100px;
    height: 50px;
}
Run Code Online (Sandbox Code Playgroud)
<div class="yellow">
    <div id="red" class="red"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

Sug*_*uge 5

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

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 + ')';
    }
}
Run Code Online (Sandbox Code Playgroud)
.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;
}
Run Code Online (Sandbox Code Playgroud)
<div class="yellow">
    <div id="red" class="red"></div>
</div>
Run Code Online (Sandbox Code Playgroud)