Search code examples
javascripthoveroverlaymouseentermouseleave

Pure JS: display overlay over elements on hover using mouseenter and mouseleave


I wonder if there is a pure JS way to display overlays in the same fashion as google webdev tools (Elements tab) do.

I posted a year ago here a script that does the job but using jQuery, this script is somewhat buggy, now I want a pure JS script, this will follow...


Solution

  • Here is the pure JS script:

    function getElementWithDOMId(DOMId)
    {
      var allElements = document.getElementsByTagName('*');
      for (var i = 0; i < allElements.length; i++)
      {
        if (allElements[i].getAttribute('DOMId') == DOMId)
        {
            return allElements[i];
        }
      }
    }
    function offset( elem ) {
        var docElem, win,
            box = { top: 0, left: 0 },
            doc = elem && elem.ownerDocument;
    
        docElem = doc.documentElement;
    
        if ( typeof elem.getBoundingClientRect !== typeof undefined ) {
            box = elem.getBoundingClientRect();
        }
        win = getWindow( doc );
        return {
            top: box.top + win.pageYOffset - docElem.clientTop,
            left: box.left + win.pageXOffset - docElem.clientLeft
        };
    };
    
    function getWindow( elem ) {
        return isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
    }
    
    function isWindow( obj ) {
        return obj != null && obj === obj.window;
    }
    function inArray(needle, haystack) {
        var length = haystack.length;
        for(var i = 0; i < length; i++) {
            if(haystack[i] == needle) return true;
        }
        return false;
    }
    var data = [];
    function allDescendants (node, tags, nodes) {
        nodes = nodes || [];
        for (var i = 0; i < node.childNodes.length; i++) {
          var child = node.childNodes[i];
          if(inArray(node.tagName, tags) && !node.hasAttribute('DOMId')) {
            var rand = Math.floor((Math.random()*1000000)+1);
            node.setAttribute('DOMId', rand);
            elWidth = node.offsetWidth;
            elHeight = node.offsetHeight;
            elLeft = offset(node).left;
            elTop = offset(node).top;
            TagName = node.tagName;
            data.push(Array(
                rand,
                {x: elLeft,         y: elTop},
                {x: elLeft+elWidth, y: elTop},
                {x: elLeft+elWidth, y: elTop+elHeight},
                {x: elLeft,         y: elTop+elHeight},
                false,
                {w: elWidth,        h: elHeight},
                {tagName: TagName}
            ))
          }
          allDescendants(child, tags, nodes);
        }
    }
    function addOverlay(node, id) {
        console.debug('adding overlay with props width %d, height %d, left %d and top %d', node.offsetWidth, node.offsetHeight, offset(node).left, offset(node).top);
        var div = document.createElement("div");
        div.style.position = "absolute";
        div.style.width = node.offsetWidth + 'px';
        div.style.height = node.offsetHeight + 'px';
        div.style.top = offset(node).top + 'px';
        div.style.left = offset(node).left + 'px';
        div.style.background = "#9fc4e7";
        div.style.border = '2px solid black';
        div.style['-moz-opacity'] = 0.1;
        div.style.opacity = 0.1;
        div.style.filter = 'alpha(opacity=10)';
        div.setAttribute('id',id);
        document.body.appendChild(div);
    };
    allDescendants(document.getElementsByTagName('body')[0],['DIV','SPAN','H1','H2','H3','H4','TABLE','TD','TR','A','UL','LI','OL','INPUT','TEXTAREA','P','CODE','IMG', 'PRE']);
    document.addEventListener('mousemove', function(e) {
        for (i in data) {
            x = e.pageX;
            y = e.pageY;
            if((x>data[i][1].x) & (x<data[i][2].x) & (y>data[i][1].y) & (y<data[i][3].y) & (!data[i][5]))  {
                addOverlay(getElementWithDOMId(data[i][0]), data[i][0]);
                data[i][5] = true;
            } else if(((x<data[i][1].x) | (x>data[i][2].x) | (y<data[i][1].y) | (y>data[i][3].y)) & (data[i][5])) {
                document.getElementById(data[i][0]).parentNode.removeChild(document.getElementById(data[i][0]));
                data[i][5] = false;  
            }
        }
    });