【问题标题】:spawn & drag of SVG elements - approach生成和拖动 SVG 元素 - 方法
【发布时间】:2017-03-09 15:51:46
【问题描述】:

我正在学习 Javascript/SVG 组合(动画和制作交互式 SVG)。

我想创建一个代码 sn-p,其中菜单元素(“库存”)可以拖动到主屏幕(“画布”),而原始元素将保留在其位置(就像移动副本一样它脱离了原始元素)。

在这里,我尽我所能编写了代码 sn-p: http://codepen.io/cmer41k/pen/f2b5eea274cdde29b0b2dc8a2424a645

所以我设法做了一些事情,但它有问题:

  1. 我可以处理 1 个副本并使其可拖动,但是我不知道如何处理所有这些生成元素的 ID,这会导致拖动问题

  2. 我不明白如何让它无限期地工作(这样它就可以产生任意数量的可拖动到画布上的圆圈)

  3. 画布中的可拖动元素经常重叠,我无法以它们不重叠的方式附加监听器,以便我拖动的元素上的监听器会“通过”那里的任何其他元素传播;(

问题基本上是 - 有人可以建议我应该将逻辑放入这个 sn-p 以便它不那么麻烦。我很确定我在这里遗漏了一些东西;((例如,它不应该那么难,不是吗?)

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

【问题讨论】:

    标签: javascript svg clone element draggable


    【解决方案1】:

    你很亲密。你有几个错误。例如。

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

    应该是:

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

    drag = t 应该是drag = copy (?)

    当我认为您打算将它们附加到“画布”部分时,您还将克隆附加到库存部分。

    但也有一些不太明显的错误导致了不可靠性。例如,如果您将 mousemove 和 mouseup 事件附加到库存和克隆形状,那么如果拖得太快,您将不会收到事件。鼠标将移到形状之外,并且事件不会传递给形状。解决方法是将这些事件处理程序移动到根 SVG。

    我所做的另一项更改是将克隆的 DOM 中的 xy 位置存储为 _x_y。这比尝试将它们保存在单独的数组中更容易。

    无论如何,这是我对你的示例的修改版本,它的工作更加可靠。

    // define meta objects
    var drag = null;
    
    var canvas = {};
    var inventory = {};
    	
    window.onload = function() {
    		
        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.getElementById("svg").onmousemove=Drag;
    	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);
      
    	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 = Drag;
                copy.removeAttribute("id");
                copy._x = 0;
                copy._y = 0;
    			canvas.appendChild(copy);
    			drag = copy;
    			dPoint = m;
    		} 
    		else 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")) {
    		drag._x += m.x - dPoint.x;
    		drag._y += m.y - dPoint.y;
    		dPoint = m;
    		drag.setAttribute("transform", "translate(" +drag._x+","+drag._y+")");	
    	}
    		
        // stop drag
    	if (drag && (et == "mouseup")) {
    		drag.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
    		}
    }
    /* SVG styles */
    path
    {
    	stroke-width: 4;
    	stroke: #000;
    	stroke-linecap: round;
    }
    
    path.fill
    {
    	fill: #3ff;
    }
    
    html, body {
    	margin: 0;
    	padding: 0;
    	border: 0;
    	overflow:hidden;
    	background-color: #fff;	
    }
    body {
    	-ms-touch-action: none;
    }
    #canvasBackground {
    	fill: lightgrey;
    }
    #inventoryBackground {
    	fill: grey;
    }
    .inventory {
      fill: red;
    }
    .draggable {
      fill: green;
    }
    svg {
        position: fixed; 
    	  top:0%; 
    	  left:0%; 
    	  width:100%; 
    	  height:100%;  
    }
    <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>

    【讨论】:

    • 嘿,保罗,非常感谢;)我一步一步地经历了它,现在我对如何做这些事情有了更好的理解。
    猜你喜欢
    • 2014-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2015-01-13
    相关资源
    最近更新 更多