Tuesday, May 28, 2013

SVG Navigable Viewport Part 2: Some Cross-Browser Support

So last time I presented a basic SVG viewport navigation strategy. I tested it in Chrome and it worked a treat. However, when I decided to test in the other browsers at my disposal (FF20, IE10), the nasty head of cross-platform incompatibility popped up in the strangest ways possible. I managed to add custom handlers for Firefox, but I didn't have time to look at IE10 or other browsers.

This time I'm going to try to figure out what gotcha's I have to solve to get IE10 working, seeing that it is currently the second most used browser. I would test Safari, but unfortunately the latest version is simply unavailable for me to test. I might try testing on Opera as well if I have time.

Problem 1: SVG Root Overflow Default Value

The W3C SVG standard specifies that a root SVG element an initial overflow value of visible, BUT a user agent stylesheet is allowed to modify this. Chrome and Firefox both do this and thus the "default" value is hidden, while IE10 does not so the initial value of visible is used. So the default value is not necessarily required to be consistent! This is discussed in the W3C mailing list.

The best way to ensure proper behavior of any property is to just manually specify it's value.

<svg id='svg_base' overflow='hidden' width='512' height='512'>


IE10 Wheel Handler

At this point, I have managed to get IE10 to display and pan the viewport correctly. However, zooming was still a problem (who could have guessed).

So I did a little digging and found that IE10 uses the MouseWheelEvent DOM interface, which only provides a single delta attribute which captures y-axis rotations. Chrome uses the WheelEvent DOM Interface, which provides deltaX, deltaY, and deltaZ so scrolling in any coordinate can be handled. WheelEvent is the current standard, and MouseWheelEvent is the old deprecated DOM interface. Actually, Chrome is not completely fault free because the standard specifies the attribute name should be delta{N}, where {N} is the axis, and Chrome uses wheelDelta{N}. As discussed last time, Firefox has their own "special" way for getting wheel events that I won't even go into. The fix is fairly straightforward, though not pretty at all:

if(e.deltaY !== undefined)
{
// standard
var zoomFactor = Math.pow(1.1, e.deltaY / 56);
}
else if(e.wheelDeltaY !== undefined)
{
// Chrome
var zoomFactor = Math.pow(1.1, e.wheelDeltaY / 56);
}
else if(e.wheelDelta !== undefined)
{
// IE and MouseWheelEvent
var zoomFactor = Math.pow(1.1, e.wheelDelta / 56);
}
else
{
// err... just disable zooming with mouse wheel
var zoomFactor = 1;
}


Conclusion

And there we go! A full working version in Chrom, Firefox, and IE10. There are still bits which aren't quite the same in IE10, for example I don't know a way to simulate the Vector-Effects I'm using to make the rectangles stroke width doesn't change when zooming, but it's close enough for most cases. This just highlights a small portion of the problem with client-side Web Development. As an interesting note, I tested the original viewport navigation code in Opera 12.15, and it works perfectly fine. As stated before, I have no way to test this in the latest version of Safari, and I do not have the resources to test nearly all mobile browsers.

Here's a live demo of the fixed code: