如何在缩放的SVG中将屏幕坐标转换为文档空间?

14

我正在使用Keith Wood开发的SVG jQuery插件,而不是HTML5画布。

我如下所示定义我的svg图像,以使我的svg三角形图像适应其div容器:

  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" viewBox="0 0 299 215" >
    <g>
    <polygon points="1,1 299,1 149,210" fill="blue" stroke="blue" stroke-width="0" class="votenow"/>
    </g>
    </svg>

那么我如何匹配坐标系统呢?

我想在三角形的某个点捕获鼠标位置,并在这些X Y坐标处画一个圆圈,但由于坐标系统不匹配,圆圈会被画在不同的位置。

因此,圆将在点10,10处被绘制,但在50,60处显示,例如。

人们如何应对这种情况?

谢谢。

最终解决方案:使用JQuery插件绘制圆圈,并使用getScreenCTM()计算点的位置。

也许我不再需要JQuery插件,但现在可以用它。没看到只使用插件就能完成的方法。

$('#cvtriangle .tri').on( "click", function(e) {
    jqsvg = $('#cvtriangle').svg('get');
    svg = document.querySelector("svg");
    var pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    pt = pt.matrixTransform(svg.getScreenCTM().inverse());
    jqsvg.circle(pt.x, pt.y, 5, {class: 'vote', fill: 'white', stroke: 'white', strokeWidth: 2, cursor: 'pointer'});
});
2个回答

16

请参阅http://msdn.microsoft.com/en-us/library/hh535760%28v=vs.85%29.aspx。这是我的示例代码。对于此用途,getScreenCTM方法非常有用。

    <svg viewBox="0 0 300 300" onload="
        var c = document.getElementById('c');
        var cx = c.cx.baseVal;
        var cy = c.cy.baseVal;
        var svg = this;
        var point = svg.createSVGPoint();
        svg.onmousemove = function(e){
            point.x = e.clientX;
            point.y = e.clientY;
            var ctm = c.getScreenCTM();
            var inverse = ctm.inverse();
            var p = point.matrixTransform(inverse);
            cx.value = p.x;
            cy.value = p.y;
        };
    ">
        <rect width="100%" height="100%" fill="yellow"/>
        <circle id="c" r="10" fill="blue"/>
    </svg>


好的,我已经使用你的示例代码获取映射并使用JQuery SVG插件绘制了圆圈。 - Jon

12

如果在SVG元素上调用函数getScreenCTM(),它将返回用于将文档坐标转换为屏幕坐标的变换矩阵。你需要另一个方向的变换矩阵,因此在矩阵对象上调用inverse()

var transform = svg.getScreenCTM().inverse();

现在,您可以将一个点对象转换为执行最终转换:

pt = pt.matrixTransform(transform);

这里有一个可工作的演示

var x = document.getElementById("x"),
    y = document.getElementById("y"),
    svg = document.querySelector("svg");

svg.addEventListener("mousemove", function(evt) {
    var pt = svg.createSVGPoint();
    pt.x = evt.pageX;
    pt.y = evt.pageY;
    pt = pt.matrixTransform(svg.getScreenCTM().inverse());

    x.innerHTML = pt.x;
    y.innerHTML = pt.y;
}, false);
#container {
    width: 200px;
    height: 200px;
}
div {
    float: left;
    margin-left: 1em;
}
<div id="container">
    <svg version="1.0" viewbox="0 0 100 100">
        <rect x="0" y="0" width="100" height="100" fill="blue"/>
    </svg>
</div>

<div>
    x = <span id="x"></span><br/>
    y = <span id="y"></span>
</div>

如果上述版本(使用pageX/Y)不适用于您,请尝试使用此版本。

var x = document.getElementById("x"),
    y = document.getElementById("y"),
    svg = document.querySelector("svg");

svg.addEventListener("mousemove", function(evt) {
    var pt = svg.createSVGPoint();
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    pt = pt.matrixTransform(evt.target.getScreenCTM().inverse());

    x.innerHTML = pt.x;
    y.innerHTML = pt.y;
}, false);
#container {
    width: 200px;
    height: 200px;
}
div {
    float: left;
    margin-left: 1em;
}
<div id="container">
    <svg version="1.0" viewbox="0 0 100 100">
        <rect x="0" y="0" width="100" height="100" fill="blue"/>
    </svg>
</div>

<div>
    x = <span id="x"></span><br/>
    y = <span id="y"></span>
</div>


由于某些原因,pt.x = evt.pageX 没有起作用,但 pt.x = evt.clientX 起了作用,所以我选择了 defghi1977 的答案。感谢详细的回答,祝好! - Jon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接