17

Given two points on a webpage and a set of DOM elements, how to find out the subset of those DOM elements that sit inside the rectangle area defined by the two points?

I am working on a web-based gallery, in which every photo is wrapped in a li tag. When a user drag out a rectangle area with mouse, all li elements inside the rectangle are marked as selected.

Prefer a jQuery solution for less wordy and an efficient way.

powerboy
  • 10,523
  • 20
  • 63
  • 93

1 Answers1

13

Try something like this:

// x1, y1 would be mouse coordinates onmousedown
// x2, y2 would be mouse coordinates onmouseup
// all coordinates are considered relative to the document
function rectangleSelect(selector, x1, y1, x2, y2) {
    var elements = [];
    jQuery(selector).each(function() {
        var $this = jQuery(this);
        var offset = $this.offset();
        var x = offset.left;
        var y = offset.top;
        var w = $this.width();
        var h = $this.height();

        if (x >= x1 
            && y >= y1 
            && x + w <= x2 
            && y + h <= y2) {
            // this element fits inside the selection rectangle
            elements.push($this.get(0));
        }
    });
    return elements;
}

// Simple test
// Mark all li elements red if they are children of ul#list
// and if they fall inside the rectangle with coordinates: 
// x1=0, y1=0, x2=200, y2=200
var elements = rectangleSelect("ul#list li", 0, 0, 200, 200);
var itm = elements.length;
while(itm--) {
    elements[itm].style.color = 'red';
    console.log(elements[itm]);
}

For a vanilla JS solution, check out this pen: https://codepen.io/ArtBIT/pen/KOdvjM

ArtBIT
  • 3,931
  • 28
  • 39
  • 2
    Thanks ArtBIT. I just searched for a while on Google. Seems that no convenient way to do this, no better solution other than looping all DOM elements and doing elementary school math on them. – powerboy Oct 23 '10 at 02:32
  • No worries @powerboy, and yeah, that's why I added the `selector` support, to reduce the number of elements you'd need to process. – ArtBIT Oct 23 '10 at 02:35
  • You can use [getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) to get an object with `top`,`right`,`bottom`,`left`,`width` and `height`, in one call. – Yuval A. Jul 29 '15 at 13:36
  • @ArtBIT: How do I find element(s) inside given rectangle coordinates if I don't have a selector to pass into 'rectangleSelect' method mentioned above? Don't want to give top level document as selector as it will be a big performance hit to go through each element. – Pankaj Kapare Jun 11 '21 at 15:31
  • @PankajKapare performance is exactly the reason why you need to pass in the selector since it limits the traversing to only the children of that element. In the example above, jQuery will do the optimization for you, it would first get a reference to the `ul#list` element, and then select any `li` elements that are its children, and check whether they fall inside the selection rectangle. Try to pass descendant selectors, which would help jQuery to limit the scope of the search. – ArtBIT Jun 23 '21 at 10:20