SVG:Pointer-events
The SVG specification introduced the 'pointer-events' property to provide SVG authors with more control over when and which parts of an element can be the target of a pointer event. This document discusses 'pointer-events', and how it might work in HTML (HTML authors have been asking for 'pointer-events' like functionality since forever).
pointer-events in SVG 1.1
The pointer-events property determines which areas of an element can intercept a pointer event, and under what conditions. The following table summarizes the SVG 1.1 values.
value areas hit and conditions for a hit
----- ----------------------------------
auto /* like 'visiblePainted', like 'none' on outer-<svg> */
visiblePainted fill if(fill:!none), stroke if(stroke:!none),
requires(visibility:visible)
painted fill if(fill:!none), stroke if(stroke:!none)
visible *, requires(visibility:visible)
visibleFill fill, requires(visibility:visible)
visibleStroke stroke, requires(visibility:visible)
fill fill
stroke stroke
all *
none -
The syntax of the lines in the column on the right might seem like they could be alternative values for pointer-events that users could use. However, they're pretty verbose, and its not clear that authors want a lot of granularity.
Use cases
Please only append to this list so that we have consistent numbering so we can refer to cases by number.
- Provide a way to allow pointer events to go "through" an element even when it's visible to the user.
- Provide a way to allow pointer events to go "through" areas of an element that are transparent, clipped/masked out, or otherwise not visible to users/viewers, while allowing pointer events to be "caught" by parts of the element that are visible to users.
- Provide a way to allow pointer events to be "caught" by an element even when it is invisible to the user.
Should clipping affect pointer event targeting?
One of the long running debates in the SVG WG and on www-svg is whether clipping and masking should affect pointer event targeting (hit testing). Current (2010) implementations do not take masking into account for hit testing, but Mozilla and Opera do take clipping into account, whereas Webkit and Batik do not. My (jwatt's) personal opinion is that it's most intuitive for authors to have both clipping and masking affect hit testing by default. In fact I think it would be best for the principle to be that the default behavior is: "if an element affects a given pixel, then a pointer event occurring at that pixel may target the element, but if the element does not affect the pixel, then the pointer event will not target the element."
Text should be a special case, by default. In the typical case where text is displayed at normal reading size, when a user wishes to click on it to activate a link, or perhaps to select it, it would be unexpected and annoying for the pointer event to go "through" and target whatever is underneath if the click happened to be between two letters, or in the inside of an "o", say. For text, having the character cell respond to pointer events is a better default.
The current property values suck
The current values for 'pointer-events' suck - especially for HTML. Quite apart from the fact that they use the SVG specific terms "fill" and "stroke" in their names, they're confusing, and even authors that have been using SVG for a long time frequently have to refer back to the spec to figure out which value they need to use. For example:
- What's the difference between 'visiblePainted', 'visible', 'painted' and 'all'? (Note that none of these tell you if the element in question actually affects the pixel that was clicked.)
- Does the value of the 'fill' property matter for the 'painted' and 'fill' properties? (Yes and no respectively.)
- ...
Proposed values
'none', 'painted' and 'all'.
In SVG it may make sense to be able to have separate treatment for fill and stroke. In that case maybe the values 'all', 'fill', 'stroke' and 'painted', 'paintedFill', 'paintedStroke' would make sense. The former three would ignore opacity and visibility, the latter three would not. In fact, for these extra names to make a little more sense in CSS box model contexts such as HTML where you have 'background' and 'border' instead of 'fill' and 'stroke', the names could be 'all', 'perimeter', 'interior', and 'painted', 'paintedPerimeter', 'paintedInterior'.
To merge...
The current specification makes the value of the 'visibility' property special, but for some strange reason ignores the effects of opacity. As a result the 'visible' in value names such as 'visiblePainted' is nothing to do with whether something visible is actually painted, but rather to do with whether the 'visibility' property is set to 'visible' or not. The 'fill-opacity', 'stroke-opacity' or 'opacity', or the 'fill' or 'stroke' properties with rgba()/hsla() values that set opacity to zero, could all prevent any paint from being output, but as far as 'visiblePainted' et. al. are concerned, it's visible and painted if 'visibility' is set to 'visible'. Perhaps these values could be fixed to take account of opacity?
In fact 'visibleFill', 'visibleStroke' and 'visible' don't care about the values of 'fill' or 'stroke', even if they are 'none'.
Another source of confusion is the difference between 'visiblePainted', 'visible', 'painted' and 'all'. For all four the geometry is the combined stroke and fill geometry. The difference is in whether the 'fill' and 'stroke' properties are set to 'none' or not ('visiblePainted' and 'painted' do not allow them to be 'none', but 'visible' and 'all' do). Why do we even need a distinction between non-painting due to the value of 'visibility' vs 'fill'/'stroke'? Why don't we also have 'paintedFill', 'paintedStroke' and 'paintedAll' values then???
The 'visible' value should really have been 'visibleAll' for consistency. Maybe it seemed easier to remember, but the inconsistency it brings to the naming makes it harder to remember how everything works as a whole.
What about when 'fill' or 'stroke' references a gradient or pattern that is fully transparent/empty (or has large areas that are)? I think it would be fine to always treat paint server references as fully opaque paint. The utility behind 'painter-events' is to