34 votes

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 où 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 donc il doit 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>
 

46voto

tkdave Points 796

Le comportement glissable 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);
  });
 

2voto

Mike Points 21

La solution, je suis à bricoler avec implique (pour l'attacher à votre cas), la création d'une nouvelle div et svg, positionné au-dessus de la forme d'origine, pour servir de poignée pour le ciblées svg objet. La poignée div déplaçable et de stocker le départ haut/gauche décalage à l'extérieur (pense caché div). Une fois que le "stop" de l'événement pour la déplaçable div est déclenché, à comprendre le degré de changement pour le haut et à gauche (stopX-startX=changeX) et de l'appliquer à l'origine des formes coordonnées. Alors .remove() temporaire en forme.

2voto

Timothy Dean Points 715

Ce lien a une excellente description de la façon de résoudre le problème en général (c'est à dire, sans nécessiter de JQuery), et c'est certainement la meilleure solution que j'ai vu. Cependant, j'ai voulu continuer à l'aide de JQuery excellent Déplaçable de l'API.

J'ai récemment passé quelques jours à marteler à ce problème. L'on a accepté la réponse ci-dessus est ce que j'ai essayé en premier, mais je ne pouvais pas le faire directement dans Firefox. Il y a quelque chose à propos de la manière dont les navigateurs poignée SVG coordonnées différemment.

Je suis venu avec une solution qui a assez bien fonctionné pour moi, en Chrome et Firefox, et me permet de continuer à utiliser JQuery UI. Je n'ai pas testé partout. C'est certainement un hack.

Vous pouvez voir un moyen rapide de la maquette de ce que j'ai fait dans un violon ici. L'idée clé est d'utiliser un proxy div qui vous maintenir en vol stationnaire exactement au-dessus de l'élément svg vous souhaitez faire glisser. Ensuite, vous modifiez l'élément svg coordonnées x et y que vous faites glisser le proxy div. Quelque chose comme ceci:

$('#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 je voulais glisser serait toujours remplir une certaine place sur l'écran, donc c'était très facile de positionner le proxy div-dessus de la cible. Dans d'autres situations, il pourrait être beaucoup plus difficile. Il n'est également pas trop difficile à utiliser le 'confinement' option pour vous assurer de ne pas glisser de l'arrière-plan à l'extérieur du cadre...il faut juste un peu attention mathématiques et vous devez réinitialiser l'enceinte de confinement entre chaque glisser.

Pour faire de cette applicables à plusieurs éléments SVG, vous pouvez utiliser des transformations plutôt que de x et y coordonnées.

0voto

skyfoot Points 3480

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

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

0voto

user202834 Points 1

Dans mon cas, la réponse acceptée de @tkdave a fonctionné avec un petit ajustement. Je devais changer

 event.target.setAttribute('x', ui.position.left);
event.target.setAttribute('y', ui.position.top);
 

à

 event.target.setAttribute('cx', ui.position.left);
event.target.setAttribute('cy', ui.position.top);
 

J'espère que cela aide quelqu'un.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X