2011-01-31 22 views
28

Quiero implementar la funcionalidad como SVG-edición el elemento de rectánguloSVG coordina con transformar la matriz

  1. Girar rectángulo
  2. Cambiar el tamaño de
  3. Arrastre

Al girar el rectángulo SVG funciona bien , pero cuando quiero cambiar el tamaño del rectángulo, tiene un problema. Las coordenadas no funcionan bien; Utilizo la matriz de transformación para rotar targetelement.setAttribute(transform,rotate(45,cx,cy)) pero cuando el elemento se ha girado las coordenadas se mueven. También estoy usando la función inverse para invertir la matriz de transformación, resuelve el problema pero no funciona con la función de arrastre.

+1

La descripción del problema es difícil de entender - ¿podría describir con mayor precisión (incluido el código) lo que hizo, lo que quería que sucediera, y lo que sucedió en su lugar? – joriki

+0

posible duplicado de [SVG - cambiar el tamaño de un rectángulo colocado en un ángulo] (http://stackoverflow.com/questions/4732624/svg-resizing-a-rectangle-positioned-at-an-angle) – Phrogz

Respuesta

94

He creado un ejemplo práctico de lo que yo creo que está describiendo en mi sitio aquí:
http://phrogz.net/svg/drag_under_transformation.xhtml

En general, se convierte el cursor del ratón en el espacio local de un objeto por:

  1. Creación de un controlador de eventos mousemove:

    var svg = document.getElementsByTagName('svg')[0]; 
    document.documentElement.addEventListener('mousemove',function(evt){ 
        ... 
    },false); 
    
  2. En ª en el controlador de eventos, convertir las coordenadas del ratón (en píxeles) en el espacio global del documento SVG:

    var pt = svg.createSVGPoint(); 
    pt.x = evt.clientX; 
    pt.y = evt.clientY; 
    var globalPoint = pt.matrixTransform(svg.getScreenCTM().inverse()); 
    
  3. convertir el punto mundial en el espacio del objeto que está arrastrando:

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

Por desbordamiento de pila posteridad, aquí está el código fuente completo de mi SVG + demostración XHTML (en caso de que mi sitio está desactivado):

<!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:[email protected]">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> 
+0

thanx phrogz ... Después de la rotación quiero cambiar el tamaño del rectángulo de nuevo como svg-edit ... creo que mis co-ords rectangulares cambian cuando giro –

+1

Gracias por el código. Estaba teniendo problemas para averiguar cómo obtener el valor de transformación sin usar getAttribute, pero luego vi el método getTransformToElement() en tu código. Aclamaciones. :) – Yansky

+1

Limpio, simple, funciona. Con una documentación de svg tan pobre en la web, esta respuesta realmente se destaca. –

0

Para aquellos que utilizan Chrome favor agregue las siguientes líneas después

var pt = svg.createSVGPoint(); 

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

Más información aquí: https://github.com/cpettitt/dagre-d3/issues/202

+0

Esto no responde a la pregunta original. –

+0

Sí, pero la respuesta no funciona en el navegador Crome sin ella. –

+0

Las respuestas deben responder a la pregunta, este es un comentario sobre una respuesta existente que no está permitido aquí. Una vez que tenga 50 representantes, puede agregarlo como comentario a la respuesta existente. –

Cuestiones relacionadas