2016-10-27 16 views
0

Я нахожусь на моей кривой обучения для Javascript/SVG combo (анимация и создание интерактивных SVG).spawn & drag элементов SVG - подход

Я хотел создать фрагмент кода, в котором элементы меню («инвентарь») можно перетащить на главный экран («холст»), в то время как исходный элемент останется на своем месте (как если бы он переместил копию это от исходного элемента).

Здесь я обработал фрагмент кода, как лучше всего, как я мог: http://codepen.io/cmer41k/pen/f2b5eea274cdde29b0b2dc8a2424a645

Так я вроде удалось сделать что-то, но его багги:

  1. Я мог бы иметь дело с 1 экземпляр и делает его draggable, но тогда я не знаю, как бороться с идентификаторами для всех этих нерестилищных элементов, что вызывает проблемы с перетаскиванием.

  2. Я не понимаю, как заставить его работать бесконечно (чтобы он мог вызвать любую амо нет кругов, перетаскиваемых на холст)

  3. Перетаскиваемые элементы в холсте часто перекрываются, и я не могу подключить слушателей так, как они не пересекаются, так что слушатель на элементе, который я перетаскиваю, будет распространяться «через» любые другие элементы есть; (

Вопрос в основном - кто-то может предложить логику, что я должен поставить в этот фрагмент так, чтобы это не было обременительным. Я уверен, что я что-то здесь не хватает; ((например, оно не должно быть трудно это не так)

HTML:

<body> 
<svg id="svg" 
    height="800" 
    width="480" 
    viewbox="0 0 480 800" 
    preserveAspectRatio="xMinYMin meet" 
    xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
> 
    <rect id="canvasBackground" width="480" height="480" x="0" y="0"/> 
    <rect id="inventoryBackground" width="480" height="100" x="0" y="480"/> 


<g id="inventory"> 
<path id="curve4" class="inventory" d="M60,530 A35,35 0 1,1 60,531" /> 
<path id="curve3" class="inventory" d="M150,530 A35,35 0 1,1 150,531" /> 
<path id="curve2" class="inventory" d="M240,530 A35,35 0 1,1 240,531" /> 
<path id="curve1" class="inventory" d="M330,530 A35,35 0 1,1 330,531" /> 
</g> 

<g id="canvas"> 
</g> 

</svg> 
</body> 

Javascript:

// define meta objects 
var drag = null; 

// this stores all "curves"-circles 
var curves = {}; 
var canvas = {}; 
var inventory = {}; 

window.onload = function() { 

     // creates the curve-circles in the object and at their initial x,y coords 
     curves.curve1 = document.getElementById("curve1"); 
     curves.curve1.x = 0; 
     curves.curve1.y = 0; 
     curves.curve2 = document.getElementById("curve2"); 
     curves.curve2.x = 0; 
     curves.curve2.y = 0; 
     curves.curve3 = document.getElementById("curve3"); 
     curves.curve3.x = 0; 
     curves.curve3.y = 0; 
     curves.curve4 = document.getElementById("curve4"); 
     curves.curve4.x = 0; 
     curves.curve4.y = 0; 
     canvas = document.getElementById("canvas"); 
     inventory = document.getElementById("inventory"); 

     // attach events listeners 

     AttachListeners(); 
} 

function AttachListeners() { 
    var ttt = document.getElementsByClassName('inventory'), i; 
    for (i = 0; i < ttt.length; i++) { 
    document.getElementsByClassName("inventory")[i].onmousedown=Drag; 
    document.getElementsByClassName("inventory")[i].onmousemove=Drag; 
    document.getElementsByClassName("inventory")[i].onmouseup=Drag; 
    } 
} 

// Drag function that needs to be modified;// 
function Drag(e) { 
     e.stopPropagation(); 
     var t = e.target, id = t.id, et = e.type; m = MousePos(e); 

      if (!drag && (et == "mousedown")) { 

       if (t.className.baseVal=="inventory") { //if its inventory class item, this should get cloned into draggable? 
        copy = t.cloneNode(true); 
        copy.onmousedown=copy.onmousemove=onmouseup=Drag; 
        inventory.insertBefore(copy, inventory.firstChild); 
        drag = t; 
        dPoint = m; 
       } 
       if (t.className.baseVal=="draggable") { //if its just draggable class - it can be dragged around 
        drag = t; 
        dPoint = m; 
       } 

      } 
     // drag the spawned/copied draggable element now 
      if (drag && (et == "mousemove")) { 
       curves[id].x += m.x - dPoint.x; 
       curves[id].y += m.y - dPoint.y; 
       dPoint = m; 
       curves[id].setAttribute("transform", "translate(" +curves[id].x+","+curves[id].y+")"); 
      } 

     // stop drag 
      if (drag && (et == "mouseup")) { 
       t.className.baseVal="draggable"; 
       drag = null; 
      } 
} 



// adjust mouse position to the matrix of SVG & screen size 
function MousePos(event) { 
     var p = svg.createSVGPoint(); 
     p.x = event.clientX; 
     p.y = event.clientY; 
     var matrix = svg.getScreenCTM(); 
     p = p.matrixTransform(matrix.inverse()); 
     return { 
      x: p.x, 
      y: p.y 
     } 
} 

ответ

3

Вы были близки? . у вас было несколько ошибок Eg

copy.onmousedown=copy.onmousemove=onmouseup=Drag; 

должно быть:..

copy.onmousedown=copy.onmousemove=copy.onmouseup=Drag; 

И drag = t должны были drag = copy (?)

Также вы добавления клонов в разделе инвентаризации, когда я думаю, что вы хотели, чтобы добавить их в раздел «холст».

Но были также некоторые менее очевидные ошибки, которые вносили вклад в неустранимость. Например, если вы присоедините события mousemove и mouseup к инвентарным и клонированным формам, вы не будете получать события, если перетаскиваете слишком быстро. Мышь выйдет за пределы формы, и события не будут переданы формам. Исправить это, чтобы переместить эти обработчики событий в корневой SVG.

Еще одно изменение я сделал было сохранить x и y позиции в DOM для клона как _x и _y. Это упрощает работу, если вы пытаетесь сохранить их в отдельном массиве.

В любом случае, вот моя модифицированная версия вашего примера, которая работает намного надежнее.

// define meta objects 
 
var drag = null; 
 

 
var canvas = {}; 
 
var inventory = {}; 
 
\t 
 
window.onload = function() { 
 
\t \t 
 
    canvas = document.getElementById("canvas"); 
 
\t inventory = document.getElementById("inventory"); 
 
\t \t 
 
\t // attach events listeners 
 
\t AttachListeners(); 
 
} 
 

 
function AttachListeners() { 
 
\t var ttt = document.getElementsByClassName('inventory'), i; 
 
\t for (i = 0; i < ttt.length; i++) { 
 
     document.getElementsByClassName("inventory")[i].onmousedown=Drag; 
 
\t } 
 
    document.getElementById("svg").onmousemove=Drag; 
 
\t document.getElementById("svg").onmouseup=Drag; 
 
} 
 

 
// Drag function that needs to be modified;// 
 
function Drag(e) { 
 
    var t = e.target, id = t.id, et = e.type; m = MousePos(e); 
 
    
 
\t if (!drag && (et == "mousedown")) { 
 
\t \t \t \t 
 
\t \t if (t.className.baseVal=="inventory") { //if its inventory class item, this should get cloned into draggable? 
 
\t  \t copy = t.cloneNode(true); 
 
\t \t \t copy.onmousedown = Drag; 
 
      copy.removeAttribute("id"); 
 
      copy._x = 0; 
 
      copy._y = 0; 
 
\t \t \t canvas.appendChild(copy); 
 
\t \t \t drag = copy; 
 
\t \t \t dPoint = m; 
 
\t \t } 
 
\t \t else if (t.className.baseVal=="draggable") \t { //if its just draggable class - it can be dragged around 
 
\t \t \t drag = t; 
 
\t \t \t dPoint = m; 
 
\t \t } 
 
\t } 
 

 
    // drag the spawned/copied draggable element now 
 
\t if (drag && (et == "mousemove")) { 
 
\t \t drag._x += m.x - dPoint.x; 
 
\t \t drag._y += m.y - dPoint.y; 
 
\t \t dPoint = m; 
 
\t \t drag.setAttribute("transform", "translate(" +drag._x+","+drag._y+")"); \t 
 
\t } 
 
\t \t 
 
    // stop drag 
 
\t if (drag && (et == "mouseup")) { 
 
\t \t drag.className.baseVal="draggable"; 
 
\t \t drag = null; 
 
\t } 
 
} 
 
      
 
\t \t 
 

 
// adjust mouse position to the matrix of SVG & screen size 
 
function MousePos(event) { 
 
\t \t var p = svg.createSVGPoint(); 
 
\t \t p.x = event.clientX; 
 
\t \t p.y = event.clientY; 
 
\t \t var matrix = svg.getScreenCTM(); 
 
\t \t p = p.matrixTransform(matrix.inverse()); 
 
\t \t return { 
 
\t \t \t x: p.x, 
 
\t \t \t y: p.y 
 
\t \t } 
 
}
/* SVG styles */ 
 
path 
 
{ 
 
\t stroke-width: 4; 
 
\t stroke: #000; 
 
\t stroke-linecap: round; 
 
} 
 

 
path.fill 
 
{ 
 
\t fill: #3ff; 
 
} 
 

 
html, body { 
 
\t margin: 0; 
 
\t padding: 0; 
 
\t border: 0; 
 
\t overflow:hidden; 
 
\t background-color: #fff; \t 
 
} 
 
body { 
 
\t -ms-touch-action: none; 
 
} 
 
#canvasBackground { 
 
\t fill: lightgrey; 
 
} 
 
#inventoryBackground { 
 
\t fill: grey; 
 
} 
 
.inventory { 
 
    fill: red; 
 
} 
 
.draggable { 
 
    fill: green; 
 
} 
 
svg { 
 
    position: fixed; 
 
\t top:0%; 
 
\t left:0%; 
 
\t width:100%; 
 
\t height:100%; 
 
}
<svg id="svg" 
 
    height="800" 
 
    width="480" 
 
\t viewbox="0 0 480 800" 
 
\t preserveAspectRatio="xMinYMin meet" 
 
\t xmlns="http://www.w3.org/2000/svg" 
 
\t xmlns:xlink="http://www.w3.org/1999/xlink" 
 
> 
 
\t <rect id="canvasBackground" width="480" height="480" x="0" y="0"/> 
 
\t <rect id="inventoryBackground" width="480" height="100" x="0" y="480"/> 
 
    
 

 
<g id="inventory"> 
 
<path id="curve4" class="inventory" d="M60,530 A35,35 0 1,1 60,531" /> 
 
<path id="curve3" class="inventory" d="M150,530 A35,35 0 1,1 150,531" /> 
 
<path id="curve2" class="inventory" d="M240,530 A35,35 0 1,1 240,531" /> 
 
<path id="curve1" class="inventory" d="M330,530 A35,35 0 1,1 330,531" /> 
 
</g> 
 
    
 
<g id="canvas"> 
 
</g> 
 

 
</svg>

+0

Эй Павел, спасибо так много;) Я прошел через это шаг за шагом, и теперь у меня есть гораздо лучше понять, как сделать эти вещи. –