HTML5 Data and Services Cookbook
上QQ阅读APP看书,第一时间看更新

Displaying combined charts

Combined charts are charts that have more than one x or y axis, and may have multiple types of series (lines, bars, and areas). Sometimes, we may want to present multiple heterogeneous types of data on a single chart, usually to visualize its correlation.

In this recipe, we're going to try and visualize a mountain hike by presenting both temperature and altitude on a single chart. The altitude series will be an area chart with gradient colors reminiscent of relief maps, but the temperature series will be a line chart, which we would like to be red if above 19 degrees Celsius and blue if below that.

In order to do this, we're going to need a charting library that can handle two y axes. We're going to use the Flot charting library because it is capable of displaying charts with two or more x or y axes.

Getting ready

Like in the previous recipes, we need to download Flot from the official website at http://www.flotcharts.org/ and extract the contents to a separate folder named flot.

How to do it...

Let's write the HTML and JavaScript code.

  1. Our HTML file needs a chart placeholder, jQuery, Flot, and our example script. This time we're also going to need the threshold plugin in order to have two temperature colors. The following is the content:
    <!DOCTYPE HTML>
    <html>
        <head>
            <title>Chart example</title>
            <style type="text/css">
                #chart { font-family: Verdana; }
            </style>
        </head>
        <body>
            <div id="chart" style="height:200px; width:800px;"></div>
            <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
            <script src="flot/jquery.flot.js"></script>
            <script src="flot/jquery.flot.threshold.js"></script>
            <script type="text/javascript" src="example.js"></script>
        </body>
    </html>
  2. Our chart is drawn in example.js using the following code:
    $(function() {    
        function getData(cb) {
            var altitudes = [], temperatures = [];
            // Generate random but convincing-looking data.
            for (var k = 0; k < 20; k += 0.5) {
                altitudes.push([k, Math.random()*50 + 1000*Math.pow((k-15)/15,2)]);
                temperatures.push([k, Math.random()*0.5 + k/4 + 15]);
            }
            cb({alt:altitudes, temp:temperatures});
        }
    
        getData(function(data) {
            $.plot("#chart", [
               {
                 data: data.alt, yaxis:1,
                 lines: {fill:true, fillColor: {
                 colors: ["#393", "#990", "#cc7", "#eee"] } }
                    },
               {
                 data: data.temp, yaxis:2, color: "rgb(200, 20, 30)",
                 threshold: { below: 19, color: "rgb(20, 100, 200)" }
                    }
                ], {
                yaxes: [ { }, { position: "right"}],
                xaxis: {
                    tickFormatter: function(km) { return km + ' km'; }
                },
                grid: {
                    markings: [{ xaxis: { from: 0, to: 8 }, color: "#eef" }]
                }
            });
        });
    });

The following screenshot shows the end result:

How it works...

With the getData function, we generate two series for the plot, one containing temperature and the other containing altitude.

When drawing the plot, we call the getData function first. In the provided callback, we take the data and pass it to the $.plot function, which takes the target container element, an array of series, and plot options.

The first series in the array contains altitude data. We have two y axes so we need to declare the y axis we're going to use for this series—the first y axis. The rest of the parameters declare the fill gradient; for more information see the Creating an area chart recipe.

The second series uses the second y axis. What is new here is the threshold property. It specifies that for values below 19 degrees, the color of the line should be different (blue rather than red).

We're going to configure the second y axis in the options object by specifying the yaxes property (note the plural in the name). This property is an array containing y axis options. We're going to use the defaults for the first axis, hence the empty object. We will place the second axis on the right-hand side.

The unit of the x axis is kilometers and therefore our tickformatter function adds the string " km" to the number.

Finally, we mark the "mountain part" (from 0 to 8 km) in blue with the grid markings option.

There's more...

Here is a simple Ajax replacement of the getData function, sending an Ajax request to a request handler hosted on the same domain at the /charts path to retrieve the chart data. This handler should return an object in the following format:

{alt: data1, temp: data2}

Where data1 and data2 are two-dimensional arrays containing the data.

function getData(cb) {
    $.get('/charts').success(cb);
}