Faster hit testing on SVG?

07/03/2020 11:48 AM

One strength of SVG in comparison to HTML Canvas is its hit testing functionality. Like HTML elements, SVG elements can make use of CSS pseudo elements like :hover or events like onmouseover or onclick. However, as more elements an SVG document contains, as less responsible it may get. I tried to figure out if it is possible to limit the time browsers spend on hit testing. And don’t forget – hit testing appears all the time you move the mouse over the screen! Even if you don’t use the power of CSS or JavaScript.

The pointer-events property

I hoped that the property pointer-events can help to speed up hit testing on SVG documents that contain hundreds or thousands of elements. pointer-events has the keywords auto, none, visiblePainted, visibleFill, visibleStroke, visible, painted, fill, stroke and all, and was introduced for a filigree control of the hit testing in SVG. I won’t explain the behavior on all keywords. I reviewed the three modes visiblePainted, visibleFill and none.

  • visiblePainted – with this keyword, the element should be the target of a pointer event, when the mouse cursor hits the fill area of the element and the fill property is not none, or the stroke area of the element and the stroke property is not none. The pointer event must not fire, when the visibility property is not set to visible.
  • visibleFill – with this keyword, the element should be the target of a pointer event, when the mouse cursor hits the fill area of the element. The pointer event must not fire, when the visibility property is not set to visible.
  • none – the element is never target of a pointer event.

From the work on WebKit, I know that we have a bunch of optimizations depending on the value of the pointer-events property. I wanted to compare the optimizations with other browsers to find a common pattern that can be used to speed up hit testing on content.

Assumptions on pointer-events

All pointer events influence, as the name says, the behavior on pointer events (hit testing) for elements. On moving objects, the exact hit testing area might not matter and the rough contour is enough.

Based on this assumption I wanted to compare the time differences on hit testing for visiblePainted and visibleFill. I also wanted to know, if disabling pointer events on “background elements” (elements that are not target of any specified pointer event) can increase the performance.

I assumed that there are noticeable performance differences between the three different values of pointer-events, if the document contains hundreds or thousands of nodes. Because strokes on SVG shapes depend on a lot of stroke properties like stroke-width, stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-dasharray and stroke-dashoffset, my assumption was that visiblePainted will take the most time, followed by visibleFill which does not include the stroke. Less time would be spend in none, since no hit testing is needed at all.

Performance measuring of different pointer-events values

To measure the performance on different pointer events, I created a test file with 10,000 individual path elements. Each element with a fill color, a stroke and the same pointer event value at the same time. I triggered the pointer events on each path element by calling document.elementFromPoint with a coordinate within each path. document.elementFromPoint returns the node that fires a pointer event on the passed coordinate.

To get more solid results, I ran each test for each pointer event eleven times, popped the first run and measured the remaining once and compared the average run times between different pointer event values.

I used the pointer event values visiblePainted, since it is the default value and contains stroke and fill, visibleFill which just includes the fill area and might be enough for moving objects and none to simulate background elements as described above.

I tested Firefox 13.0.1 FF 13, Firefox nightly 16.0a1 (2012-07-02) FF nighly, Chrome 22.0.1193.0 canary Chromium, Chrome 20.0.1132.47 Chrome, Opera 12.00 Build 1476 Opera 12 and Safari 5.1.7 (7534.57.2) Safari 5.1 on a Mac book pro late 2011. I also ran the test on IE 10.0.8400.0 pre release IE 10 pre in a VM.

You can find the test file here. Caution! The test may need several minutes for completion. The example below is a reduced version of the test. Move the mouse over the 300 path elements in the SVG canvas. The fill color of the paths will change on hovering.

Note: The testing itself always influences test results. Another way of testing might lead to slightly different results. However, the general conclusion should not change.

Results and analysis

The following diagram and table illustrates the time spend on each pointer event.

diagram of hit testing time across browsers



Results on hit testing performance.
Times in ms

Browser

visiblePainted

visibleFill

none

FF 13

1208.7

12417.3

1592.9

FF nightly

1424.4

12725

1831.9

Chrome

944

728.6

1437.8

Chromium

497.4

411

810.5

Safari 5.1

952.5

867

2342.4

Opera 12

15.9

15.6

15.5

IE 10 pre

235.9

243.3

330.8

First, the winner on the overall comparison is by far Opera! It seems that Opera does not spend to much time on hit testing at all. The differences between the three pointer event values is to small to make assumptions about the fastest pointer event here. And with ~15ms for hit testing on all 10,000 elements, there is not much need to think about performance.

It looks a bit different on other browsers. WebKit based browsers like Chrome and Safari are approximately 10% – 20% faster with visibleFill then with visiblePainted. Not much of a surprise for me.

Firefox is a lot slower on hit testing for such a number of shapes. It is in fact 100 times slower than Opera for visiblePainted and even 800 times slower on visibleFill and therefore the slowest of all tested browsers. Since visiblePainted in theory includes the same hit tests as visibleFill and even more tests for the stroke, this was the biggest surprise for me.

The results for Internet Explorer are quite similar on visibleFill and visiblePainted and both twice as good as on Chromium. But I tested IE in a virtual machine, so it might be a bit faster on a native installation of Windows, even if the results look quite reasonable in comparison with other tests in the past.

Nearly all browsers spend more time on pointer event value none than one of the other two values.

Summary

The idea of speeding up hit testing in browser with choosing a different value for pointer-events then the default value visiblePainted does not look like a good idea. On some browsers the time spend on hit testing can dramatically increase (~10 times slower on Firefox). Or it is not necessarily a big win (~10% to 20% faster on WebKit) and not worth it when it slows down other browsers. In general browsers spend more time on hit testing with the pointer even value none. Something that surprised me a lot.

Given the performance lost for Firefox on visibleFill, and the goal to let authors concentrate on the open web – not certain web browsers – the default value visiblePainted seems to still be the best choice. And at least on current browsers it does not make sense to deactivate hit testing for elements, if event handlers or CSS pseudo elements are not needed.

Comments

« Older