I found a way to detect exactly which element is currently being rendered. First, you'll need the following override, which addresses several issues with the renderer parameters. It shouldn't affect the normal bar charts, but I haven't tested them.
Ext.override(Ext.chart.series.Bar,{
drawSeries: function() {
var me = this,
chart = me.chart,
store = chart.getChartStore(),
surface = chart.surface,
animate = chart.animate,
stacked = me.stacked,
column = me.column,
enableShadows = chart.shadow,
shadowGroups = me.shadowGroups,
shadowGroupsLn = shadowGroups.length,
group = me.group,
seriesStyle = me.seriesStyle,
items, ln, i, j, baseAttrs, sprite, rendererAttributes, shadowIndex, shadowGroup,
bounds, endSeriesStyle, barAttr, attrs, anim;
// ---- start edit ----
var currentCol, currentStoreIndex;
// ---- end edit ----
if (!store || !store.getCount()) {
return;
}
//fill colors are taken from the colors array.
delete seriesStyle.fill;
endSeriesStyle = Ext.apply(seriesStyle, this.style);
me.unHighlightItem();
me.cleanHighlights();
me.getPaths();
bounds = me.bounds;
items = me.items;
baseAttrs = column ? {
y: bounds.zero,
height: 0
} : {
x: bounds.zero,
width: 0
};
ln = items.length;
// Create new or reuse sprites and animate/display
for (i = 0; i < ln; i++) {
sprite = group.getAt(i);
barAttr = items[i].attr;
if (enableShadows) {
items[i].shadows = me.renderShadows(i, barAttr, baseAttrs, bounds);
}
// ---- start edit ----
if (stacked && items[i].storeItem.index != currentStoreIndex) {
//console.log("i: %o, barsLen: %o, j: %o, items[i]: %o",i,bounds.barsLen,i / bounds.barsLen,items[i]);
currentStoreIndex = items[i].storeItem.index;
currentCol = 0;
}
else {
++currentCol;
}
// ---- end edit ----
// Create a new sprite if needed (no height)
if (!sprite) {
attrs = Ext.apply({}, baseAttrs, barAttr);
attrs = Ext.apply(attrs, endSeriesStyle || {});
sprite = surface.add(Ext.apply({}, {
type: 'rect',
group: group
}, attrs));
}
if (animate) {
// ---- start edit ----
rendererAttributes = me.renderer(sprite, items[i].storeItem, barAttr, (stacked? currentStoreIndex : i), store, (stacked? currentCol : undefined));
// ---- end edit ----
sprite._to = rendererAttributes;
anim = me.onAnimate(sprite, { to: Ext.apply(rendererAttributes, endSeriesStyle) });
if (enableShadows && stacked && (i % bounds.barsLen === 0)) {
j = i / bounds.barsLen;
for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
anim.on('afteranimate', function() {
this.show(true);
}, shadowGroups[shadowIndex].getAt(j));
}
}
}
else {
// ---- start edit ----
rendererAttributes = me.renderer(sprite, items[i].storeItem, Ext.apply(barAttr, { hidden: false }), (stacked? currentStoreIndex : i), store, (stacked? currentCol : undefined));
// ---- end edit ----
sprite.setAttributes(Ext.apply(rendererAttributes, endSeriesStyle), true);
}
items[i].sprite = sprite;
}
// Hide unused sprites
ln = group.getCount();
for (j = i; j < ln; j++) {
group.getAt(j).hide(true);
}
// Hide unused shadows
if (enableShadows) {
for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
shadowGroup = shadowGroups[shadowIndex];
ln = shadowGroup.getCount();
for (j = i; j < ln; j++) {
shadowGroup.getAt(j).hide(true);
}
}
}
me.renderLabels();
}
});
Here's the change list for renderer()
:
- The second parameter is now mapped to the correct store item
- The fourth parameter is now the store index number instead of the internal item number (worthless otherwise IMO)
- Added a sixth parameter that tells the current segment index within the record, not counting other properties in the record that don't belong to the axis.
Example: for a record that looks like {name: 'metric': segment1: 12, segment2: 22}
, the index for segment1
will be 0
instead of 1
, because the first item in the record does not belong to its axis (it's the category name)
So, to answer your question, now you can use the renderer like so:
renderer: function(sprite, record, attr, storeIndex, store, col) {
return (col == 0)? Ext.apply(attr, { fill: '#fff' }) : attr;
}
If you want to set the color for a named item, you may also do it like this:
renderer: function(sprite, record, attr, storeIndex, store, col) {
var uid = Ext.Object.getAt(record.data, col+1)[0];
return (uid == 'user2')? Ext.apply(attr, { fill: '#f00' }) : attr;
}
For that last one, you'll need this function, which allows you to retrieve a property from an object using a numeric index:
Ext.Object.getAt = function(obj, idx) {
var keys = Ext.Object.getKeys(obj);
if (idx < keys.length) {
return [keys[idx],obj[keys[idx]]];
}
return null;
}