这是我第一次在 Stack Overflow 中发布问题,请随时评论我如何改进我的问题。
我正在尝试制作两个不能重叠的 SVG 矩形可拖动对象。为此,我使用 Snap.svg 来拖动元素,并使用 Snap API 中的 .isBBoxIntersect 实用程序方法在每次调用移动函数时获取它们的边界框以查看它们是否发生碰撞。如果它们发生碰撞,我想确保它们不会重叠,从而使每个对象都无法通过另一个对象。当前被拖动的对象将在某个轴上移动,直到碰撞再次返回 false。我在这里有一些我想要的基本代码:
<html>
<head>
<title>
</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
</head>
<body>
<script>
var s = Snap(600,500);
var rect = s.rect(0,0,40,40);
var rectr = s.rect(400,90,50,50);
var b=0;
var c=0;
var isInter;
var move = function(dx,dy, x, y, event) {
var b1 = rect.getBBox();
var b2 = rectr.getBBox();
isInter = Snap.path.isBBoxIntersect(b1, b2);
if (isInter==false) {
b=dx;
c=dy;
}
if (isInter==true) {
if (b1.y2==b2.y&&b1.x2==b2.x||b1.x==b2.x2&&b1.y2==b2.y){c=b2.y-b1.h, b=dx
}
else if (b1.x==b2.x2&&b1.y==b2.y2||b1.x2==b2.x&&b1.y==b2.y2){c=b2.y2; b=dx;}
else if (b1.y2==b2.y){(dy>=b2.y-b1.h) ? (c=b2.y-b1.h, b=dx): (b=dx, c=dy);}
else if (b1.y==b2.y2){(dy<=b1.y) ? (c=b2.y2, b=dx):(b=dx,c=dy);}
else if (b1.x2==b2.x){(dx>=b1.x) ? (b=b2.x-b1.width, c=dy):(b=dx, c=dy);}
else if (b1.x==b2.x2){(dx<=b1.x2) ? (b=b2.x2, c=dy):(b=dx, c=dy);}
else {b=dx; c=dy;}
}
this.attr({
transform: this.data('origTransform') + ((this.data('origTransform')) ? "t": "T") + [b,c]
});
}
var start = function() {
this.data('origTransform', this.transform().local );
b=0;
c=0;
}
rect.drag(move, start);
circle.drag(move, start);
</script>
</body>
</html>
这些是出现的三个主要问题:
如果拖得太快,引擎跟不上,可拖动对象就会重叠。我希望有一种无论拖动多快都能防止重叠的方法。
只有在 rectr 上拖动时,碰撞才适用于 rect。我可以很容易地在 rect 上为 rectr 添加另一个碰撞检测 block ,但我认为这会大大降低引擎速度。我的碰撞检测似乎过于复杂。因此,我希望有一种更有效的方法来测试碰撞。
如果先拖动rectr,然后在rectr 上拖动rect,则碰撞检测完全失败。这可能是 .getBBox() 的问题,但我不能肯定地说。
如能就这三个问题提供任何帮助,我们将不胜感激。
谢谢!
最佳答案
抱歉,我只能提供使用 Javascript 的替代方案。也许这会在将来的某个时候对您有所帮助。
此示例创建随机放置的五十 (50) 个 svg 形状。每个形状都是可拖动的。如果拖动的形状的边界框与另一个形状相交,则其不透明度会发生变化,直到拖动的形状移出相交范围。
祝你好运。
<head>
<title>Untitled</title>
</head>
<body onLoad=svgGLOB(50,800,800,30)>
<div style=font-family:arial>
Fifty(50) svg shapes are created and randomly located. Each shape is draggable. If the dragged shape's bounding box intersects another shape, its opacity is changed until the dragged shape moves out of intersect range.
</div>
<div id=svgDiv style='width:800px;height:800px;border:1px solid black'>
<svg id=mySVG width="800" height="800" onmousedown="startDrag(evt)" onmousemove="drag(evt)" onmouseup="endDrag()"></svg>
</div>
</body>
<script>
function intersectShape(target)
{
var r1 = target.getBoundingClientRect(); //BOUNDING BOX OF THE TARGET OBJECT
for(k=0;k<globG.childNodes.length;k++)
{
var shape=globG.childNodes.item(k)
if(shape!=target)
{
var r2=shape.getBoundingClientRect();
//CHECK IF ANY TWO BOUNDING BOXES OVERLAP
if(!(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top))
shape.setAttribute("opacity",.5)
else
shape.setAttribute("opacity",1)
}
}
}
var TransformRequestObj
var TransList
var DragTarget=null;
var Dragging = false;
var OffsetX = 0;
var OffsetY = 0;
//---mouse down over element---
function startDrag(evt)
{
if(!Dragging) //---prevents dragging conflicts on other draggable elements---
{
if(evt.target.getAttribute("class")=="dragTarget")
{
DragTarget = evt.target;
DragTarget.setAttribute("style","cursor:move")
//---reference point to its respective viewport--
var pnt = DragTarget.ownerSVGElement.createSVGPoint();
pnt.x = evt.clientX;
pnt.y = evt.clientY;
//---elements transformed and/or in different(svg) viewports---
var sCTM = DragTarget.getScreenCTM();
var Pnt = pnt.matrixTransform(sCTM.inverse());
TransformRequestObj = DragTarget.ownerSVGElement.createSVGTransform()
//---attach new or existing transform to element, init its transform list---
var myTransListAnim=DragTarget.transform
TransList=myTransListAnim.baseVal
OffsetX = Pnt.x
OffsetY = Pnt.y
Dragging=true;
}
}
}
//---mouse move---
function drag(evt)
{
if(Dragging)
{
var pnt = DragTarget.ownerSVGElement.createSVGPoint();
pnt.x = evt.clientX;
pnt.y = evt.clientY;
//---elements in different(svg) viewports, and/or transformed ---
var sCTM = DragTarget.getScreenCTM();
var Pnt = pnt.matrixTransform(sCTM.inverse());
Pnt.x -= OffsetX;
Pnt.y -= OffsetY;
TransformRequestObj.setTranslate(Pnt.x,Pnt.y)
TransList.appendItem(TransformRequestObj)
TransList.consolidate()
intersectShape(DragTarget)
}
}
//--mouse up---
function endDrag()
{
Dragging = false;
DragTarget.setAttribute("style","cursor:default")
}
//==================add a bunch of SVG elements============
//---onload: svgGLOB(50,800,800,30)---
function svgGLOB(elems,svgWidth,svgHeight,elemSize)
{
/* ---fill empty inline SVG element---
<div id="svgDiv"><svg id="mySVG" /></div>
*/
var NS="http://www.w3.org/2000/svg"
mySVG.setAttribute("width",svgWidth)
mySVG.setAttribute("height",svgHeight)
svgDiv.style.width=svgWidth+"px"
svgDiv.style.height=svgHeight+"px"
var globG=document.createElementNS(NS,"g")
globG.id="globG"
globG.setAttribute("stroke","black")
globG.setAttribute("stroke-width",1)
mySVG.appendChild(globG)
var points=randomPoints(elems,svgWidth,svgHeight,elemSize)
var n=points.length
var circleCnt=0
var ellipseCnt=0
var rectCnt=0
var polygonCnt=0
var RandomElems=[]
RandomElems[0]="circle"
RandomElems[1]="rect"
RandomElems[2]="ellipse"
RandomElems[3]="polygon_3"
RandomElems[4]="polygon_4"
RandomElems[5]="polygon_5"
RandomElems[6]="polygon_6"
RandomElems[7]="polygon_7"
RandomElems[8]="polygon_8"
RandomElems[9]="polygon_9"
RandomElems[10]="polygon_10"
RandomElems[11]="polygon_11"
RandomElems[12]="polygon_12"
for(var k=0;k<n;k++)
{
var rand=rdm(0,12)
var elemStr=RandomElems[rand]
if(!elemStr.indexOf("_"))
var elemSt=elemStr
else
var elemSt=elemStr.split("_")[0]
var elem=document.createElementNS(NS,elemSt)
if(elemSt=="circle")
{
elem.setAttribute("r",elemSize)
elem.setAttribute("fill",rcolor())
elem.setAttribute("cx",points[k][0])
elem.setAttribute("cy",points[k][1])
elem.id=elemSt+(circleCnt++)
}
else if(elemSt=="ellipse")
{
elem.setAttribute("rx",elemSize)
elem.setAttribute("ry",elemSize/2)
elem.setAttribute("fill",rcolor())
elem.setAttribute("cx",points[k][0])
elem.setAttribute("cy",points[k][1])
elem.id=elemSt+(ellipseCnt++)
}
else if(elemSt=="rect")
{
elem.setAttribute("width",elemSize)
elem.setAttribute("height",elemSize)
elem.setAttribute("fill",rcolor())
elem.setAttribute("x",points[k][0])
elem.setAttribute("y",points[k][1])
elem.id=elemSt+(rectCnt++)
}
else if(elemSt=="polygon")
{
var pgonSides=parseInt(elemStr.split("_")[1])
var pgonPnts=polygon(pgonSides,elemSize,points[k][0],points[k][1])
elem.setAttribute("fill",rcolor())
elem.setAttribute("points",pgonPnts.join())
elem.id=elemSt+(polygonCnt++)
}
elem.setAttribute("class","dragTarget")
globG.appendChild(elem)
}
//---obtain a random whole number from a thru b---
function rdm(a,b)
{
return a + Math.floor(Math.random()*(b-a+1));
}
function randomPoints(elems,svgWidth,svgHeight,elemSize)
{
//--return format:[ [x,y],[x,y],,, ]
//---Generate random points---
function times(n, fn)
{
var a = [], i;
for (i = 0; i < n; i++) {
a.push(fn(i));
}
return a;
}
var width=svgWidth-2*elemSize
var height=svgHeight-2*elemSize
return RandomPnts = times(elems, function() { return [Math.floor(width * Math.random()) + elemSize, Math.floor(height * Math.random()) + elemSize] });
}
//---random color---
function rcolor()
{
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ )
{
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
function polygon(vCnt,radius,centerX,centerY)
{
var myPoints=[]
var polyXPts = Array(vCnt);
var polyYPts = Array(vCnt);
var vertexAngle = 360/vCnt;
//---init polygon points processor---
for(var v=0; v<vCnt; v++)
{
theAngle = (v*vertexAngle)*Math.PI/180;
polyXPts[v] = radius*Math.cos(theAngle);
polyYPts[v] = -radius*Math.sin(theAngle);
}
//--note points are CCW---
for(var v=0;v<vCnt; v++)
{
var point=[centerX+polyXPts[v],centerY+polyYPts[v]]
myPoints.push(point)
}
return myPoints
}
}
</script>
关于javascript - 使用 Snap.svg (Javascript) 不可重叠的 Draggables,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38099780/