产卵SVG元素的拖动-方法 [英] spawn & drag of SVG elements - approach

查看:75
本文介绍了产卵SVG元素的拖动-方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am on my learning curve for Javascript/SVG combo (animating and making interactive SVGs).

我想创建一个代码段,可以将菜单元素(库存")拖到主屏幕(画布")上,而原始元素将保留在原处(就像一个人将其副本移动一样)脱离原始元素).

I wanted to create a code snippet where menu elements ("inventory") can be dragged over to the main screen ("canvas") while the originating element would remain in its place (as if one would move a copy of it off the original element).

在这里,我尽力制作了代码片段: http://codepen.io/cmer41k/pen/f2b5eea274cdde29b0b2dc8a2424a645

Here I crafted the code snippet as best as I could: http://codepen.io/cmer41k/pen/f2b5eea274cdde29b0b2dc8a2424a645

所以我设法做到了,但是它有很多缺陷:

So I sort of managed to do something but its buggy:

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

  1. I could deal with 1 copy and making it draggable, but then I don't know how to deal with IDs for all those spawning elements, which causes dragging issues

我不明白如何使其无限期地工作(以便它可以生成可拖动到画布上的任意数量的圆圈)

I fail to understand how to make it work indefinitely (so that it can spawn any amount of circles draggable to canvas)

画布中的可拖动元素经常重叠,而且我无法以不重叠的方式附加侦听器,因此我拖动的元素上的侦听器将传播"通过其中的其他任何元素;(

Draggable elements in canvas often overlap and I fail to attach the listeners the way they don't overlap so that the listener on the element I am dragging would propagate "through" whatever other elements there;(

问题基本上是-有人可以建议我在这段代码中添加一些逻辑,以免麻烦.我很确定我在这里错过了一些东西;((例如,它应该不是那么难吗?)

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:

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

推荐答案

您已经关闭.您有几个错误.例如

You were close. You had a couple of bugs. Eg.

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

应该是:

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

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

当我认为要将克隆添加到画布"部分时,您也将克隆添加到清单"部分.

Also you were appending the clones to the inventory section, when I think you intended to append them to the "canvas" section.

但是,还有一些不太明显的错误导致了这种不可靠.例如,如果将mousemove和mouseup事件附加到清单和克隆形状,则拖动得太快将不会获得这些事件.鼠标将移到该形状之外,并且事件不会传递到该形状.解决方法是将这些事件处理程序移至根SVG.

But there were also also some less-obvious mistakes that were contributing to the unreliableness. For example, if you attach the mousemove and mouseup events to the inventory and clone shapes, then you will won't get the events if you drag too fast. The mouse will get outside the shape, and the events won't be passed to the shapes. The fix is to move those event handlers to the root SVG.

我进行的另一项更改是将克隆中的xy位置存储为_x_y.这比将它们保存在单独的数组中要容易得多.

Another change I made was to store the x and y positions in the DOM for the clone as _x and _y. This makes it easier than trying to keep them in a separate array.

无论如何,这是我对示例的修改版本,可以更可靠地工作.

Anyway, here's my modified version of your example which works a lot more reliably.

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

这篇关于产卵SVG元素的拖动-方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