简体   繁体   English

使用SVG形状在“生成”拖动期间的鼠标处理程序

[英]Mouse Handlers during “spawn” drag with SVG shapes

I am continuing elaborating my little project and learning javascript & svg. 我将继续完善我的小项目并学习javascript和svg。

In my last code i implemented "click to spawn element and drag it" by creating a copy (cloneNode(true)) of the clicked object and then re-assigning it to the draggable. 在我的上一个代码中,我通过创建被单击对象的副本(cloneNode(true)),然后将其重新分配给可拖动对象来实现“单击以生成元素并将其拖动”。

Now that I refactored whole code to leverage javascript object factory I seems have stuck trying to figure the proper "loop";( 现在,我重构了整个代码以利用javascript对象工厂,我似乎一直想找出适当的“循环”;(

Try the snipped below: - i managed to create draggables (inventory shapes) - i managed to add some logic to recognize if its inventory class and do the copy and change class to "draggable" - now two issues: -- spawned objects are not really full copies of the original Draggables, hence they don't have mouse listeners and I am not sure how to detach the listeners from original objects... 请尝试以下内容:-我设法创建了可拖动物品(库存形状)-我设法添加了一些逻辑以识别其库存类别,并将复制类别更改为“可拖动”-现在有两个问题:-生成的对象不是实际上是原始Draggable的完整副本,因此它们没有鼠标侦听器,而且我不确定如何将侦听器与原始对象分离...

How do you ppl code all that? 您如何用ppl编写所有代码?

 //var morphUIon = false; var morphTarget = null; var canvas = {}; var inventory = {}; canvas = document.getElementById("canvas"); inventory = document.getElementById("inventory"); window.onload = function() { var src = document.querySelectorAll(".inventory"); for (var h = 0; h < src.length; h++) { var o = new Draggable(src[h]); //inventory.push(o); } } function Draggable(elem) { this.target = elem this.clickPoint = this.target.ownerSVGElement.createSVGPoint() this.lastMove = this.target.ownerSVGElement.createSVGPoint() this.currentMove = this.target.ownerSVGElement.createSVGPoint() this.dpath = this.target.getAttribute("d") this.subclass = this.target.getAttribute("subclass") this.target.pathPoints = parsePathToPoints(this.dpath, this.subclass) this.target.addEventListener("dblclick", this) this.target.addEventListener("mousedown", this) this.handleEvent = function(evt) { switch (evt.type) { case 'mousedown': evt.preventDefault() if (this.target.classList.contains("inventory")) { var spawned = this.target.cloneNode(true); spawned.classList.remove("inventory"); spawned.classList.add("draggable"); canvas.appendChild(spawned); this.target = spawned; //return; } this.clickPoint = globalToLocalCoords(evt.clientX, evt.clientY) this.target.classList.add("dragged") this.target.ownerSVGElement.addEventListener("mousemove", this.move) this.target.ownerSVGElement.addEventListener("mouseup", this.endMove) //to ensure dblclick is "heard" we delay the pointer trick below by 200ms. //setTimeout(function() {this.target.setAttribute("pointer-events", "none")}, 200) break; case 'dblclick': evt.preventDefault() if (morphTarget) { if (morphTarget!=this.target) { morphTarget.classList.remove("morphed") this.target.classList.add("morphed") morphTarget = elem; } else { return; } } else { morphTarget = elem this.target.classList.add("morphed") } Morph(this.target); break; } } this.move = function(evt) { evt.preventDefault() var p = globalToLocalCoords(evt.clientX, evt.clientY) this.currentMove.x = this.lastMove.x + (px - this.clickPoint.x) this.currentMove.y = this.lastMove.y + (py - this.clickPoint.y) this.target.setAttribute("transform", "translate(" + this.currentMove.x + "," + this.currentMove.y + ")") }.bind(this) this.endMove = function(evt) { this.lastMove.x = this.currentMove.x this.lastMove.y = this.currentMove.y this.target.classList.remove("dragged") //this.target.setAttribute("pointer-events", "all") this.target.ownerSVGElement.removeEventListener("mousemove", this.move) this.target.ownerSVGElement.removeEventListener("mouseup", this.endMove) }.bind(this) function globalToLocalCoords(x, y) { var p = elem.ownerSVGElement.createSVGPoint() var m = elem.parentNode.getScreenCTM() px = x py = y return p.matrixTransform(m.inverse()) } } function Morph(elem) { console.log(elem); } function parsePathToPoints(d, sub) { var darray = []; var pathPoints = {}; switch (sub) { case 'circle': darray = d.replace(/M|A|Z/g, "").replace(/,/g, " ").split(" ").map(Number); pathPoints.p0 = {"x": darray[0], "y": darray[1]}; pathPoints.p1 = {"x": darray[0]+darray[2], "y": darray[1]-darray[3]}; pathPoints.p2 = {"x": darray[7], "y": darray[8]}; pathPoints.p3 = {"x": darray[0]+darray[2], "y": darray[1]+darray[3]}; pathPoints.p4 = {"x": darray[2], "y": darray[3]}; // = radius used in the circle path return pathPoints; break; case 'curve4': darray = d.replace(/M|Q/g, "").replace(/,/g, " ").split(" ").map(Number); for (i=0, j=1, o=9; i<darray.length-2; i+=2, j+=2, o++) { pathPoints["p"+(o-9)] = {"x": darray[i], "y": darray[j]}; }; return pathPoints; break; case 'curve3': darray = d.replace(/M|Q/g, "").replace(/,/g, " ").split(" ").map(Number) for (i=0, j=1, o=9; i<darray.length; i+=2, j+=2, o++) { pathPoints["p"+(o-9)] = {"x": darray[i], "y": darray[j]}; } return pathPoints; break; case 'curve2': darray = d.replace(/M|Q/g, "").replace(/,/g, " ").split(" ").map(Number); for (i=0, j=1, o=9; i<darray.length; i+=2, j+=2, o++) { pathPoints["p"+(o-9)] = {"x": darray[i], "y": darray[j]}; } return pathPoints; break; case 'curve1': darray = d.replace(/M|Q/g, "").replace(/,/g, " ").split(" ").map(Number); for (i=0, j=1, o=9; i<darray.length; i+=2, j+=2, o++) { pathPoints["p"+(o-9)] = {"x": darray[i], "y": darray[j]}; } return pathPoints; break; case 'cubic': darray = d.replace(/M|C/g, "").replace(/,/g, " ").split(" ").map(Number); for (i=0, j=1, o=9; i<darray.length; i+=2, j+=2, o++) { pathPoints["p"+(o-9)] = {"x": darray[i], "y": darray[j]}; } return pathPoints; break; } } function pointsToPath(pathPoints, pathSubclass) { console.log("joining "+pathPoints+"for a "+pathSubclass); } 
 html, body { margin: 0; padding: 0; border: 0; overflow:hidden; background-color: #fff; } svg { position: fixed; top:0%; left:0%; width:100%; height:100%; } .inventory { fill: transparent; stroke: black; cursor: move; } .draggable { fill: transparent; stroke: blue; cursor: move; } .dragged { fill: transparent; stroke: green; cursor: move; } .morphed { fill: transparent; stroke: red; cursor: move; } .lines { stroke: green; stroke-dasharray: 8,5; stroke-width: 1; opacity: 0.5; } path { stroke-width: 3; stroke: #000; stroke-linecap: round; } path.fill { fill: #3ff; } #canvasBackground { fill: lightgrey; } #inventoryBackground { fill: grey; } #morphUIrect { fill: none; stroke: blue; stroke-dasharray: 10,5; opacity: 0.1; } .label { fill: grey; } 
 <body> <svg id="svg" height="480" width="480" viewbox="0 0 480 580" preserveAspectRatio="xMinYMax 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" pointer-events="all"/> <rect id="inventoryBackground" width="480" height="100" x="0" y="480" pointer-events="all"/> <g id="inventory"> <path class="inventory" subclass="circle" d="M30,530 A35,35 1 1,1 100,530 A35,35 1 1,1 30,530" /> <path class="inventory" subclass="curve4" d="M125,500 Q155,490 185,500 Q195,530 185,560 Q155,570 125,560 Q115,530 125,500" /> <path class="inventory" subclass="curve3" d="M245,495 Q275,520 280,560 Q245,570 210,560 Q215,520 245,495" /> <path class="inventory" subclass="curve2" d="M305,515 Q345,475 385,515 Q345,555 305,515"/> <path class="inventory" subclass="curve1" d="M305,550 Q345,580 385,550"/> <path class="inventory" subclass="cubic" d="M420,495 C470,530 380,530 425,565"/> </g> <g id="canvas"> </g> <g id="morphUI"> <rect id="morphUIrect" visibility = "visible" x="0" y="0" width="0" height="0"></rect> <line id="l0" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l1" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l2" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l3" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l4" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l5" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l6" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <line id="l7" visibility = "hidden" class="lines" x1="0" y1="0" x2="0" y2="0"/> <circle id="0" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="1" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="2" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="3" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="4" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="5" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="6" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="7" visibility = "hidden" class="control" cx="0" cy="0" r="8"/> <circle id="8" visibility = "hidden" class="control" cx="0" cy="0" r="10" _x="0" _y="0"/> </g> </svg> </body> 

It's usually better not to attach event handlers to individual SVG shape elements. 通常最好不要将事件处理程序附加到单个SVG形状元素上。 If you move fast while dragging, then release the mouse button, the mouseup event can happen outside the shape you are dragging. 如果在拖动时快速移动,然后释放鼠标按钮,则mouseup事件可能会在您拖动的形状之外发生。 And you can end up with "stuck" shapes. 您最终可能会遇到“卡死”的形状。 It is better to attach the mouseup/mousedown events to the root <svg> element and keep track of which element you are dragging in a variable. 最好将mouseup / mousedown事件附加到根<svg>元素,并跟踪要在变量中拖动的元素。 This also has the benefit that you don't have to keep adding and removing event handlers from the dragged elements. 这还有一个好处,您不必一直在拖动的元素中添加和删除事件处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM