2009-07-10 36 views
31

Tengo una página HTML 5 donde cargo un círculo svg. Cuando hago clic en el círculo, creo otro pequeño círculo donde hago clic. Quiero poder arrastrar el segundo círculo, pero no puedo hacerlo con jquery-ui .draggable();SVG se puede arrastrar usando JQuery y Jquery-svg

Soy capaz de mover el círculo accediendo a sus atributos cx y cy por lo que debe haber una forma de arrastrarlo.

<!DOCTYPE HTML> 
<html > 
<head> 
<title></title> 
<link href="css/reset.css" rel="stylesheet" type="text/css"> 
<link href="css/layout.css" rel="stylesheet" type="text/css"> 
<link href="css/style.css" rel="stylesheet" type="text/css"> 
<script src="js/jquery.js" type="text/javascript" ></script> 
<script src="js/jquerysvg/jquery.svg.js" type="text/javascript" ></script> 
<script src="js/jquery-ui.js" type="text/javascript" ></script> 
<script type="text/javascript" > 
jQuery(document).ready(function(){ 
    $('#target').svg({onLoad: drawInitial}); 
    $('circle').click(function(e){ 
     drawShape(e); 
     var shape = this.id; 

    }); 

    $('.drag').mousedown(function(e){ 
     var shape = this.id; 
     this.setAttribute("cx", e.pageX); 
     this.setAttribute("cy", e.pageY); 
    }); 
}) 

function drawInitial(svg) { 
    svg.add($('#svginline')); 
} 

function drawShape(e) { 
    var svg = $("#target").svg('get'); 
    $('#result').text(e.clientX + ": " + e.pageX); 
    var dragme = svg.circle(e.clientX, e.clientY, 5, {fill: 'green', stroke: 'red', 'stroke-width': 3, class_: 'drag'});  
    //$(dragme).draggable(); 
} 
</script> 
</head> 
<body> 
    <div id="target" ></div> 
    <svg:svg id="svginline"> 
     <svg:circle id="circ11" class="area" cx="75" cy="75" r="50" stroke="black" stroke-width="2" fill="red"/> 
    </svg:svg> 
    <div id="result" >ffff</div> 
</body> 
</html> 

Respuesta

44

El comportamiento de jQuery UI que se puede arrastrar funciona, pero debe actualizar la posición manualmente en el controlador de arrastre, ya que el posicionamiento CSS relativo no funciona dentro de SVG.

svg.rect(20,10,100,50, 10, 10, {fill:'#666'}); 
svg.rect(40,20,100,50, 10, 10, {fill:'#999'}); 
svg.rect(60,30,100,50, 10, 10, {fill:'#ccc'}); 

$('rect') 
    .draggable() 
    .bind('mousedown', function(event, ui){ 
    // bring target to front 
    $(event.target.parentElement).append(event.target); 
    }) 
    .bind('drag', function(event, ui){ 
    // update coordinates manually, since top/left style props don't work on SVG 
    event.target.setAttribute('x', ui.position.left); 
    event.target.setAttribute('y', ui.position.top); 
    }); 
+0

Gracias, esto funciona como un regalo. – skyfoot

1

He creado una función de arrastrar y soltar básico para orientar los objetos SVG. No tengo ninguna detección de contención o colisión. Existe un problema si muevo el mouse demasiado rápido. Dejo atrás el objeto que se puede arrastrar.

<!DOCTYPE HTML> 
<html > 
<head> 
<title></title> 
<link href="css/reset.css" rel="stylesheet" type="text/css"> 
<link href="css/layout.css" rel="stylesheet" type="text/css"> 
<link href="css/style.css" rel="stylesheet" type="text/css"> 
<script src="js/jquery.js" type="text/javascript" ></script> 
<script src="js/jquery-ui.js" type="text/javascript" ></script> 
<script src="js/jquerysvg/jquery.svg.js" type="text/javascript" ></script> 
<script src="js/jquerysvg/jquery.svgdom.js" type="text/javascript" ></script> 

<script type="text/javascript" > 
jQuery(document).ready(function(){ 
    $('#target').svg({onLoad: drawInitial}); 
    $('circle').click(function(e){ 
     drawShape(e); 
     var shape = this.id; 

    }); 
}) 

function drawInitial(svg) { 
    svg.add($('#svginline')); 
} 

function onMouseDown(evt){ 
     //var shape = this.id; 

     var target = evt.target;   
     target.onmousemove = onMouseMove; 

     return false; 
} 

function onMouseMove(evt){ 
    circle = evt.target 

    var cx = circle.getAttribute("cx"); 
    offsetX = $('#target').offset().left; 
    offsetY = $('#target').offset().top 
    circle.setAttribute("cx", evt.clientX -offsetX); 
    circle.setAttribute("cy", evt.clientY - offsetY); 

    circle.onmouseup = OnMouseUp; 
} 

