如何使可拖动的div元素不堆叠在一起



我使用let divEx = document.createElement('div')创建各种可拖动元素,然后将其添加到main.appendChild(divEx)的主div,最后使用memDiv.setAttribute('draggable', 'true')将属性draggable设置为true。当按下按钮时,整个功能都在主Js文件中调用的函数中。虽然拖放功能工作得很好,但是如果position style属性被设置为绝对属性,则div元素被设置在每个元素之上,如果在CSS中被设置为相对属性,则div元素被设置在彼此之下。在DOM中,它显示了不同的div元素,但是它们的位置都是相同的。我希望下面的截图能解释这个问题:

绝对例子:

屏幕上有三个div元素(class=memDiv)两个相互重叠,一个新创建的

这是我移动第三个元素后显示的,它也堆叠在其他元素的上面

这个问题的最佳解决方案是什么?

答案:关键方法/解决方案是div元素

之间的Collision Detection

看起来你正在尝试做一个游戏或类似的东西,请节省你自己的痛苦/不要重新发明轮子:),只是利用一个库,寻找collision detection或设置Z索引为1,并检查重叠,我更喜欢sat.js库。

注意:这里是sat.js,看看这个来自第三方的样本/credit to OSU blake

console.clear();
var log = console.log.bind(console);

// Alias a few things in SAT.js to make the code shorter
var V = function (x, y) { return new SAT.Vector(x, y); };
var P = function (pos, points) { return new SAT.Polygon(pos, points); };
var C = function (pos, r) { return new SAT.Circle(pos, r); };
var B = function (pos, w, h) { return new SAT.Box(pos, w, h); };
// Converts a SAT.Polygon into a SVG path string.
function poly2path(polygon) {
var pos = polygon.pos;
var points = polygon.calcPoints;
var result = 'M' + pos.x + ' ' + pos.y;
result += 'M' + (pos.x + points[0].x) + ' ' + (pos.y + points[0].y);
for (var i = 1; i < points.length; i++) {
var point = points[i];
result += 'L' + (pos.x + point.x) + ' ' + (pos.y + point.y);
}
result += 'Z';
return result;
}
// Create a Raphael start drag handler for specified entity
function startDrag(entity) {
return function () {
this.ox = entity.data.pos.x;
this.oy = entity.data.pos.y;
};
}
// Create a Raphael move drag handler for specified entity
function moveDrag(entity, world) {
return function (dx, dy) {
// This position updating is fairly naive - it lets objects tunnel through each other, but it suffices for these examples.
entity.data.pos.x = this.ox + dx;
entity.data.pos.y = this.oy + dy;
world.simulate();
};
}
// Create a Raphael end drag handler for specified entity
function endDrag(entity) {
return function () {
entity.updateDisplay();
};
}
var idCounter = 0;
function noop() {}
function Entity(data, display, options) {
options = _.defaults(options || {}, {
solid: false, // Whether this object is "solid" and therefore should participate in responses.
heavy: false, // Whether this object is "heavy" and can't be moved by other objects.
displayAttrs: {}, // Raphael attrs to set on the display object
onCollide: noop, // Function to execute when this entity collides with another - arguments are (otherEntity, response)
onTick: noop // Function called at the start of every simulation tick - no arguments
});
this.id = idCounter++;
this.data = data;
this.display = display;
this.displayAttrs = _.extend({
fill: '#CCC',
stroke: '#000'
}, options.displayAttrs);
this.isSolid = options.solid;
this.isHeavy = options.heavy;
this.onCollide = options.onCollide;
this.onTick = options.onTick;
}
Entity.prototype = {
remove: function () {
this.display.remove();
},
// Call this to update the display after changing the underlying data.
updateDisplay: function () {
if (this.data instanceof SAT.Circle) {
this.displayAttrs.cx = this.data.pos.x;
this.displayAttrs.cy = this.data.pos.y;
this.displayAttrs.r = this.data.r;
} else {
this.displayAttrs.path = poly2path(this.data);
}
this.display.attr(this.displayAttrs);
},
tick: function () {
this.onTick();
},
respondToCollision: function (other, response) {
this.onCollide(other, response);
// Collisions between "ghostly" objects don't matter, and
// two "heavy" objects will just remain where they are.
if (this.isSolid && other.isSolid &&
!(this.isHeavy && other.isHeavy)) {
if (this.isHeavy) {
// Move the other object out of us
other.data.pos.add(response.overlapV);
} else if (other.isHeavy) {
// Move us out of the other object
this.data.pos.sub(response.overlapV);
} else {
// Move equally out of each other
response.overlapV.scale(0.5);
this.data.pos.sub(response.overlapV);
other.data.pos.add(response.overlapV);
}
}
}
};
function World(canvas, options) {
options = _.defaults(options || {},  {
loopCount: 1 // number of loops to do each time simulation is called. The higher the more accurate the simulation, but slowers.
});
this.canvas = canvas; // A raphael.js canvas
this.response = new SAT.Response(); // Response reused for collisions
this.loopCount = options.loopCount;
this.entities = {};
}
World.prototype = {
addEntity: function(data, options) {
var entity = new Entity(
data,
data instanceof SAT.Circle ? this.canvas.circle() : this.canvas.path(),
options
);
// Make the display item draggable if requested.
if (options.draggable) {
entity.display.drag(moveDrag(entity, this), startDrag(entity), endDrag(entity));
}
entity.updateDisplay();
this.entities[entity.id] = entity;
return entity;
},
removeEntity: function (entity) {
entity.remove();
delete this.entities[entity.id];
},
simulate: function () {
var entities = _.values(this.entities);
var entitiesLen = entities.length;
// Let the entity do something every simulation tick
_.each(entities, function (entity) {
entity.tick();
});
// Handle collisions - loop a configurable number of times to let things "settle"
var loopCount = this.loopCount;
for (var i = 0; i < loopCount; i++) {
// Naively check for collision between all pairs of entities 
// E.g if there are 4 entities: (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)
for (var aCount = 0; aCount < entitiesLen; aCount++) {
var a = entities[aCount];
for (var bCount = aCount + 1; bCount < entitiesLen; bCount++) {
var b = entities[bCount];
this.response.clear();
var collided;
var aData = a.data;
var bData = b.data;
if (aData instanceof SAT.Circle) {
if (bData instanceof SAT.Circle) {
collided = SAT.testCircleCircle(aData, bData, this.response);
} else {
collided = SAT.testCirclePolygon(aData, bData, this.response);
}
} else {
if (bData instanceof SAT.Circle) {
collided = SAT.testPolygonCircle(aData, bData, this.response);
} else {
collided = SAT.testPolygonPolygon(aData, bData, this.response);
}
}
if (collided) {
a.respondToCollision(b, this.response);
}
}
}
}
// Finally, update the display of each entity now that the simulation step is done.
_.each(entities, function (entity) {
entity.updateDisplay();
});
}
};


