Reputation: 2837
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:
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
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