SVG and today's web browsers

Our intranet's homepage, like many others, features a dashboard - a bunch of key metrics designed to give users an idea of how they're doing, at a glance. In it's current guise, it's fairly limited, featuring the three latest news items, and three metrics relating to stock listings, photography and pricing.

Screen_shot_2010-06-11_at_12

In the 18 months since we re-launched our intranet, we've created loads of new applications, added tons of new features, and hooked into many new parts of the business that were previously unavailable to us. Many different brands use different systems, so we're keen to make sure that anyone, from any part of the business, is able to understand what's going on.

We're redesigning our dashboard, to feature a lot more instant at-a-glance insights into what's going on, and to show our staff, managers and directors what needs their focus. We've had lots of feedback on the gauges, with the majority liking the instant colours but finding the graphs themselves lacking something.

So given that SVG seems like the best candidate for the job, I set about creating a rough idea of what my gauge would look like using very basic shapes, colours and gradients in Adobe Illustrator:

Screen_shot_2010-06-11_at_13

Illustrator's SVG export was a little mark-up heavy, so I scrapped it, fired up TextMate and put this SVG together:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
    <defs>
        <!-- Gradients for the gauge bevel -->
        <linearGradient id="grShOuter" x1="0%" x2="100%" y1="100%" y2="0%">
            <stop offset="0" style="stop-color: #e9e9e9" />
            <stop offset="1" style="stop-color: #898989" />
        </linearGradient>
        <linearGradient id="grShInner" x1="0%" x2="100%" y1="100%" y2="0%">
            <stop offset="0"   style="stop-color: #f9f9f9" />
            <stop offset="0.4" style="stop-color: #d9d9d9" />
            <stop offset="0.5" style="stop-color: #898989" />
            <stop offset="0.6" style="stop-color: #d9d9d9" />
            <stop offset="1"   style="stop-color: #f9f9f9" />    
        </linearGradient>
    
        <!-- Gradient for the gauge background -->
        <radialGradient id="grGaugeBack" cx="50%" cy="100%" r="85%">
            <stop offset="0" style="stop-color: #666" />
            <stop offset="1" style="stop-color: #000" />
        </radialGradient>

        <!-- Gradient for the needle itself -->
        <linearGradient id="grNeedle" x1="0%" x2="100%" y1="0%" y2="0%">
            <stop offset="0"       style="stop-color: #f9f9f9" />
            <stop offset="0.4995" style="stop-color: #efefef" />
            <stop offset="0.5005" style="stop-color: #d9d9d9" />
            <stop offset="1"       style="stop-color: #cfcfcf" />
        </linearGradient>
    
        <!-- Gradients for the needle cap -->
        <linearGradient id="grCapOuter" x1="0%" x2="0%" y1="0%" y2="100%">
            <stop offset="0" style="stop-color: #292929" />
            <stop offset="1" style="stop-color: #898989" />
        </linearGradient>
        <linearGradient id="grCapInner" x1="0%" x2="0%" y1="100%" y2="0%">
            <stop offset="0" style="stop-color: #393939" />
            <stop offset="1" style="stop-color: #797979" />
        </linearGradient>
    
        <!-- Tick marks -->
        <rect id="tickMajor" x="30" y="108"  width="25"   height="4"   transform="rotate(-45,110,110)" />
        <rect id="tickMinor" x="30" y="109.25" width="12.5" height="1.5" transform="rotate(-45,110,110)" />
        <g id="tickMinorGroup">
            <use xlink:href="#tickMinor" transform="rotate( 13.5,110,110)" />
            <use xlink:href="#tickMinor" transform="rotate( 27  ,110,110)" />
            <use xlink:href="#tickMinor" transform="rotate( 40.5,110,110)" />
        </g>
        <g id="gaugeTicks">
            <use xlink:href="#tickMajor" />
            <use xlink:href="#tickMinorGroup" />
            <use xlink:href="#tickMajor"        transform="rotate( 54,110,110)" />
            <use xlink:href="#tickMinorGroup"    transform="rotate( 54,110,110)" />
            <use xlink:href="#tickMajor"         transform="rotate(108,110,110)" />
            <use xlink:href="#tickMinorGroup"    transform="rotate(108,110,110)" />
            <use xlink:href="#tickMajor"         transform="rotate(162,110,110)" />
            <use xlink:href="#tickMinorGroup"    transform="rotate(162,110,110)" />
            <use xlink:href="#tickMajor"         transform="rotate(216,110,110)" />
            <use xlink:href="#tickMinorGroup"    transform="rotate(216,110,110)" />
            <use xlink:href="#tickMajor"         transform="rotate(270,110,110)" />
        </g>
    </defs>

    <!-- The Gauge -->
    <g id="gaugeBack">
        <circle fill="url(#grShOuter)" cx="110" cy="110" r="100" />
        <circle fill="url(#grShInner)" cx="110" cy="110" r="95" />
        <circle cx="110" cy="110" r="88" />
        <circle fill="url(#grGaugeBack)" cx="110" cy="110" r="85" />
    </g>

    <!-- Tick marks -->
    <use xlink:href="#gaugeTicks" fill="#fff" opacity="0.35" />

    <g id="gaugePointer">
        <polygon id="gaugeNeedle" fill="url(#grNeedle)" points="107.5,42.5 110,40 112.5,42.5 117.5,135 110,137.5, 102.5,135" transform="rotate(-135,110,110)" />
        <circle fill="url(#grCapOuter)" cx="110" cy="110" r="15" />
        <circle fill="url(#grCapInner)" cx="110" cy="110" r="12" />
    </g>
