Polyfilling

A polyfill is a JavaScript library that replicates an API feature for the browsers that don't have it natively. Usually, a polyfill doesn't add its own API or additional features; it just adds the missing feature.

Polyfills are available for almost every HTML5 and CSS3 feature, but this doesn't mean that we can start adding libraries to provide all the modern features in the web browser. Also, the modern features can conflict with each other, so polyfills must be included carefully. To support SVG in those browsers, the following two polyfills can be used:

The first step to use a polyfill is to detect whether a feature is available in the browser or not.

Feature detection

There are several ways to find out whether the browser supports a particular feature. One of them is to get the user agent attribute of the navigator global object, but this is highly unreliable because the user can configure the user agent property. Another option is try to use the feature to check whether it has the methods and properties that we expect. However, this method is error prone and depends on the particular feature that we are looking for.

The most reliable way is to use the Modernizr library. Despite its name, it doesn't add any modern features to old browsers; it only detects the availability of the HTML5 and CSS3 features. However, it does interact well with the libraries that implement the missing features, providing a script loader to include the libraries in order to fill the gaps. The library can be customized to include the detection of only the features that we need.

The library performs a suite of tests to detect which features are available and which are not, and sets the results of these tests in the Boolean attributes of the global Modernizr object, add classes to the HTML object that explains which features are present. The library should be loaded in the header, because the features that we want to add must be available before the <body> element:

<!-- Include the feature detection library -->
<script src="/assets/js/lib/modernizr-latest.js"></script>

To detect the support of SVG in the browser, we can use the Modernizr.svg property. We can also use it to properly handle the lack of support:

<script>
    // Handle the availability of SVG.
    if (Modernizr.svg) {
        // Create a visualization with SVG.
    } else {
        // Fallback visualization.
    }
</script>

The canvg example

We will begin our example by creating an SVG image with D3. In this example, we will create an array of circles in SVG and then display them with canvas using the canvg library. We begin by including the libraries in the header as follows:

<!-- Canvg Libraries -->
<script src="/assets/js/lib/rgbcolor.js"></script>
<script src="/assets/js/lib/StackBlur.js"></script>
<script src="/assets/js/lib/canvg.js"></script>

For now, we will begin as usual by selecting the container div, appending the SVG element, and setting its width and height:

    // Set the width and height of the figure.
    var width = 600,
        height = 300;

    // Select the container div and append the SVG element.
    var containerDiv = d3.select('#canvg-demo'),
        svg = containerDiv.append('svg')
            .attr('width', width)
            .attr('height', height);

We will generate a data array with one item per circle. We want to have one circle for each 10 pixels. The position of each circle will be given by the x and y attributes. The z attribute will contain a number proportional to both x and y; this number will be used to compute the radius and color scales, as follows:

    // Generate data for the position and size of the rectangles.
    var data = [];
    for (var k = 0; k < 60; k += 1) {
        for (var j = 0; j < 30; j += 1) {
            data.push({
                x: 5 + 10 * k,
                y: 5 + 10 * j,
                z: (k - 50) + (20 - j)
            });
        }
    }

We can create the radius and color scales. Both the scales will use the extent of the z property to set their domains:

    // Create a radius scale using the z attribute.
    var rScale = d3.scale.sqrt()
        .domain(d3.extent(data, function(d) { return d.z; }))
        .range([3, 5]);

    // Create a linear color scale using the z attribute.
    var cScale = d3.scale.linear()
        .domain(d3.extent(data, function(d) { return d.z; }))
        .range(['#204a87', '#cc0000']);

We can now create the circles in the SVG element. We create a selection for the circles to be created, bind the data array, append the circles on enter, and set their attributes:

    // Select the circle elements, bind the dataset and append
    // the circles on enter.
    svg.selectAll('circle')
        .data(data)
        .enter()
        .append('circle')
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .attr('r', function(d) { return rScale(d.z); })
        .attr('fill', function(d) { return cScale(d.z); })
        .attr('fill-opacity', 0.9);

Until now, this is a standard D3. In a browser without SVG support, the elements will be created but not rendered. The canvg function interprets the SVG content and draws it with canvas instead. The function receives the canvas target (where we want SVG to be drawn), the SVG string, and an object with options. If it is called without arguments, the function will convert all the SVG elements present on the page. We will use this option as follows:

// Replace all the SVG elements by canvas drawings.
canvg();

If you inspect the page, you will see that the SVG element is gone, and in its place, there is a canvas element of the same size as the original SVG. The visual result is the same as that without using the canvg polyfill. Note that the event handlers bound to the original SVG elements won't work. For instance, if we added a callback for the click event on the circles, the callback for the event won't be invoked in the canvas version. Using canvg to render an SVG element is shown in the following screenshot:

The canvg example
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset