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;
}