html5 - rotate - SVG se coordina con la matriz de transformación
svg transform scale (2)
He creado un ejemplo de trabajo de lo que creo que estás describiendo en mi sitio aquí:
http://phrogz.net/svg/drag_under_transformation.xhtml
En general, convierte el cursor del mouse en el espacio local de un objeto al:
Crear un controlador de eventos
mousemove
:var svg = document.getElementsByTagName(''svg'')[0]; document.documentElement.addEventListener(''mousemove'',function(evt){ ... },false);
En ese controlador de eventos, convierta las coordenadas del mouse (en píxeles) en el espacio global de su documento SVG:
var pt = svg.createSVGPoint(); pt.x = evt.clientX; pt.y = evt.clientY; var globalPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
Convierta el punto global en el espacio del objeto que está arrastrando:
var globalToLocal = dragObject.getTransformToElement(svg).inverse(); var inObjectSpace = globalPoint.matrixTransform( globalToLocal );
Para la posteridad de Stack Overflow, esta es la fuente completa de mi demo de SVG + XHTML (en caso de que mi sitio esté inactivo):
<!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>
Quiero implementar la funcionalidad como svg-edit on rectangle element
- Girar rectángulo
- Cambio de tamaño
- Arrastrar
Al rotar 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 ha sido rotado se mueven las coordenadas. 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.
Para aquellos que usan Chrome, agreguen 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