I found a way to pinpoint which item is currently displayed. First, you will need the following redefinition, which addresses several issues with renderer parameters. It should not affect the normal histograms, but I have not 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 is a list of changes for renderer() :
- The second parameter is now mapped to the correct store item
- The fourth parameter is now the store index index instead of the internal position number (otherwise invalid IMO)
- A sixth parameter has been added that tells the current segment index in the record, not counting other properties in the record that do not 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 element in the record does not belong to its axis (this is the name of the category)
So, to answer your question, now you can use the visualization tool like this:
renderer: function(sprite, record, attr, storeIndex, store, col) { // set the color to white for the first item in every record return (col == 0)? Ext.apply(attr, { fill: '#fff' }) : attr; }
If you want to set the color for the named element, you can also do it like this:
// let say that every record looks like this: // {name: 'metric one', user1: 23, user2: 50, user3: 10} renderer: function(sprite, record, attr, storeIndex, store, col) { // retrieve the segment property name from the record using its numeric index. // remember that 'col' doesn't take into account other fields that don't // belong to the axis, so in this case we have to add 1 to the index var uid = Ext.Object.getAt(record.data, col+1)[0]; // set the color to red for 'user2' return (uid == 'user2')? Ext.apply(attr, { fill: '#f00' }) : attr; }
For this latter, you will need this function, which allows you to retrieve a property from an object using a numerical 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; }