The following code saves the boundaries of the elements in two lists: x and y positions. Then, you can use a for-loop
to start at a given offset, and walk through the list. At the bottom of the answer, an implementation is shown.
// These arrays are going to contain many empty elements ;)
var xAxis = [];
var yAxis = [];
// Our storage. Each element looks like: [$element, top, right, bottom, left]
// Beware of cross-references! Deleted elements cannot be GCed if they're here!
var allElements = [];
/*
* @param $elem jQuery object
* @returns Object containing the jQuery object and the floored border offsets
*/
function getBorders($elem) {
$elem = $elem instanceof jQuery ? $elem.first() : $($elem);
var offset = $elem.offset(); // Properties: top, left
var width = $elem.outerWidth(); // Includes padding, border.
var leftBorder = offset.left; // Position of the left border ->|
var rightBorder = leftBorder + width; // Position of the right border |<-
var height = $elem.outerHeight(); // Includes padding, border
var topBorder = offset.top; // Position of the top border _v_
var bottomBorder = offset.top + height;// Position of the bottom border ^
// Turn all numbers in integers, so that they can be used as indexes
// for arrays
// See also: http://stackoverflow.com/a/8112802/938089
return {
$elem: $elem,
top: ~~topBorder,
right: ~~rightBorder,
bottom: ~~bottomBorder,
left: ~~leftBorder
};
}
$('.widget').each(function() {
var $this = $(this);
var info = getBorders($this);
allElements.push(info);
// The positions are floored, so that they can be used as a quick reference
xAxis[info.left] = xAxis[info.right] = info;
yAxis[info.top] = yAxis[info.bottom] = info;
});
The created list can now be used to check whether there's any element which collides. For example, consider the following function:
function doesItCollide($elem) {
// WeakMaps are useful. For compatibility, I don't use them.
var info$elem = getBorders($elem);
// info$elem properties: $elem, top, right, bottom, left
// Y-oriented
for (var y=info$elem.top; y<yAxis.length; y++) {
var candidate = yAxis[y];
// Not undefined, and not iself
if (candidate && candidate.$elem[0] !== info$elem.$elem[0]) {
// Check whether the element is inside the range
if (candidate.top >= info$elem.bottom &&
candidate.bottom >= info$elem.bottom) continue;
// It's here, so the top / bottom are possibly in the same range
// Check whether the x-positions are also colliding
if (candidate.left >= info$elem.left && /* Left within range? */
candidate.left <= info$elem.right || /* OR */
candidate.right <= info$elem.right && /* Right within range? */
candidate.right >= info$elem.left) {
return candidate;
}
}
}
return null;
}
Example (Demo: http://jsfiddle.net/LtJsM/):
$('.widget').each(function() {
var $this = $(this);
var overlapping = doesItCollide($this);
if (overlapping) {
alert('Current element: '+this.className +
'\nColliding element: ' + overlapping.$elem[0].className);
}
});