Labeling columns on Google API ComboChart

by augustomen

HTML

<script src="http://www.google.com/jsapi?fake=.js"></script>
<div id="mychart" style="width: 600px; height: 400px"></div>

JavaScript

function drawVisualization() {
    // just a normal ComboChart setup
    var data = google.visualization.arrayToDataTable([
        ['Month', 'Value', 'Cancelled'],
        ['Jan/2013', 0.872, 0.02],
        ['Feb/2013', 0.921, 0.03],
        ['Mar/2013', 0.946, 0.06],
        ['Apr/2013', 0.780, 0.01],
        ['May/2013', 0.819, 0.11],
        ['Jun/2013', 0.697, 0.06],
        ['Jul/2013', 0.717, 0.01],
        ['Aug/2013', null, null],
        ['Sep/2013', null, null],
        ['Oct/2013', null, null],
        ['Nov/2013', null, null],
        ['Dec/2013', null, null]
    ]);
    var formatter = new google.visualization.NumberFormat({ pattern:'#.#%' });
    formatter.format(data, 1);
    formatter.format(data, 2);

    mydiv = $("#mychart");
    chart = new google.visualization.ComboChart(mydiv[0]);
    chart.draw(data, {
        width: 600, height: 400, seriesType: 'bars',
        legend: {position: "bottom"},
        vAxis: {format: "#.#%"},
        chartArea: {left: 60, top: 30, width: 540},
        focusTarget: 'category',
        series: {1: {type: "line"}}
    });    
    
    /* Here comes the hack!
    We're going to add a svg text element to each column bar.
    This code will work for this data setup only. If you add/remove a series, this code must be adapted
    */    
    rects = mydiv.find('svg > g > g > g > rect');
    var row = 0;
    for (i = 0; i < rects.length; i++) {
        // this selector also retrieves gridlines
        // we're excluding them by height
        el = $(rects[i]);
        if (parseFloat(el.attr("height")) <= 2) { continue; }
        aparent = el.parent();
        do { // skips 'null' values
            text = data.getValue(row++, 1);
        } while (text == null && row < data.getNumberOfRows());
        
        if (text) {
            text = formatter.formatValue(text);
            // see below
            pos = getElementPos(el);
            attrs = {x: pos.x + pos.width / 2, y: pos.y - 2,
                     fill:...