使用 jQuery 分层交叉元素
我有一个包含可拖动/可放置元素的页面,一旦放置,需要计算它们相对于它们可能接触的其他可拖动元素的左侧位置和宽度。
这本身并不太难,但我真正遇到的麻烦是让它们填补空白。如何让可拖动对象填充空白空间而不相互重叠?
// $t is the element being added/dropped.
// nd refers to New Dimensions, IE, the new dimensions for $t
// existingDivs gets any DIV's that have already been added to the dom
var $t = $(this), nd = {t:$t.position().top, h:$t.height(), l: 0, w: 95},
existingDivs = $('#container .subContainer .draggable'), intersectArr = [],
nonIntersectArr = [], finalArr = [];
// If there are no DIV's in the DOM you dont need to check if they intersect.
if (existingDivs.length > 0) {
// Find the DIV's that Intersect with the one being added
intersectArr = $.grep(existingDivs, function(val,num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
// If they intersect add it to this array
return ((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
(nd.t <= xd.t && nd.t+nd.h > xd.t));
});
// Find the DIV's that DO NOT Intersect with the one being added
nonIntersectArr = $.grep(existingDivs, function(val,num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
// If they DO NOT intersect add it to this array
return ((xd.t > nd.t && xd.t > nd.t+nd.h) ||
(nd.t > xd.t && nd.t > xd.t+xd.h));
});
// For every element that does not intersect, check it verse the ones that do
$(nonIntersectArr).each(function(){
// nid is Non Intersecting Dimensions
var $t2 = $(this), c = 0, nid = {h:$t2.height(),
w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
$(intersectArr).each(function(){
// id is Intersecting Dimensions
var $t3 = $(this), id = {h:$t3.height(), w:parseFloat($t3.css('width')),
l:parseFloat($t3.css('left')), t:$t3.position().top};
// if the non intersecting hits one that is intersecting, then there is no space
// beneath/near it, so we add it to the final intersecting array then increment c
if((id.t <= nid.t && id.t+id.h > nid.t) ||
(nid.t <= id.t && nid.t+nid.h > id.t)){ finalArr.push(this); c++; }
else { finalArr.push(this); }
});
// if c has been incremented, we cant use this nonIntersect, so add it to the final
if(c > 0) { finalArr.push(this); }
});
// make sure all items in the final Array are unique
finalArr = $.unique(finalArr);
// iterate over the final array, processing the dimensions of each element in the
// array layering them so you can see each one
$(finalArr).each(function(num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(this), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
if(((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
(nd.t <= xd.t && nd.t+nd.h > xd.t))) {
if(nd.l == xd.l){
nd.w = ((95/(finalArr.length+1))*1.5);
xd.l = ((nd.w)*(num));
$(finalArr).each(function(ci){
$(this).css({left:((nd.w*ci)*0.58)+'%',
width:((95/(finalArr.length+1))*1.5)+'%'});
nd.l = ((nd.w*ci)*0.58);
});
}
}
});
}
// Add the New Element to the container and position accordingly.
nd.l = ((nd.l/finalArr.length)*(finalArr.length+1))+'%';
nd.w = nd.w+'%';
$('#container .subContainer').append('<div style="top:'+nd.t+'px;left:'+nd.l+
';width:'+nd.w+';height:'+nd.h+'px;" class="dragId_'+$t.attr('id')+
' draggable"><div class="title">'+$t.attr('title')+'</div></div>');
任何建议/帮助将不胜感激。谢谢。
I have a page with draggable/droppable elements that once dropped need to calculate their left position and width in regards to other draggables that they may be touching.
This isn't too hard in and of itself, but where I'm really having trouble is getting them to fill in empty space. How do I get the draggables to fill in the empty space without doubling on top of each other?
// $t is the element being added/dropped.
// nd refers to New Dimensions, IE, the new dimensions for $t
// existingDivs gets any DIV's that have already been added to the dom
var $t = $(this), nd = {t:$t.position().top, h:$t.height(), l: 0, w: 95},
existingDivs = $('#container .subContainer .draggable'), intersectArr = [],
nonIntersectArr = [], finalArr = [];
// If there are no DIV's in the DOM you dont need to check if they intersect.
if (existingDivs.length > 0) {
// Find the DIV's that Intersect with the one being added
intersectArr = $.grep(existingDivs, function(val,num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
// If they intersect add it to this array
return ((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
(nd.t <= xd.t && nd.t+nd.h > xd.t));
});
// Find the DIV's that DO NOT Intersect with the one being added
nonIntersectArr = $.grep(existingDivs, function(val,num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
// If they DO NOT intersect add it to this array
return ((xd.t > nd.t && xd.t > nd.t+nd.h) ||
(nd.t > xd.t && nd.t > xd.t+xd.h));
});
// For every element that does not intersect, check it verse the ones that do
$(nonIntersectArr).each(function(){
// nid is Non Intersecting Dimensions
var $t2 = $(this), c = 0, nid = {h:$t2.height(),
w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
$(intersectArr).each(function(){
// id is Intersecting Dimensions
var $t3 = $(this), id = {h:$t3.height(), w:parseFloat($t3.css('width')),
l:parseFloat($t3.css('left')), t:$t3.position().top};
// if the non intersecting hits one that is intersecting, then there is no space
// beneath/near it, so we add it to the final intersecting array then increment c
if((id.t <= nid.t && id.t+id.h > nid.t) ||
(nid.t <= id.t && nid.t+nid.h > id.t)){ finalArr.push(this); c++; }
else { finalArr.push(this); }
});
// if c has been incremented, we cant use this nonIntersect, so add it to the final
if(c > 0) { finalArr.push(this); }
});
// make sure all items in the final Array are unique
finalArr = $.unique(finalArr);
// iterate over the final array, processing the dimensions of each element in the
// array layering them so you can see each one
$(finalArr).each(function(num){
// xd is Existing Dimensions, for the current item being checked
// verse the one being added.
var $t2 = $(this), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
l:parseFloat($t2.css('left')), t:$t2.position().top};
if(((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
(nd.t <= xd.t && nd.t+nd.h > xd.t))) {
if(nd.l == xd.l){
nd.w = ((95/(finalArr.length+1))*1.5);
xd.l = ((nd.w)*(num));
$(finalArr).each(function(ci){
$(this).css({left:((nd.w*ci)*0.58)+'%',
width:((95/(finalArr.length+1))*1.5)+'%'});
nd.l = ((nd.w*ci)*0.58);
});
}
}
});
}
// Add the New Element to the container and position accordingly.
nd.l = ((nd.l/finalArr.length)*(finalArr.length+1))+'%';
nd.w = nd.w+'%';
$('#container .subContainer').append('<div style="top:'+nd.t+'px;left:'+nd.l+
';width:'+nd.w+';height:'+nd.h+'px;" class="dragId_'+$t.attr('id')+
' draggable"><div class="title">'+$t.attr('title')+'</div></div>');
Any suggestions/help would be much appreciated. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
以下是您需要执行的算法:
够简单吗?嗯,这是简化版本:
编辑:例如...
假设我将正方形 3 放在正方形 1 和正方形 2 的顶部:
步骤 1. 找到与某物相交的最右边的形状。在本例中,这是形状 2。将其移到相交部分的右侧。
现在有形状接触吗?是的,最右边的是形状 3。将它移到它所接触的形状的右侧,形状 1:
现在有形状接触吗?是的,最右边的是形状 2。将它移到它所接触的形状的右侧,形状 3:
现在有形状接触吗?不。所以我们已经完成了第 1 步。
第 2 步:找到最左边没有紧贴任何物体的形状。在这种情况下,最左边没有依偎着任何东西的是形状 4。将其向左移动,使其位于其左侧最右侧形状的右侧,该形状与其具有相同的 y 坐标:
有什么东西没有依偎着任何东西吗?没有!所以你完成了!
正如您所看到的,基本上有一个扩张阶段和一个收缩阶段。你从右到左进行扩展阶段,这样就不会通过其他东西来扩展任何东西。你从左到右进行收缩阶段,这样就不会通过其他东西收缩。
Here's the algorithm for what you need to do:
Simple enough? Well, here's the simplified version:
Edit: For example...
Suppose I took square 3 and plopped it on top of square 1 and square 2:
Step 1. Find the rightmost shape that's intersecting something. In this case, that's shape 2. Move it right of what it's intersecting.
Are there shapes touching now? Yes, and the rightmost one is shape 3. Move it right of the shape it's touching, shape 1:
Are there shapes touching now? Yes, and the rightmost one is shape 2. Move it right of the shape it's touching, shape 3:
Are there shapes touching now? No. So we're done step 1.
Step 2: Find the leftmost shape that's not snuggled up to anything. In this case, the leftmost one not snuggled up to anything is shape 4. Move it left so it's just right of the rightmost shape left of it that exists at the same y-coordinates as it:
Anything not snuggled up to anything? Nope! So you're done!
As you can see, there's basically an expansion phase and a contraction phase. You do the expansion phase right to left so that nothing gets expanded right through something else. You do the contraction phase left to right so nothing gets contracted through something else.