以光标位置为变换原点缩放 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>
我正在尝试使用触控板缩放 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>