function OnMouseUp(evt) { 
    var target = evt.target;   
    target.onmousemove = null; 
} 

function drawShape(e) { 
    var svg = $("#target").svg('get'); 
    offsetX = $('#target').offset().left; 
    offsetY = $('#target').offset().top; 
    $('#result').text(e.clientX + ": " + e.pageX); 
    var dragme = svg.circle(e.clientX - offsetX, e.clientY - offsetY, 5, {onmousedown: "onMouseDown(evt)",fill: 'green', stroke: 'red', 'stroke-width': 3});  
    $(dragme).addClass('drag'); 
} 
</script> 
</head> 
<body> 
    <div id="target" ></div> 
    <svg:svg id="svginline"> 
     <svg:circle id="circ11" class="area" cx="75" cy="75" r="50" stroke="black" stroke-width="2" fill="red"/> 
    </svg:svg> 
    <div id="result" >ffff</div> 
</body> 
</html> 
+0

que tuvieron una respuesta de Keith Wood, quien creó jquerysvg http://keith-wood.name/svg.html "Estoy trabajando en conseguir jQuery para trabajar con el DOM SVG, que es ligeramente diferente a el HTML DOM para el que se diseñó jQuery. Esto permitirá la conexión de manejadores de eventos jQuery a los elementos SVG. No implementará el método de arrastrar y soltar explícitamente, pero ayudará a utilizar jQuery para hacerlo. y funcionalidad drop-up para una futura versión." – skyfoot

+0

Debido a la cantidad de vistas que pensé que iba a actualizar esto. Creé una funcionalidad similar en Silverlight y el método de arrastrar y soltar también fue sobrio hasta que usé Silverlights Mouse Capture. No estoy seguro de lo que sucede en el método de Captura de mouse pero si se puede implementar en jquery, esto resolvería el arrastre y soltar. – skyfoot

+0

Funciona perfectamente @skyfoot. Pero ¿qué pasa con la línea que tiene dos pares de coordenadas, es decir (x1, y1) y (x2, y2) en lugar de tener una coordenada como círculo (cx, cy)? Gracias. – Bakhtiyor

2

La solución que estoy jugando con involucra (a atarla a su caso) la creación de un nuevo div SVG y su colocación sobre la forma original, para actuar como el mango para el objeto SVG dirigida. Haga que el controlador div se pueda arrastrar y guarde el desplazamiento superior/izquierdo inicial externamente (piense en div oculto). Una vez que se dispara el evento "stop" para el div arrastrable, determine el grado de cambio para la parte superior e izquierda (stopX-startX = changeX) y aplíquelo a las coordenadas de formas originales. Entonces. Retire() su forma temporal.

2

This link tiene una excelente descripción de cómo resolver el problema en general (es decir, sin necesidad de JQuery), y que es sin duda la mejor solución que he visto. Sin embargo, quería seguir usando la excelente API Draggable de JQuery.

Recientemente, pasé un par de días tratando de resolver este problema. La respuesta aceptada anteriormente es lo que intenté primero, pero no pude hacer que funcionara correctamente en Firefox. Hay something about how browsers handle coordenadas SVG de manera diferente.

Se me ocurrió una solución que funcionó bastante bien para mí, tanto en Chrome como en Firefox, y me permite seguir usando la interfaz de usuario de JQuery. No lo he probado en todas partes. Definitivamente es un truco.

Puede ver una maqueta rápida de lo que hice en un violín here. La idea clave es usar un proxy div que sigas desplazándote exactamente sobre el elemento svg que deseas arrastrar. A continuación, cambie las coordenadas xey del elemento svg a medida que arrastra el div proxy. Algo como esto:

$('#proxy').on('drag', function(e) 
    { 
     t = $('#background'); 
     prox = $('#proxy'); 
     t.attr('x', t.attr('x')*1 
        + prox.css('left').slice(0,-2)*1 
        - prox.data('position').left) 
      .attr('y', t.attr('y')*1 
         + prox.css('top').slice(0,-2)*1 
         - prox.data('position').top); 
     prox.data('position',{top : prox.css('top').slice(0,-2)*1, 
           left: prox.css('left').slice(0,-2)*1} 
       ); 
    }); 

En mi caso el elemento SVG quería arrastrar sería siempre llenar una determinada plaza en la pantalla, por lo que era muy fácil de colocar el div de proxy sobre el objetivo. En otras situaciones, podría ser mucho más difícil. Tampoco es demasiado difícil usar la opción de 'contención' para asegurarte de que no arrastras el fondo fuera del marco ... solo requiere una cuidadosa operación matemática y debes restablecer la contención entre cada arrastre.

Para que esto sea aplicable a más elementos SVG, puede usar transformaciones en lugar de coordenadas xey.

Cuestiones relacionadas