Is there any way to find the nearest element to a point (x,y) with approximate height and width? Even if there will be multiple components of the same height and width it should take the nearest one.
I am trying to create an approach in Puppeteer to identify the nearest element to a coordinate (x,y) while testing or web-scraping.
You need to better define nearest element but once you do, write a distance(point, element) function, iterate all elements and take the smallest of those.
Let's go with the easy one, a distance to an element center of gravity.
var stats = document.querySelector(".stats");
var element = document.querySelector(".element");
window.addEventListener('mousemove', function(ev) {
var mx = ev.pageX
var my = ev.pageY
var str = "distance(" + ev.pageX + ", " + ev.pageY + ", elem) = " + distance(mx, my, element);
stats.innerText = str;
})
function distance(x, y, element) {
var rect = element.getBoundingClientRect() // modern browsers
var x1 = rect.x
var y1 = rect.y
var x2 = x1 + rect.width
var y2 = y1 + rect.height
return Math.sqrt(((x1 + x2) / 2 - x) ** 2 + ((y1 + y2) / 2 - y) ** 2).toFixed(2);
}
body {
height: 1200px;
}
.element {
width: 100px;
height: 100px;
background: green;
position: absolute;
top: 100px;
left: 300px;
}
<body>
<div class="stats"></div>
<div class="element"></div>
</body>
Now having that we can have a few elements to evaluate distance and choose smallest.
window.addEventListener('mousemove', function(ev) {
var mx = ev.pageX
var my = ev.pageY
var min = Infinity
var chosen = null;
document.querySelectorAll("body *").forEach(function(element) {
element.classList.remove("closest")
var d = +distance(mx, my, element)
if (d < min) {
min = d
chosen = element;
}
})
chosen.classList.add("closest")
})
function distance(x, y, element) {
var rect = element.getBoundingClientRect() // modern browsers
var x1 = rect.x
var y1 = rect.y
var x2 = x1 + rect.width
var y2 = y1 + rect.height
return Math.sqrt(((x1 + x2) / 2 - x) ** 2 + ((y1 + y2) / 2 - y) ** 2).toFixed(2);
}
body {
height: 1200px;
}
.element {
width: 100px;
height: 100px;
background: green;
position: absolute;
top: 100px;
left: 300px;
}
.elem1 {}
.elem2 {
background: blue;
top: 20px;
left: 20px;
}
.elem3 {
background: yellow;
top: 70px;
left: 50px;
width: 200px;
height: 20px;
}
.closest {
border: 2px solid red;
}
<body>
<div class="element elem1"></div>
<div class="element elem2"></div>
<div class="element elem3"></div>
</body>
An improvement would be distance to closest corner. But also need to consider being on top of element and z-index and maybe more stuff.