Search code examples
javascriptarraysjsongoogle-visualizationjavascript-objects

Dynamic number of columns on Google Charts DataTable


Having trouble handling some JavaScript objects...

I'm generating a Google Chart based on user selections - there are two multi-select lists that create an object like this:

$('option:selected', $('#slChartSettingsEntities')).each(function () {
    var el1 = $(this);
    $('option:selected', $('#slChartSettingsStats')).each(function () {
        var el2 = $(this);
        dashParms.items.push({
            entityid: el1.val(),
            statid: el2.val(),
            entityname: el1.text(),
            statname: el2.text()
        });
    });
});

I use dashParms to create columns on the chart like this:

// preliminary stuff:

var seriesCount = 0; // this is what I'm trying to avoid

var data = new google.visualization.DataTable();
data.addColumn({ id: 'date', label: 'Date', type: 'date' });
data.addColumn({ id: result.companyName, label: result.companyName, type: 'number' });
if ($('#cbxEtc').is(':checked')) {
    data.addColumn({ id: 'ave', label: 'Company Average', type: 'number' });
    seriesCount++; // ...trying to avoid
}

// importantly:

for (var j = 0; j < dashParms.items.length; ++j) {
    data.addColumn({
        id: (dashParms.items[j].entityid + '#' + dashParms.items[j].statid),
        label: (dashParms.items[j].entityname + ' (' + dashParms.items[j].statname + ')'),
        type: 'number'
    });
    seriesCount++; // ...trying to avoid
}

I pass dashParms to the server and get back the data (a C# List<List<object>>; can show this in detail but not relevant I think) which I use to populate the rows on the chart:

var jsonResult = $.parseJSON(result.chartData);

if (seriesCount == 0) {
    $.each(jsonResult, function (k, v) {
        data.addRow([
            new Date(v[0], 0, 1),
            v[1]
        ]);
    });
}
else if (seriesCount == 1) {
    $.each(jsonResult, function (k, v) {
        data.addRow([
            new Date(v[0], 0, 1),
            v[1],
            v[2]
        ]);
    });
}
else if (seriesCount == 2) {
    $.each(jsonResult, function (k, v) {
        data.addRow([
            new Date(v[0], 0, 1),
            v[1],
            v[2],
            v[3]
        ]);
    });
}
else if (seriesCount == 3) {
    // etc etc etc
}

I do the same with the chart config object:

if (seriesCount == 0) {
    chartcfg = {
        'chartType': 'ComboChart',
        'options': {
            'seriesType': 'bars'
        }
    };
}
else if (seriesCount == 1) {
    chartcfg = {
        'chartType': 'ComboChart',
        'options': {
            'seriesType': 'bars',
            'series': {
                1: { type: 'line', tooltip: true }
            }
        }
    };
}
else if (seriesCount == 2) {
    chartcfg = {
        'chartType': 'ComboChart',
        'options': {
            'seriesType': 'bars',
            'series': {
                1: { type: 'line', tooltip: true },
                2: { type: 'line', tooltip: true }
            }
        }
    };
}
else if (seriesCount == 3) {
    // etc etc etc
}

How can I refactor and dynamically create these objects to avoid painfully else iffing all the way up to 30? I realise there are two questions here - 1) how to create the array used for data.addRow(), 2) how to create the chartcfg JSON object.


Solution

  • you can add the rows and build the series option in the same loop,
    use the value array to loop on the series.

    first, build the default config object,
    then loop on the json and value array...

    var chartcfg = {
      chartType: 'ComboChart',
      options: {
        seriesType: 'bars',
        series: {}
      }
    };
    
    $.each(jsonResult, function (k, v) {
      var row = [];
      $.each(v, function (index, value) {
        if (index === 0) {
          row.push(new Date(value, 0, 1));
        } else {
          row.push(value);
          chartcfg.options.series[index] = {
            type: 'line',
            tooltip: true
          };
        }
      });
      data.addRow(row);
    });