Hit-testing SVG shapes?

The SVG 1.1 DOM has just the right method (unfortunately it's not yet implemented in mozilla):

var nodelist = svgroot.getIntersectionList(hitrect, null);

For a full working example see here.


I don't know of any way of intersecting a whole rectangle. But you can intersect a point, so you could build a more complicated check out of that:

var el= document.elementFromPoint(x, y);

will give you the highest-stacked element at a particular page-relative co-ordinate. You'll get the <svg> element if no shapes inside the SVG are hit.

This is a non-standard Mozilla extension, but it works on WebKit as well. Unfortunately, though it exists in Opera, it won't look inside <svg>, so on that browser the element will always be the SVGSVGElement.


Chrome's version of checkIntersection (and getIntersectionList) tests the element bounding boxes, rather than the elements themselves. I was able to write my own checkIntersection which works on chrome by using a canvas with this fairly involved approach which seems to work well for small rectangles and will be slow for large ones, so it's nice for hit testing. This technique will work as a polyfill for checkIntersection in Chrome, for small rectangles and possibly other browsers that have broken implementations of checkIntersection.

  1. Create an image that uses a data URI containing your SVG's outerHTML (you may need to include style rules in it as well), like so (this image doesn't have to be in the page). You can use an onload event handler to determine when it's loaded if you need to.
  2. Create a canvas to use for your hit-test rectangle (this canvas doesn't need to be in the page)

To test if a rectangle intersects with any of your shapes, do this:

  1. Make sure the canvas is the same size as your rectangle (set its width and height)
  2. Clear the canvas using the canvas context clearRect() method
  3. Draw the SVG on the canvas at -x, -y so that the portion of the image that overlaps the canvas corresponds to the area you want to test using drawImage()
  4. Fetch the canvas's ImageData using the context's getImageData(). Every 4th element of the data array is the alpha byte and a nonzero value means part of your SVG overlaps the rectangle. If all of the 4th bytes are 0, then your SVG did not intersect the rectangle.