2013-01-20 11 views
5

Sto tentando di riordinare gli elementi DOM SVG utilizzando gli eventi di trascinamento e rilascio nativi. Il codice seguente sembra funzionare (con alcuni strani effetti di immagine) in Firefox, funziona un numero limitato di volte in Chrome (funzionano 2 o 3 riordinamenti di trascinamento/rilascio, quindi sembra bloccarsi) e non molto bene in IE. La mia ipotesi migliore è che ci sia qualcosa sugli eventi in questione a cui non sto pensando correttamente, qualche tipo di reset. O forse usando gli eventi di trascinamento senza dataTransfer in questo modo non è corretto. Il mio obiettivo è comprendere questo tipo di funzione senza librerie, ma per avere una comprensione più chiara delle funzioni DOM, javascript, HTML e CSS al livello più elementare. Potrei facilmente sbagliare da qualche parte in quella lista.HTML5 trascinare la manipolazione DOM con javascript

<!DOCTYPE html> 
<html> 
    <head> 
    <title>Drag and Drop Experiments</title> 
    <style>svg { border-width:3px} </style> 
    </head> 
<body> 
    <div id="main"> 
    <svg id="s1" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="blue"></circle> 
    </svg> 
    <svg id="s2" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="red"></circle> 
    </svg> 
    <svg id="s3" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="yellow"></circle> 
    </svg> 
    </div> 
    <script type="text/javascript"> 
     var dragSourceElement = null; 
     var dragTargetElement = null; 
     function doDragStart(e){ 
      this.style.opacity = "0.4"; 
      this.style.border = "solid"; 
      dragSourceElement = this; 
     } 
     function doDragEnter(e){ 
      if(dragSourceElement != this){ 
      this.style.border = "dashed"; 
      } 
     } 
     function doDragLeave(e){ 
      if(dragSourceElement != this){ 
       this.style.border = ""; 
      } 
     } 
     function doDragOver(e){ 
      if(dragSourceElement != this){ 
       dragTargetElement = this; 
       e.preventDefault();//to allow a drop? 
      } 
     } 
     function doDragEnd(e){ 
      this.style.border = ""; 
      this.style.opacity = "1.0"; 
     } 
     function doDragDrop(e){ 
      if(dragSourceElement != dragTargetElement){ 
      dnd_svg(dragSourceElement,dragTargetElement); 
      } 
      dragSourceElement.style.border = ""; 
      dragTargetElement.style.border = ""; 
      dragSourceElement.style.opacity = ""; 
      dragSourceElement = null; 
      dragTargetElement = null; 
     } 
     //called after a drag and drop 
     //to insert svg element c1 before c2 in the DOM 
     //subtree of the parent of c2, assuming c1 is 
     //dropped onto c2 
     function dnd_svg(c1,c2){ 
     var parent_c2 = c2.parentElement; 
     parent_c2.insertBefore(c1,c2); 
     } 
     function addL(n){ 
      n.addEventListener('dragstart',doDragStart,false); 
      n.addEventListener('dragenter',doDragEnter,false); 
      n.addEventListener('dragleave',doDragLeave,false); 
      n.addEventListener('dragover',doDragOver,false); 
      n.addEventListener('drop',doDragDrop,false); 
     } 
     addL(document.getElementById("s1")); 
     addL(document.getElementById("s2")); 
     addL(document.getElementById("s3")); 
    </script> 
</body> 
</html> 
+0

Nota: c'è un errore javascript nella funzione dnd_svg in IE9. var parent_c2 = c2.parentElement? c2.parentElement: c2.parentNode; lo risolve per me. Vedi http://jsfiddle.net/nrNSS/. – stevebot

risposta

0

Vedere this JSFiddle. C'è un problema con gli eventi drag and drop su SVG in FF, quindi una soluzione è aggiungere un elemento wrapper a SVG. Con questo, è possibile utilizzare il metodo dataTransfer e quindi aggiungere il nodo alla posizione di rilascio.

<!DOCTYPE HTML> 
<html> 

    <head> 
     <style type="text/css"> 
      #div1,#div2 { 
       width:350px; 
       height:70px; 
       padding:10px; 
       border:1px solid #aaaaaa; 
      } 
     </style> 
     <script> 
      function allowDrop(ev) { 
       ev.preventDefault(); 
      } 

      function drag(ev) { 
       var id = ev.target ? ev.target.id : ev.srcElement.id; 
       if (id === "circle") { 
        id = ev.target.parentNode.parentNode.id; 
       } 
       ev.dataTransfer.setData("Text", id); 
      } 

      function drop(ev) { 
       ev.preventDefault(); 
       var data = ev.dataTransfer.getData("Text"); 
       ev.target.appendChild(document.getElementById(data)); 
      } 
     </script> 
    </head> 

    <body> 

     <div id="div1" ondrop="drop(event)" 
     ondragover="allowDrop(event)"></div> 
      <div id="div2" ondrop="drop(event)" 
     ondragover="allowDrop(event)"></div> 
     <br> 
     <div id="wrapper" draggable="yes" ondragstart="drag(event)" style="width:100px; height:100px;"> 
      <svg id="svg" width="100" height="100" draggable="yes" ondragstart="drag(event)" > 
       <circle id="circle" cx="50" cy="50" r="30" fill="yellow"></circle> 
      </svg> 
     </div> 
    </body> 

</html> 

questo funziona per me sia in 18 FF e IE 9. La parte fastidiosa è che FF e IE entrambi di origine diversi target per questi eventi, con IE restituzione del SVG come destinazione per l'evento di trascinamento, mentre FF restituisce il cerchio. Molto noioso.

Aggiornamento: Ho provato questo JSFiddle in Chrome 24 e funziona.

+0

Ciao, grazie - il mio obiettivo principale era cercare di vedere se potevo usare gli eventi drag and drop per mescolare gli elementi svg in giro, solo un semplice riordino. In definitiva, penso che la risposta potrebbe non essere quella di usare il drag-drop HTML5 per questo scopo. –

0

Questo tutorial è abbastanza buono per comprendere il drag and drop nativo, con molti esempi.

Tuttavia, potrebbero esserci problemi particolari associati a SVG. Vedi ad esempio questo Mozilla bug: "l'evento dragstart non viene attivato su un elemento svg".

+0

Ciao, grazie, avevo rivisto quel tutorial quando l'ho iniziato. Ma è un buon collegamento. –

Problemi correlati