SVG与变换matrix协调

我想在矩形元素上实现像svg-edit一样的function

  1. 旋转矩形
  2. 调整
  3. 拖动

旋转SVG矩形它工作正常,但是当我想调整矩形的大小时,它有一个问题。 坐标不正确; 我使用变换matrix来旋转targetelement.setAttribute(transform,rotate(45,cx,cy))但是当元素被旋转时,坐标被移动。 我也使用inverse函数来逆转换matrix它解决了问题,但它不能与拖动function。

我已经创build了一个我相信你在我的网站上描述的实例:
http://phrogz.net/svg/drag_under_transformation.xhtml

通常,通过以下方式将鼠标光标转换为对象的本地空间:

  1. 创build一个mousemove事件处理程序:

     var svg = document.getElementsByTagName('svg')[0]; document.documentElement.addEventListener('mousemove',function(evt){ ... },false); 
  2. 在该事件处理程序中,将鼠标坐标(以像素为单位)转换为SVG文档的全局空间:

     var pt = svg.createSVGPoint(); pt.x = evt.clientX; pt.y = evt.clientY; var globalPoint = pt.matrixTransform(svg.getScreenCTM().inverse()); 
  3. 将全局点转换为您要拖动的对象的空间:

     var globalToLocal = dragObject.getTransformToElement(svg).inverse(); var inObjectSpace = globalPoint.matrixTransform( globalToLocal ); 

对于堆栈溢出的后代,这里是我的SVG + XHTML演示的全部源代码(以防我的站点closures):

 <!DOCTYPE HTML> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head> <meta http-equiv="content-type" content="application/xhtml+xml;charset=utf-8"/> <title>Dragging Transformed SVG Elements</title> <style type="text/css" media="screen"> html, body { background:#eee; margin:0; user-select:none; -moz-user-select:none; -webkit-user-select:none; } p { margin:0.5em; text-align:center } svg { position:absolute; top:5%; left:5%; width:90%; height:90%; background:#fff; border:1px solid #ccc } svg rect { stroke:#333 } svg .drag { cursor:move } svg .sizer { opacity:0.3; fill:#ff0; stroke:#630;} #footer { position:absolute; bottom:0.5em; margin-bottom:0; width:40em; margin-left:-20em; left:50%; color:#666; font-style:italic; font-size:85% } #dragcatch { position:absolute; left:0; right:0; top:0; bottom:0; z-index:-1} </style> </head><body> <p>Showing how to drag points inside a transformation hierarchy.</p> <svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full"> <g transform="scale(1.2,0.8)"> <rect transform="translate(50,20) rotate(30)" class="drag resize" x="50" y="30" width="50" height="30" fill="#69c" /> <rect class="drag resize" x="5" y="5" width="90" height="50" fill="#c66" /> </g> </svg> <p id="footer"> Copyright © 2011 <a href="mailto:!@phrogz.net">Gavin Kistner</a>. Comments/criticisms welcome. </p> <script type="text/javascript"><![CDATA[ var svg = document.getElementsByTagName('svg')[0]; var svgNS = svg.getAttribute('xmlns'); var pt = svg.createSVGPoint(); function createOn(root,name,prop){ var el = document.createElementNS(svgNS,name); for (var a in prop) if (prop.hasOwnProperty(a)) el.setAttribute(a,prop[a]); return root.appendChild(el); } function rectCorner(rect){ pt.x = rect.x.animVal.value + rect.width.animVal.value; pt.y = rect.y.animVal.value + rect.height.animVal.value; return pt.matrixTransform(rect.getTransformToElement(svg)); } function pointIn(el,x,y){ pt.x = x; pt.y = y; return pt.matrixTransform(el.getTransformToElement(svg).inverse()); } function cursorPoint(evt){ pt.x = evt.clientX; pt.y = evt.clientY; return pt.matrixTransform(svg.getScreenCTM().inverse()); } // Make all rects resizable before drag, so the drag handles become drag for (var a=svg.querySelectorAll('rect.resize'),i=0,len=a.length;i<len;++i){ (function(rect){ var dot = createOn(svg,'circle',{'class':'drag sizer',cx:0,cy:0,r:5}); var moveDotToRect = function(){ var corner = rectCorner(rect); dot.setAttribute('cx',corner.x); dot.setAttribute('cy',corner.y); } moveDotToRect(); rect.addEventListener('dragged',moveDotToRect,false); dot.addEventListener('dragged',function(){ var rectXY = pointIn(rect,dot.cx.animVal.value,dot.cy.animVal.value); var w = Math.max( rectXY.x-rect.x.animVal.value, 1 ); var h = Math.max( rectXY.y-rect.y.animVal.value, 1 ); rect.setAttribute('width', w); rect.setAttribute('height',h); },false); })(a[i]); } for (var a=svg.querySelectorAll('.drag'),i=0,len=a.length;i<len;++i){ (function(el){ var onmove; // make inner closure available for unregistration el.addEventListener('mousedown',function(e){ el.parentNode.appendChild(el); // move to top var x = el.tagName=='circle' ? 'cx' : 'x'; var y = el.tagName=='circle' ? 'cy' : 'y'; var mouseStart = cursorPoint(e); var elementStart = { x:el[x].animVal.value, y:el[y].animVal.value }; onmove = function(e){ var current = cursorPoint(e); pt.x = current.x - mouseStart.x; pt.y = current.y - mouseStart.y; var m = el.getTransformToElement(svg).inverse(); me = mf = 0; pt = pt.matrixTransform(m); el.setAttribute(x,elementStart.x+pt.x); el.setAttribute(y,elementStart.y+pt.y); var dragEvent = document.createEvent("Event"); dragEvent.initEvent("dragged", true, true); el.dispatchEvent(dragEvent); }; document.body.addEventListener('mousemove',onmove,false); },false); document.body.addEventListener('mouseup',function(){ document.body.removeEventListener('mousemove',onmove,false); },false); })(a[i]); } ]]></script> <div id="dragcatch"></div> </body></html> 

对于那些使用Chrome的人,请在下面添加以下几行

 var pt = svg.createSVGPoint(); SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) { return elem.getScreenCTM().inverse().multiply(this.getScreenCTM()); }; 

更多信息在这里: https : //github.com/cpettitt/dagre-d3/issues/202