简体   繁体   中英

Find html element nearest to position (relative or absolute)

Given absolute or relative position (top & left) is there any way to get the nearest html element to these co-ordinates?

Or alternately, is there any way to craft a selector (or use some jQuery construct) to enumerate elements and then find which is closes to the provided co-ordinates? Assume that the set of elements is small and finite.

I've built a jQuery method that returns closest element to offset, within the collection:

jQuery.fn.closestToOffset = function(offset) {
    var el = null,
        elOffset,
        x = offset.left,
        y = offset.top,
        distance,
        dx,
        dy,
        minDistance;
    this.each(function() {
        var $t = $(this);
        elOffset = $t.offset();
        right = elOffset.left + $t.width();
        bottom = elOffset.top + $t.height();

        if (
            x >= elOffset.left &&
            x <= right &&
            y >= elOffset.top &&
            y <= bottom
        ) {
            el = $t;
            return false;
        }

        var offsets = [
            [elOffset.left, elOffset.top],
            [right, elOffset.top],
            [elOffset.left, bottom],
            [right, bottom],
        ];
        for (var off in offsets) {
            dx = offsets[off][0] - x;
            dy = offsets[off][1] - y;
            distance = Math.sqrt(dx * dx + dy * dy);
            if (minDistance === undefined || distance < minDistance) {
                minDistance = distance;
                el = $t;
            }
        }
    });
    return el;
};

Notes:

  1. If the offset is inside one of the elements, it will be returned.
  2. I'm looping through four offsets, because this gives the best accuracy.

Use it like this:

$('div.myCollection').closestToOffset({left: 5, top: 5});

Fixed the bugs to the previous answer (also cleaned up to ES6):

const getClosestElement = (x, y) => {
  const elements = $('body *');
  let closestEl = elements.eq(0); //initialize to first element
  let offset = closestEl.offset();
  offset.left += closestEl.outerWidth() / 2; // center of object
  offset.top += closestEl.outerHeight() / 2; // middle of object
  let minDist = Math.sqrt((offset.left - x) * (offset.left - x) + (offset.top - y) * (offset.top - y));

  elements.each((i) => {
    const el = elements.eq(i);
    offset = el.offset();
    offset.left += el.outerWidth() / 2; // center of object
    offset.top += el.outerHeight() / 2; // middle of object
    const dist = Math.sqrt((offset.left - x) * (offset.left - x) + (offset.top - y) * (offset.top - y));
    if (dist < minDist) {
      minDist = dist;
      closestEl = el;
    }
  });

  return closestEl;
};

The best way I can think of to do this would be to have a search function loop that loops through all your existing elements and compares the co-ordinates, keeping a copy of the nearest variable all the time.

Thats the way I can think of doing this, and what I would do if I was under your constraints.

I used @Felix answer and applied it to vanilla Js for my requirements, I know it's an old question but if anyone needs it

function getClosestChoice(x, y, elements) {
  let closestEl,
    minDist,
    offset;

  elements.forEach((el) => {
    offset = { left: el.offsetLeft, top: el.offsetTop };
    offset.left += el.offsetWidth / 2;
    offset.top += el.offsetHeight / 2;
    const dist = Math.sqrt(
      (offset.left - x) * (offset.left - x) + (offset.top - y) * (offset.top - y)
    );
    if (!minDist || dist < minDist) {
      minDist = dist;
      closestEl = el;
    }
  });
  return closestEl;
}

Or try the original jQuery function offsetparent() . From this page comes the next example:

$( "li.item-a" ).offsetParent().css( "background-color", "red" );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM