2016-10-27 13 views
0

我正在學習Javascript/SVG組合(動畫和製作交互式SVG)的學習曲線。SVG元素的產卵和拖拽 - 方法

我想創建一個代碼片段,其中菜單元素(「庫存」)可以拖到主屏幕(「畫布」),而原始元素將保留在它的位置(就好像我們將一個副本它關閉了原來的元素)。

在這裏,我製作的代碼片段是最好的,我可以: http://codepen.io/cmer41k/pen/f2b5eea274cdde29b0b2dc8a2424a645

所以我有點設法做一些事,但它的越野車:

  1. 我可以處理1份並使其可拖動,但我不知道如何處理所有這些產卵元素的ID,這會導致拖曳問題

  2. 我無法理解如何使它無限期地工作(以便它可以產生任何amo沒有可拖動到畫布的圓圈)

  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

你接近? 。你有幾個bug。例如:

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

應該是:

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

而且drag = t應該是drag = copy(?)

你也被追加克隆到庫存部分,當我想你打算將它們添加到「畫布」一節。

但也有一些不明顯的錯誤導致了不可靠性。例如,如果將鼠標移動和鼠標移動事件附加到清單和克隆形狀,則如果拖動過快,則不會獲取事件。鼠標將超出形狀,事件不會傳遞給形狀。解決方法是將這些事件處理程序移至根SVG。

我做的另一個改變是將xy位置存儲在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

嘿保羅,太感謝你了;)我經歷了一步一步來,現在我有更好的瞭解如何做這些事情。 –