以光标位置为变换原点缩放 SVG

Scaling SVG with cursor position as transform origin

我正在尝试使用触控板缩放 SVG 圆圈(通过移动两根手指 up/down),变换的原点必须是光标的位置。缩放第一次表现良好,并且对于每一次其他尝试,圆圈都会改变位置(它不应该)。如果光标位于圆圈内并靠近圆周,则可以清楚地看到这一点。下面是代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" content="width=device-width">

    <style>
        .container
        {
            position: fixed;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
        }

    </style>
</head>
<body>


<div class="container">
    <svg id="svg" height="600" width="600">
        <circle cx="300" cy="300" r="300" stroke="black" stroke-width="3" fill="white"/>
    </svg>
</div>

<script>
    let scale = 1;
    const e = document.getElementById("svg");

    function wheelZoom(event)
    {
        event.preventDefault();

        scale += event.deltaY * -0.01;
        scale = Math.min(Math.max(.5, scale), 2);

        x = 100*(event.clientX-e.getBoundingClientRect().x)/e.getBoundingClientRect().width;
        y = 100*(event.clientY-e.getBoundingClientRect().y)/e.getBoundingClientRect().height;

        e.style.transformOrigin = `${x}% ${y}%`;
        e.style.transform = `scale(${scale})`;
    }

    e.addEventListener("wheel", wheelZoom);
</script>


</body>
</html>

我不确定几件事:

  • 你的意思是你不希望圆圈改变位置
  • 还有你是真的想要缩放整个 SVG,还是只缩放 SVG 中的圆圈

在下面的演示中,我保持 SVG 不变,但根据滚动鼠标滚轮时您在 SVG 中的位置缩放圆圈

希望这就是您所追求的。

//    let scale = 1;
const svg = document.getElementById("svg");
const circle = document.querySelector("svg circle");

// Circle transform. Inits to 1:1 scale (called an "identity transform").
var   circleTransform = svg.createSVGMatrix();  // start

svg.addEventListener("wheel", wheelZoom);


function wheelZoom(event)
{
   event.preventDefault();

   // Get the mouse position as SVG coordinates
   var coords = convertScreenCoordsToSvgCoords(event.clientX, event.clientY);

   // Calculate an appropriate scale adjustment
   var scale = 1.0 + (event.deltaY * 0.001);

   // To scale around the mouse coords, first we transform the coordinate
   // system so that the origin is at the mouse coords.
   circleTransform = circleTransform.translate(coords.x, coords.y);
   // Then we apply the scale
   circleTransform = circleTransform.scale(scale, scale);
   // Finally we move the coordinate system back to where it was
   circleTransform = circleTransform.translate(-coords.x, -coords.y);

   // Now we need to update the circle's transform
   var transform = svg.createSVGTransform();        // An SVGTransform DOM object...
   transform.setMatrix(circleTransform);            // set to the new circleTransform...
   circle.transform.baseVal.initialize(transform);  // and used to update the circle transform property
}


function convertScreenCoordsToSvgCoords(x, y) {
   var pt = svg.createSVGPoint();  // An SVGPoint SVG DOM object
   pt.x = x;
   pt.y = y;
   // getScreenCTM tells us the combined transform that determines where 
   // the circle is rendered. Including any viewBox.
   // We use the inverse of that to convert the mouse X and Y to their
   // equivalent values inside the SVG.
   pt = pt.matrixTransform(circle.getScreenCTM().inverse());
   return {'x': pt.x, 'y': pt.y};
}
svg {
  background-color: linen;
}
<div class="container">
   <svg id="svg" height="600" width="600">
      <circle cx="300" cy="300" r="300" stroke="black" stroke-width="3" fill="white"/>
   </svg>
</div>