I'm looking for a way to obtain a virtual bounding box that will wrap inside all the DOM elements.
For example, 2 divs with 100X100 px
dimensions with position absolute
one is placed at top:0 left :0
and the other is placed at top:700px left:700px
will result a 800X800
rect (image 1):
When scrolled I expect to still get an 800X800
rectangular with an offset of the scrolled distance (image 2):
I'm thinking of iterating through the DOM, getting all bounding client rectangulars and calculate manually, something like so:
document.querySelectorAll("*").forEach((el)=>{
let r = el.getBoundingClientRect();
//calculate
})
However, it seems not very efficient. Any help would be appreciated.
Update: This is the code so far, any insights would be appreciated:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}
I've ended up writing my own method:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}