0

Get element at specified position - JavaScript

This question only answers for a particular x and y point, but I would like to select all elements within a rectangle defined by 4 x and y points and be then able to only select elements with a certain classname, the classname could be "selectable". Is there a way to do this in regular javascript? What's the most efficient way to do this?

I was thinking about calling document.elementsFromPoint(x, y) repeatedly, but because the x and y arguments are not integers, I would have to call it an infinite number of times.

Sayaman
  • 1,145
  • 4
  • 14
  • 35

1 Answers1

1

I think i made an answer. Though I haven't tested it much.

First a description of the program. The program recursively goes through the dom starting from the body element and tests to see if it is entirely inside the query rectangle. My code assumes that elements wont be found outside of there parents, but if you don't want to assume this delete the marked lines.

// first some helper functions
function isRecPartialyInside(inside, outside){
    if((between(inside.xmin, outside.xmin,outside.xmax) || between(inside.xmax, outside.xmin,outside.xmax ) && (between(inside.ymin, outside.ymin,outside.ymax) || between(inside.ymax, outside.ymin,outside.ymax )))){
        return true;
    }
    return isRecFullyInside(outside, inside);
}

function between(x, min, max){
    return x > min && x < max; 
}

function clientRecToRec(clientRec){
    return {xmin: clientRec.x, xmax:clientRec.right, ymin: clientRec.y, ymax: clientRec.bottom};
}

function isRecFullyInside(possiblyInside, possiblyOutside){
    return (possiblyInside.xmin > possiblyOutside.xmin && possiblyInside.xmax < possiblyOutside.xmax && possiblyInside.ymin > possiblyOutside.ymin && possiblyInside.ymax < possiblyOutside.ymax);
}

function isClientRecFullyInside(clientRec, rec){
    let crec = clientRecToRec(clientRec);
    return isRecFullyInside(crec, rec);
}

function isClientRecPartiallyInside(clientRec,rec) {
    let crec = clientRecToRec(clientRec);
    return isRecPartialyInside(crec, rec);
}
// here is the real deal
function elementsFromBox(x1,x2,y1,y2){
    let output = [];
    let boundsRec = {xmin:x1,xmax:x2,ymin:y1,ymax:y2};
    let curr = document.body;
    let stack = [];
    let frame = {index:0,list:[curr]};
    stack.push(frame);
    while(stack.length > 0){
        let currFrame = stack.at(-1);
        if(currFrame.index >= currFrame.list.length){
            stack.pop();
            continue;
        }

        let currEl = currFrame.list[currFrame.index];
        currFrame.index +=1;
        // Check if the element is fully inside. If so report
        if(isClientRecFullyInside(currEl.getBoundingClientRect(), boundsRec)){
            output.push(currEl);
        }
        if(isClientRecPartiallyInside(currEl.getBoundingClientRect(), boundsRec)){ // del
            stack.push({index:0,list:currEl.children});
            continue;
        } // del
    }
    return output;
}
peter duffy
  • 195
  • 9