我正在尝试根据鼠标的位置动态绘制SVG元素上的东西.不幸的是,我很难将鼠标坐标从mousemove事件转换为SVG元素的坐标空间.
这是我一直在测试的错误功能:
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对象内可绘制对象的边界.当你将鼠标悬停在萤火虫的日志线上并突出显示可绘制元素的微小的子矩形时,它变得非常明显.这意味着我对坐标的转换会产生有缺陷的结果.
我应该使用什么技术将事件坐标系转换为SVG容器的坐标系?
我只是拼凑了http://jsfiddle.net/7kvkq/来说明问题.
不要用getBoundingClientRect()
.相反,使用以下方法将点从屏幕空间转换为全局SVG空间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);
如果需要从屏幕空间转换为元素的局部变换,请使用getTransformToElement()
以进一步转换点:
var elTransform = demo.getTransformToElement(someElement); var elLocal = svgGlobal.matrixTransform(elTransform );
getTransformToElement()
:http://jsfiddle.net/7kvkq/4/为了获得更好的性能,不是将点转换两次并创建中间点,而是将矩阵组合成一个并使用它来转换坐标:
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