有没有办法从svg元素获取屏幕/窗口坐标? 我已经看到了相反的解决方案,如:
function transformPoint(screenX, screenY) {
var p = this.node.createSVGPoint()
p.x = screenX
p.y = screenY
return p.matrixTransform(this.node.getScreenCTM().inverse())
}
但我需要的是屏幕坐标。
Sory如果这是一个明显的问题,但我是svg的新手。 感谢。
答案 0 :(得分:3)
您在问题中包含的代码会将屏幕坐标转换为SVG坐标。换句话说,你必须做与该功能相反的事情。
getScreenCTM()
返回转换坐标所需的矩阵。请注意,代码调用inverse()
?那就是反转矩阵,使其在另一个方向上进行转换。
所以您需要做的就是从该代码中移除inverse()
来电。
var svg = document.getElementById("mysvg");
function screenToSVG(screenX, screenY) {
var p = svg.createSVGPoint()
p.x = screenX
p.y = screenY
return p.matrixTransform(svg.getScreenCTM().inverse());
}
function SVGToScreen(svgX, svgY) {
var p = svg.createSVGPoint()
p.x = svgX
p.y = svgY
return p.matrixTransform(svg.getScreenCTM());
}
var pt = screenToSVG(20, 30);
console.log("screenToSVG: ", pt);
var pt = SVGToScreen(pt.x, pt.y);
console.log("SVGToScreen: ", pt);

<svg id="mysvg" viewBox="42 100 36 40" width="100%">
</svg>
&#13;
答案 1 :(得分:2)
当我想要做同样的事情时,我正在玩这个片段(了解哪个屏幕坐标对应于SVG坐标)。我想简而言之,这就是你所需要的:
了解SVG元素的当前转换矩阵(您感兴趣的坐标),粗略地说:matrix = element.getCTM();
然后大致得到屏幕位置:position = point.matrixTransform(matrix),其中“point”是SVGPoint。
请参阅下面的代码段。我通过改变浏览器窗口大小来改变svg坐标以匹配div元素的坐标
std::apply(m_method, m_args);
// main SVG:
var rootSVG = document.getElementById("rootSVG");
// SVG element (group with rectangle inside):
var rect = document.getElementById("rect");
// SVGPoint that we create to use transformation methods:
var point = rootSVG.createSVGPoint();
// declare vars we will use below:
var matrix, position;
// this method is called by rootSVG after load:
function init() {
// first we learn current transform matrix (CTM) of the element' whose screen (not SVG) coordinates we want to learn:
matrix = rect.getCTM();
// then we "load" SVG coordinates in question into SVGPoint here:
point.x = 100; // replace this with the x co-ordinate of the path segment
point.y = 300; // replace this with the y co-ordinate of the path segment
// now position var will contain screen coordinates:
position = point.matrixTransform(matrix);
console.log(position)
// to validate that the coordinates are correct - take these x,y screen coordinates and apply to CSS #htmlRect to change left, top pixel position. You will see that the HTML div element will get placed into the top left corner of the current svg element position.
}
html, body {
margin: 0;
padding: 0;
border: 0;
overflow:hidden;
background-color: #fff;
}
svg {
position: fixed;
top:0%;
left:0%;
width:100%;
height:100%;
background:#fff;
}
#htmlRect {
width: 10px;
height: 10px;
background: green;
position: fixed;
left: 44px;
top: 132px;
}
答案 2 :(得分:1)
innerWidth
,screenX
,clientX
等... 我不确定您要搜索的内容,但是当您提出screenX
,screenY
和 SVG 时,我会让您使用片段编辑器和一些小尝试。
请注意, SVG边界框已修复为[0, 0, 500, 200]
并显示为width="100%" height="100%"
。
单击圆圈时,tspan
的最后一行带有指针的打印x
和y
。
function test(e) {
var sctm=new DOMMatrix();
var invs=new DOMMatrix();
sctm=e.target.getScreenCTM();
invs=sctm.inverse();
document.getElementById("txt1").innerHTML=
sctm.a+", "+sctm.b+", "+sctm.c+", "+sctm.d+", "+sctm.e+", "+sctm.f;
document.getElementById("txt2").innerHTML=
invs.a+", "+invs.b+", "+invs.c+", "+invs.d+", "+invs.e+", "+invs.f;
document.getElementById("txt3").innerHTML=
e.screenX+", "+e.screenY+", "+e.clientX+", "+e.clientY;
var vbox=document.getElementById("svg").getAttribute('viewBox').split(" ");
var sx=1.0*innerWidth/(1.0*vbox[2]-1.0*vbox[0]);
var sy=1.0*innerHeight/(1.0*vbox[3]-1.0*vbox[0]);
var scale;
if (sy>sx) scale=sx;else scale= sy;
document.getElementById("txt4").innerHTML=
e.clientX/scale+", "+e.clientY/scale;
}
<svg id="svg" viewBox="0 0 500 200" width="100%" height="100%" >
<circle cx="25" cy="25" r="15" onclick="javascript:test(evt);" />
<text>
<tspan x="10" y="60" id="txt1">test</tspan>
<tspan x="10" y="90" id="txt2">test</tspan>
<tspan x="10" y="120" id="txt3">test</tspan>
<tspan x="10" y="150" id="txt4">test</tspan>
</text>
</svg>
答案 3 :(得分:0)
不确定为什么以前没有建议过,但是`Element.getBoundingClientRect()应该足够了:
const {
top, // x position on viewport (window)
left, // y position on viewport (window)
} = document.querySelector('rect').getBoundingClientRect()
我认为其他答案可能来自Craig Buckler在SitePoint上推广的方法,他在该方法中解释了如何使用SVGElement API(而不是来自-DOM-Element API的getBoudingClientRect)将DOM转换为SVG坐标反之亦然。
但是 1。。这里仅需要DOM坐标。 2。。他声称在应用转换(通过CSS或SVG)时使用getBoundingClientRect会返回不正确的值,以转换为SVG坐标,但是当前的getBoundingClientRect规范考虑了这些转换。
getClientRects()方法在被调用时必须返回以下算法的结果:[...]
如果元素具有关联的SVG布局框,则返回一个DOMRectList对象,该对象包含单个DOMRect对象,该对象描述了SVG规范定义的元素的边界框,并应用适用于该元素及其祖先的变换。 >
规范: https://drafts.csswg.org/cssom-view/#extension-to-the-element-interface
答案 4 :(得分:0)
2020
Safari当前存在一些错误,如果您使用的是过渡,旋转或缩放的SVG(或SVG容器),则使该问题变得相当困难。
getScreenCTM()
在返回的矩阵中不包括祖先比例和旋转变换。 (如果您的svg既没有旋转也没有缩放,那么这就是解决方法。)
但是,如果您知道正在缩放和/或旋转的祖先元素及其变换值,则可以手动修复getScreenCTM()
提供的矩阵。解决方法如下所示:
let ctm = ele.getScreenCTM();
// -- adjust
let ancestorScale = // track yourself or derive from window.getComputedStyle()
let ancestorRotation = // track yourself or derive from window.getComputedStyle()
ctm = ctm.scale(ancestorScale)
ctm = ctm.rotate(ancestorRotation)
// Note: avoid ctm.scaleSelf etc. On some systems the matrix is a true blue SVGMatrix (opposed to a DOMMatrix) and may not support these transform-in-place methods
// --
// repeat 'adjust' for each ancestor, in order from closest to furthest from ele. Mind the order of the scale/rotation transformations on each ancestor.
如果您不了解祖先...我想出的最好的办法就是跋涉在树上,通过getComputedStyle寻找转换,根据树的深度,转换可能会非常慢... < / p>
getBoundingClientRect()
在转换时可能返回不正确的值。如果您不是对事物进行动画处理,但是您正在 进行事物转换,那么这也许是可行的方法,尽管我很确定它的性能明显不如getScreenCTM。理想情况下,在SVG中插入一个非常小的元素,使其边界矩形有效地成为一个点。
window.getComputedStyles().transform
具有与上述相同的问题。