尽管伪造了getBoundingClientRect(),你如何将事件坐标转换为SVG坐标? [英] How do you transform event coordinates to SVG coordinates despite bogus getBoundingClientRect()?

查看:125
本文介绍了尽管伪造了getBoundingClientRect(),你如何将事件坐标转换为SVG坐标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据鼠标的位置动态绘制SVG元素上的东西。不幸的是,我很难将mousemove事件中的鼠标坐标转换为SVG元素的坐标空间。

I'm experimenting with dynamically drawing things on an SVG element based on the position of the mouse. Unfortunately, I'm having difficulty translating the mouse coordinates from the mousemove event into the coordinate space of the SVG element.

这是我测试的一个错误函数:

Here is a buggy function I've been testing:

CylinderDemo.prototype.handleMouseMove = function(evt)
{
    debugEvent = evt;

    var bcr = evt.target.getBoundingClientRect();
    var x2 = evt.clientX - bcr.left;
    var y2 = evt.clientY - bcr.top;

    console.log(evt.target);
    //console.log(evt.clientY+" - "+evt.target.getBBox());

    var d = this.pathForCylinder(this.x0, this.y0, x2, y2, 30);
    this.cap.setAttributeNS(null, "d", d);
}

canvas.onmousemove = function(evt) {
self.handleMouseMove(evt);
}

问题是(至少在Firefox中)getBoundingClientRect()没有给出我是SVG对象的界限。它为我提供了SVG对象内可绘制对象的边界。当你将鼠标悬停在萤火虫的日志线上并突出显示可绘制元素的微小的子矩形时,它变得非常明显。这意味着我对坐标的转换会产生有缺陷的结果。

The problem is that (at least in Firefox) getBoundingClientRect() does not give me the bounds of the SVG object. It gives me the bounds of the drawable objects inside the SVG object. It becomes painfully obvious when you mouse over the log lines in firebug and it highlights the paltry subrectangle of drawable elements. That means that my transformation of the coordinates gives defective results.

我应该使用什么技术将事件坐标系转换为SVG容器的坐标系?

What technique should I use to transform from the event coordinate system into the coordinate system of the SVG container?

我只是拼凑在一起 http://jsfiddle.net/7kvkq/ 来说明问题。

I just cobbled together http://jsfiddle.net/7kvkq/ to illustrate the problem.

推荐答案

不要使用 getBoundingClientRect()。相反,使用 getScreenCTM()

Don't use getBoundingClientRect(). Instead, transform the point from screen space into global SVG space by using getScreenCTM():

var pt = demo.createSVGPoint(); // demo is an SVGElement
demo.addEventListener('mousemove',function(evt) {
  pt.x = evt.clientX;
  pt.y = evt.clientY;
  var svgGlobal = pt.matrixTransform(demo.getScreenCTM().inverse());
  // svgGlobal.x and svgGlobal.y are now in SVG coordinates
},false);



修正演示: http://jsfiddle.net/7kvkq/3/



如果您需要从屏幕空间转换为元素的局部变换,请使用 getTransformToElement()进一步转换点:

var elTransform = demo.getTransformToElement(someElement);
var elLocal     = svgGlobal.matrixTransform(elTransform );



的演示> getTransformToElement() http://jsfiddle.net/7kvkq/4/



为了更好性能,而不是将点转换两次并创建中间点,将矩阵合并为一个并使用它来转换坐标:

Demo of getTransformToElement(): http://jsfiddle.net/7kvkq/4/

For better performance, instead of transforming the point twice and creating an intermediary point, combine the matrices into one and use that to transform your coordinates:

var demo = document.querySelector('svg'),
    pt   = demo.createSVGPoint(),
    g    = demo.querySelector('#myGroup');

// Assumes that the group does not move with respect to the SVG;
// if so, re-calculate this as appropriate.
var groupXForm = demo.getTransformToElement(g);
demo.addEventListener('mousemove',function(evt) {
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    var xform = groupXForm.multiply(demo.getScreenCTM().inverse());
    var localPoint = pt.matrixTransform(xform);
    // localPoint.x/localPoint.y are the equivalent of your mouse position
},false);

您可以在我的网站上看到使用这些技术的演示:

http://phrogz.net/svg/drag_under_transformation.xhtml

You can see a demo using these techniques on my site:
http://phrogz.net/svg/drag_under_transformation.xhtml

这篇关于尽管伪造了getBoundingClientRect(),你如何将事件坐标转换为SVG坐标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