Advanced hit testing

The Document Object Model (DOM) in Windows Internet Explorer has supported the elementFromPoint method (introduced in the World Wide Web Consortium (W3C)'s CSSOM View Module) for some time. (Windows apps using JavaScript also support the elementFromPoint method.) The elementFromPoint method returns the element under an x- and y-coordinate in a viewport. This works well for single elements like clicking an image on a page. However, for games, graphics editors, and other applications that might use multiple layers, it’s not possible to get everything that intersects with a given point on the screen using the elementFromPoint method.

Internet Explorer 10 and Windows apps using JavaScript introduce the msElementsFromPoint and msElementsFromRect methods, which return a node list of all the elements that intersect the point at the given x- and y-coordinates or a rectangular area, respectively.

This topic contains the following sections:

  • The msElementsFromPoint method
  • The msElementsFromRect method
  • Related topics

The msElementsFromPoint method

The msElementsFromPoint method takes the x- and y-coordinates of a point and returns a node list of elements that intersect with the point. The list is sorted by z-order, with the first element as the topmost in the order.

Method Description

msElementsFromPoint(x, y)

Returns a NodeList of elements that are under a point defined by x and y.

 

The following code sample creates a series of overlapping div blocks of varying colors. When you click one, it uses the msElementsFromPoint method to get all the elements under the click position and change the background color to gray. Because all elements are returned, including body and html, we change the background color on only the elements with a nodeName of div.

<!DOCTYPE html >
<html >
<head>
    <title>Hittest example</title>
    <style type="text/css">
      button
      {
        position:absolute;
        top:600px;
        left:20px;
      }
      div
      {
        display:block;
        position:absolute;
        border:2px solid black;
        opacity:0.8;        
      }
      #div1
      {
        background-color:Red;
        left:200px;
        top:200px;
        height:200px;
        width:300px;
      }    
      #div2
      {
        background-color:Pink;
        left:150px;
        top:150px;
        height:200px;
        width:300px;
      }    
      #div3
      {
        background-color:Green;
        left:250px;
        top:250px;
        height:50px;
        width:80px;
      }
      #div4
      {
        background-color:Yellow;
        left:400px;
        top:300px;
        height:250px;
        width:250px;
      }
      #div5
      {
        background-color:Purple;
        left:275px;
        top:100px;
        height:500px;
        width:20px;
      }
      #div6
      {
        background-color:Aqua;
        left:200px;
        top:175px;
        height:50px;
        width:400px;
      }
      #div7
      {
        background-color:Fuchsia;
        left:430px;
        top:100px;
        height:375px;
        width:30px;
      }            
      #div8
      {
        background-color:Lime;
        left:175px;
        top:290px;
        height:40px;
        width:450px;
      }        
    </style>
</head>
<body>
  <h1>getElementsFromPoint test</h1>
    <button id="refresh" onclick="refresh();">Refresh</button>
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
    <div id="div4"></div> 
    <div id="div5"></div>
    <div id="div6"></div>
    <div id="div7"></div>
    <div id="div8"></div>
<script type="text/javascript">

    window.addEventListener("click", testHit, false);
    function refresh() 
    {
      window.location.reload(false);           //reload page
    }
    function testHit(e) 
    {
      if (document.msElementsFromPoint)  //feature testing
      {
        var hitTargets = document.msElementsFromPoint(e.clientX, e.clientY); 
        // get elements from point                 
        for (var i = 0; i < hitTargets.length; i++) 
        {
          if(hitTargets[i].nodeName.toUpperCase() == "DIV")
          {
            hitTargets[i].style.backgroundColor = "gray"; 
          } //if it's a div, gray it out.               
        }
      }               
    }</script>
</body>
</html>

Because msElementsFromPoint returns all elements that intersect a point, including the html element and others, the code filters for just the div element by using the nodeName property.

The msElementsFromRect method

The msElementsFromRect method accepts a top and left point and the width and height of a rectangular area and returns any elements that intersect that area.

Method Description

msElementsFromRect(left,top,width,height);

Returns a NodeList of elements that are under a rectangle defined by the left,top,width, and height parameters.

 

The previous example can be modified to use msElementsFromRect by adding a width and height parameter. For example:

function testHit(e) {
   if (Document.msElementsFromRect) //feature testing 
   {
      var hitTargets = document.msElementsFromRect(e.clientX - 25, e.clientY - 25, 50, 50); 
      // captures elements within 50px block 
      for (var i = 0; i < hitTargets.length; i++) {
         if(hitTargets[i].nodeName.toUpperCase() == "DIV") {
            hitTargets[i].style.backgroundColor = "gray"; 
            }  //if it's a div, gray it out. 
         }
      }
   }

In this update to the "testHit" function, elements that are under a 50-pixel rectangular area are returned when the mouse is clicked.

Document Object Model (DOM)

Internet Explorer 10 Guide for Developers