如何将svg元素坐标转换为屏幕坐标?

时间:2018-01-19 14:36:15

标签: javascript svg

有没有办法从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的新手。 感谢。

5 个答案:

答案 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;
&#13;
&#13;

答案 1 :(得分:2)

当我想要做同样的事情时,我正在玩这个片段(了解哪个屏幕坐标对应于SVG坐标)。我想简而言之,这就是你所需要的:

  1. 了解SVG元素的当前转换矩阵(您感兴趣的坐标),粗略地说:matrix = element.getCTM();

  2. 然后大致得到屏幕位置:position = point.matrixTransform(matrix),其中“point”是SVGPoint。

  3. 请参阅下面的代码段。我通过改变浏览器窗口大小来改变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)

使用innerWidthscreenXclientX等...

我不确定您要搜索的内容,但是当您提出screenXscreenY SVG 时,我会让您使用片段编辑器和一些小尝试。

请注意, SVG边界框已修复为[0, 0, 500, 200]并显示为width="100%" height="100%"

单击圆圈时,tspan的最后一行带有指针的打印xy

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

支持: https://caniuse.com/#feat=getboundingclientrect

答案 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具有与上述相同的问题。