Finding closest anchor href via scrollOffset
HTML
<button class="getClosest" href="#">Find Closest</button>
<script type="text/javascript" charset="utf-8">
// This just generates random anchors on the page
for ( var i=0; i < 500; i++ ) {
var anchor = document.createElement( 'a' );
anchor.id = 'p-' + i;
var text = document.createTextNode( i );
anchor.appendChild( text );
if( ! ( i % 30 ) ) document.body.appendChild( document.createElement( 'br' ) );
document.body.appendChild( anchor );
};
</script>
CSS
body { white-space: nowrap; }
a {
font: 12px/30px sans-serif;
background: #222;
border-radius: 50%;
color: #fff;
padding: 5px;
display: inline-block;
width: 100%;
height: 30px;
margin: 20px;
vertical-align: middle;
text-align: center;
}
.getClosest {
position: fixed;
top: 50%;
left: 50%;
padding: 5px;
width: 200px;
height: 40px;
margin: -20px 0 0 -100px;
}
JavaScript
// findPos : courtesy of @ppk - see http://www.quirksmode.org/js/findpos.html
var findPos = function(obj) {
var curleft = 0,
curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft;
curtop = obj.offsetTop;
while ((obj = obj.offsetParent)) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
}
return [curleft, curtop];
};
var findClosestAnchor = function( anchors ) {
var sortByDistance = function(element1, element2) {
var pos1 = findPos( element1 ),
pos2 = findPos( element2 );
// vect1 & vect2 represent 2d vectors going from the top left extremity of each element to the point positionned at the scrolled offset of the window
var vect1 = [
window.scrollX - pos1[0],
window.scrollY - pos1[1]
],
vect2 = [
window.scrollX - pos2[0],
window.scrollY - pos2[1]
];
// we compare the length of the vectors using only the sum of their components squared
// no need to find the magnitude of each (this was inspired by Mageek’s answer)
var sqDist1 = vect1[0] * vect1[0] + vect1[1] * vect1[1],
sqDist2 = vect2[0] * vect2[0] + vect2[1] * vect2[1];
if ( sqDist1 < sqDist2 ) return -1;
else if ( sqDist1 > sqDist2 ) return 1;
else return 0;
};
// Convert the nodelist to an array, then returns the first item of the elements sorted by distance
return Array.prototype.slice.call( anchors ).sort( sortByDistance )[0];
};
var anchors = document.body.querySelectorAll('a[id]');
var onButtonClick = function(e) {
e.preventDefault();
var closest = findClosestAnchor( anchors );
alert( 'Closest element is : #' + closest.getAttribute( 'id' ) );
};
document.getElementsByClassName('getClosest')[0].addEventListener( 'click', onButtonClick );