web-dev-qa-db-fra.com

SVG déplaçable à l'aide de JQuery et Jquery-svg

J'ai une page HTML 5 où je charge un cercle svg. Lorsque je clique sur le cercle, je crée un autre petit cercle dans lequel je clique. Je veux pouvoir faire glisser le deuxième cercle mais je ne peux pas sembler le faire avec jquery-ui .draggable ();

Je peux déplacer le cercle en accédant à ses attributs cx et cy. Il doit donc y avoir un moyen de le faire glisser.

    <!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>
33
skyfoot

le comportement déplaçable de l'interface utilisateur jQuery fonctionne, mais vous devez mettre à jour la position manuellement dans le gestionnaire de glissement, car le positionnement CSS relatif ne fonctionne pas dans 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);
  });
47
tkdave

Ce lien a une excellente description de la façon de résoudre le problème en général (c’est-à-dire sans avoir besoin de JQuery), et c’est définitivement la meilleure solution que j’ai vue. Cependant, je voulais continuer à utiliser l'excellente API Draggable de JQuery.

J'ai récemment passé quelques jours à marteler ce problème. La réponse acceptée ci-dessus est ce que j'ai essayé en premier, mais je ne pouvais pas le faire fonctionner correctement dans Firefox. Il y a quelque chose sur la façon dont les navigateurs gèrent les coordonnées SVG différemment.

J'ai proposé une solution qui fonctionnait assez bien pour moi, à la fois sous Chrome et Firefox, et qui me permettait de continuer à utiliser l'interface utilisateur de JQuery. Je ne l'ai pas testé partout. C'est définitivement un bidouillage.

Vous pouvez voir une rapide maquette de ce que j'ai fait dans un violon ici . L'idée principale est d'utiliser un div de proxy que vous continuez de survoler exactement sur l'élément svg que vous souhaitez faire glisser. Ensuite, vous modifiez les coordonnées x et y de l'élément svg en faisant glisser le proxy div. Quelque chose comme ça:

$('#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}
                  );
    });

Dans mon cas, l'élément SVG que je voulais faire glisser remplissait toujours un certain carré à l'écran, il était donc très facile de positionner le div de proxy sur la cible. Dans d'autres situations, cela pourrait être beaucoup plus difficile. Il n’est pas difficile non plus d’utiliser l’option «confinement» pour vous assurer de ne pas faire glisser l’arrière-plan en dehors du cadre ... cela demande quelques calculs précis et vous devez réinitialiser le confinement entre chaque déplacement.

Pour rendre cela applicable à plusieurs éléments SVG, vous pouvez utiliser des transformations plutôt que des coordonnées x et y.

2
galdre

La solution avec laquelle je bricole consiste (pour le lier à votre cas) à créer un nouveau div et svg, positionné sur la forme d'origine, pour servir de descripteur à l'objet svg ciblé. Faites en sorte que la poignée soit déplaçable et stockez le décalage supérieur/gauche de départ à l’extérieur (pensez à la division cachée). Une fois que l'événement "stop" du div pouvant être glissé est déclenché, déterminez le degré de changement pour le haut et le gauche (stopX-startX = changeX) et appliquez-le aux coordonnées de formes d'origine. Puis supprimez () votre forme temporaire.

2
Mike

J'ai créé une fonction de base glisser-déposer pour cibler mes objets svg. Je n'ai aucune détection de confinement ou de collistion. Il y a un problème si je déplace la souris trop rapidement, je vais laisser l'objet déplaçable derrière.

<!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>
1
skyfoot

Il suffit de placer le svg dans un div déplaçable.

//*
$(document).ready(function(){
  $('#mydiv').draggable();
});
//*/
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<div id="mydiv">
  <svg xml:lang="en"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <text class="main" x="10" transform="rotate(-28 0 0)" y="90">Sol min</text>
    <text class="sous" x="4" y="110" transform="rotate(-28 0 20)">(SOUS DOM.)</text>
   <line stroke="black" stroke-width="2" x1="10" y1="100" x2="110" y2="46" />
   <line stroke="red" stroke-width=2 x1=10 y1=99 x2=10 y2=140 />
 </svg>
</div>

0
Philippe Perret