Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
383 views
in Technique[技术] by (71.8m points)

html - SVG coordinates with transform matrix

I want to implement the functionality like svg-edit on rectangle element

  1. Rotate rectangle
  2. Resizing
  3. Drag

Rotating the SVG rectangle it works fine, but when I want to resize the rectangle it has a problem. The coordinates are not working right; I use the transform matrix to rotate targetelement.setAttribute(transform,rotate(45,cx,cy)) but when the element has been rotated the coordinates are moved. I'm also using inverse function to inverse the transform matrix it resolves the problem but its not working with drag function.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have created a working example of what I believe you are describing on my site here:
http://phrogz.net/svg/drag_under_transformation.xhtml

In general, you convert the mouse cursor into the local space of an object by:

  1. Creating a mousemove event handler:

    var svg = document.getElementsByTagName('svg')[0];
    document.documentElement.addEventListener('mousemove',function(evt){
      ...
    },false);
    
  2. In that event handler, convert the mouse coordinates (in pixels) into the global space of your SVG document:

    var pt = svg.createSVGPoint();
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    var globalPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
    
  3. Convert the global point into the space of the object you are dragging:

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

For Stack Overflow posterity, here's the full source of my SVG+XHTML demo (in case my site is down):

<!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();
          m.e = m.f = 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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...