</svg>

Those of you in the know won't be surprised by IE6, IE7 and IE8's efforts, but I was a little underwhelmed by the IE9 platform preview. There doesn't appear to be any gradient support, and when you do use them use the opacity attribute, you get very odd artefacts on the resulting image:

Svg-comparison

I was, however, very pleased with the other browser's results - there's no need to show you the individual images generated by Firefox, Safari/Chrome and Opera, as they really did look practically identical - and given that we're going to be settling on SVG for the gauges, I needed to find a solution to the IE problem.

Enter SVGWeb

SVGWeb is something I first heard about last September, but wasn't quite useful enough for us to go ahead with. Now, although it's by no means even a beta release, I've found it to be stable enough in testing to do what we need it to do - simply, render the gauge, in Internet Explorer as close as possible to the output we get on Mozilla and WebKit browsers.

All it requires is the addition of a script to your <head>...

<!--[if lte IE 8]><script src="svgweb/svg.js" data-path="svgweb"></script><![endif]-->

...and a slight change to the way in which you add your SVG markup or files to your page - instead of simply adding an <svg> tag, you add your SVG using an <object> tag - not ideal, but certainly not a show-stopper:

Et voila:

Ie6-ie8

There are some very slight differences between the native output from the higher quality browsers, mostly with regards to the opacity of the tick marks, but it's close enough that we can commit to using SVG now and, thanks to the Internet Explorer team's commitment to providing SVG compatibility in IE9, in the future.

Why not Flash or Silverlight?

This article wasn't intended to be an attack on Flash, and I don't want to start any religious wars, but I do really believe that Flash has had it's time. More and more things that we used to require things like Flash for are now easier to create and more accessible when made with open web standards such as SVG, HTML and CSS. For what we require in this particular example, using Flash or Silverlight would be overkill - in fact, I'd rather resort to using server-generated images than using plugins to create the gauges.

The obvious and highly publicised benefit of not using a plugin, of course, is that the content works on mobile devices without the Flash plugin, and given that our company is pretty much standardising on HTC Android devices, with the occasional iPhone and iPad, it means that our lovely new graphics will, to borrow a phrase, 'just work'.

More and more companies are turning away from Flash for infographics and charts - Campaign Monitor have just announced that they've switched from Flash over to the excellent HighCharts JavaScript graphing library. Given that there are excellent graphing libraries out there, I can't imagine that major applications like Google Analytics will continue using Flash for much longer either.