以光标位置为变换原点缩放 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的主要内容,如果未能解决你的问题,请参考以下文章