(function () {
var canvas = Raphael('example1', 640, 480);
var world = new World(canvas);
var poly = world.addEntity(P(V(160,120), [V(0,0), V(60, 0), V(100, 40), V(60, 80), V(0, 80)]).translate(-50, -40), { solid: true, draggable: true });
var poly2 = world.addEntity(P(V(10,10), [V(0,0), V(30, 0), V(30, 30), V(0, 30)]), { solid: true, draggable: true });
var circle1 = world.addEntity(C(V(50, 200), 30), { solid: true, heavy: true, draggable: true });
function doRotate() {
poly.data.setAngle(poly.data.angle + (Math.PI / 60)); // Assuming 60fps this will take ~2 seconds for a full rotation
world.simulate();
window.requestAnimationFrame(doRotate);
}
window.requestAnimationFrame(doRotate);
}());

(function () {
var canvas = Raphael('example2', 640, 640);
var world = new World(canvas, {
loopCount: 5
});
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
var displayAttrs = {
fill: 'rgba(' + Math.floor(Math.random() * 255) + ',' +  Math.floor(Math.random() * 255) + ',' +  Math.floor(Math.random() * 255) + ')'
}
var c = world.addEntity(C(V((40 * i) + 20, (40 * j) + 20), 18), { solid: true, draggable: true, displayAttrs: displayAttrs });
}
}
}());

相关内容

  • 没有找到相关文章

最新更新