deathlock
deathlock

Reputation: 2837

(amCharts) I have a chart which data has two different prefixes. Any way to tell the function which data has which prefix?

I have an amChart chart which data is taken from two tables below it (code is modified from this SO answer). Every row the category in each tables begins with different prefix: first table begins with (Sales) and second table begins with (Market).

Here is my code for better illustration: http://jsfiddle.net/uoxbm2d3/2/

Since there are two tables and it's a column/bar chart, I need the columns/bars to be stacked based on from which table or what prefix they have. So (Sales) will only be stacked with (Sales) or, in other words, data from Table 1 will only be stacked with Table 1. Same goes with (Market)/Table 2 that will only be stacked with its siblings. Something like this:

Sorry for the terrible editing, but you get the idea

The green/yellow/orange color is from Table 1 (Sales); the blue/purple color is from Table 2 (Market).

Is there any way to tell the function which graph comes from which table? Or at least to tell the function which data has which prefix?

Here is a piece of the script

    function generateGraphsFromData(chart, chartData) {
    //get the chart graph value fields as lookup table with a seen property set to false by default
    //this will be used to determine what graphs need to be removed when looking at the data
    var graphValueFields = chart.graphs.reduce(function(valueFields, graph) {
        valueFields[graph.valueField] = 0;
        return valueFields;
    }, {});

    var removeValueFields = [];

    //create an array of new graph value fields by filtering out the categoryField
    //and the currently known valueFields. 
    var newGraphValueFields = [];

    Object.keys(chartData[0]).filter(function(key) {
        return key != chart.categoryField;
    }).forEach(function(valueField) {
        //if this is a new graph, add it to the list
        if (graphValueFields[valueField] === undefined) {
            newGraphValueFields.push(valueField);
        } else {
            //otherwise, set the seen flag to 1
            graphValueFields[valueField] = 1;
        }
    });

    //for each new value field left over, create a graph object and add to the chart.
    newGraphValueFields.forEach(function(valueField) {
        var graph = new AmCharts.AmGraph();
        graph.title = valueField;
        graph.valueField = valueField;
        graph.balloonText = "<strong>[[title]]</strong><br /> Rp[[value]]";
        graph.id = valueField; //use the valueField as the ID for ease of removal
        graph.type = 'column';
        graph.lineAlpha = 0;
        graph.fillAlphas = 0.5;
        graph.bullet = "none";
        graph.stackable = true; // disable stacking
        chart.addGraph(graph);
    });

    //loop through the graphValueFields lookup table and remove all graphs that were not seen when
    //rescanning the data
    Object.keys(graphValueFields).forEach(function(removeGraphValueField) {
        if (graphValueFields[removeGraphValueField] === 0) {
            chart.removeGraph(chart.getGraphById(removeGraphValueField));
        }
    })
    }

Upvotes: 0

Views: 398

Answers (1)

xorspark
xorspark

Reputation: 16012

Once you add your new graphs and remove any old ones, you can sort by title then loop through them again to find the first non-matching prefix and set the graph's newStack property to true while setting it to false in the rest of the graphs. For example:

  chart.graphs.sort(function(lhs, rhs) {
    //sort by title, ensures that the sales (first table) data comes first
    var lhsSalesIdx = lhs.title.indexOf('(Sales)');
    var rhsSalesIdx = rhs.title.indexOf('(Sales)');

    if (lhsSalesIdx !== -1 && rhsSalesIdx === -1) {
      return -1;
    }
    else if (lhsSalesIdx === -1 && rhsSalesIdx !== -1) {
      return 1;
    }
    else {
        return lhs.title.localeCompare(rhs.title);
    }
  });
  var stackSet = false;
  //find the first instance of the market row graph and set its newStack property to true
  //while clearing out the others
    for (var i = 0; i < chart.graphs.length; ++i) {
    if (!stackSet && chart.graphs[i].title.indexOf('(Sales)') === -1) {
        chart.graphs[i].newStack = true;
        stackSet = true;
    }
    else {
      chart.graphs[i].newStack = false;
    }     
  }

Updated fiddle - note that I set stackable back to true in your new graph loop for this to work as well.

Upvotes: 1

Related Questions