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

Posted

技术标签:

【中文标题】以光标位置为变换原点缩放 SVG【英文标题】:Scaling SVG with cursor position as transform origin 【发布时间】:2022-01-11 00:39:52 【问题描述】:

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

<!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"  >
        <circle cx="300" cy="300" r="300" stroke="black" stroke- 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>

【问题讨论】:

这是因为变换原点改变了位置:如果您从最左边或最右边的边缘点将圆缩放两倍,那么圆的大小将相同但在不同的位置。如果你不想要这个,你必须计算相对于前一个变换原点的变换原点 @mrmonsieur 感谢您的评论。你能告诉我具体怎么做吗?我最近开始学习 html、css 和 javascript,我尝试了所有我能想到的方法,但没有结果。 【参考方案1】:

我不确定有几件事:

你不希望圆圈改变位置是什么意思 您是否真的希望整个 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"  >
      <circle cx="300" cy="300" r="300" stroke="black" stroke- fill="white"/>
   </svg>
</div>

【讨论】:

@Paul_Lebeau 谢谢你的回答。它就像我试图做的那样工作。我不介意是缩放整个 SVG 还是仅缩放圆形。通过“更改位置”,我的意思是当我滚动鼠标滚轮时,圆圈在被缩放之前被移动,而不是仅仅被缩放。谢谢,你的回答对我很有帮助。 我发现 D3 库可以使用 d3.zoom() 轻松完成此功能。它在 Chrome 和 Safari 中运行良好,但在 Firefox 中形状会保持模糊一段时间。您的方法适用于所有这些浏览器。

以上是关于以光标位置为变换原点缩放 SVG的主要内容,如果未能解决你的问题,请参考以下文章

计算在鼠标光标位置放大的视图偏移

动画 SVG 组对象 - 使用样式组件进行变换旋转不会围绕圆原点旋转

如何在缩放投影矩阵Opengl的同时平移光标位置

Safari SVG 变换原点缩放动画

svg子元素上的CSS变换原点问题

qwt 在重新缩放或缩放光标后绘制移动曲线