Mohit,
I have a solution which worked for me on a recent projet.
Basically what I did was extended the StackedBarRender3D and override the drawStackVertical method.
Looking at the cource code of StackedBarRenderer3D, the last step in the drawStackVertical method is
to draw the item labels, which makes it very easy to add an extra step in my custom class to draw a new
label.
Things to note are that the calculateLabelAnchorPoint was copied from org.jfree.chart.renderer.category.BarRenderer
as the method is a private method in the BarRender class.
The createFrontFace method contains code which was copied from the StackedBarRenderer3D class, however modified to only
calulate the path which makes up the front face of the stack.
public class CustomStackedBarRenderer3D extends StackedBarRenderer3D
{
private static final long serialVersionUID = 1L;
private boolean categoryTotal = false;
private static final int TOTAL_LABEL_OFFSET = -10;
public CustomStackedBarRenderer3D() {
super();
}
public boolean getCategoryTotal() {
return categoryTotal;
}
public void setCategoryTotal(boolean value) {
categoryTotal = value;
}
protected void drawStackVertical(List values, Comparable category,
Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot,
CategoryAxis domainAxis, ValueAxis rangeAxis,
CategoryDataset dataset) {
super.drawStackVertical(values, category, g2, state, dataArea, plot, domainAxis, rangeAxis, dataset);
if(getCategoryTotal()) {
// draw our total item label. The drawItemLabel method exists in the BarRenderer class.
ItemLabelPosition position = null;
// get the column and the last row.
int column = dataset.getColumnIndex(category);
int row = dataset.getRowCount();
// calculate the total value and convert to a
string for the label.
double total = DataUtilities.calculateColumnTotal(dataset, dataset.getColumnIndex(category));
// if the total is zero, the don't draw a label.
if(total <= 0.0d)
return;
// only show total if there are three or more values in the stack.
if(values.size() < 3)
return;
System.out.println("For the label " + Double.toString(total) + " size of values is: " + values.size() );
String label = Double.toString(total);
// get the label position.
position = getPositiveItemLabelPosition(row, column);
// calculate the bounds of the stack.
double barX0 = domainAxis.getCategoryMiddle(column,
dataset.getColumnCount(), dataArea, plot.getDomainAxisEdge())
- state.getBarWidth() / 2.0;
double barW = state.getBarWidth();
int blockCount = values.size() - 1;
Object[] prev = (Object[]) values.get(blockCount - 1);
Object[] curr = (Object[]) values.get(blockCount);
double v0 = ((Double) prev[1]).doubleValue();
double vv0 = rangeAxis.valueToJava2D(v0, dataArea,
plot.getRangeAxisEdge());
double v1 = ((Double) curr[1]).doubleValue();
double vv1 = rangeAxis.valueToJava2D(v1, dataArea,
plot.getRangeAxisEdge());
Shape frontFace = createFrontFace(barX0, barW, vv0, vv1);
// get anchor point i.e. bottom left of the label.
Point2D anchorPoint = calculateLabelAnchorPoint(
ItemLabelAnchor.OUTSIDE12, frontFace.getBounds2D(), plot.getOrientation());
anchorPoint.setLocation(anchorPoint.getX(), anchorPoint.getY() + TOTAL_LABEL_OFFSET);
// draw the label.
TextUtilities.drawRotatedString(label, g2,
(float) anchorPoint.getX(), (float) anchorPoint.getY(),
position.getTextAnchor(), position.getAngle(),
position.getRotationAnchor());
}
}
/**
* Calculates the path which makes up the front face of the stack.
* Taken from the StackedBarRenderer3D class.
*/
private Shape createFrontFace(double x0, double width, double y0, double y1) {
Point2D p00 = new Point2D.Double(x0, y0);
Point2D p01 = new Point2D.Double(x0 + width, y0);
Point2D p0 = new Point2D.Double(x0, y1);
Point2D p1 = new Point2D.Double(x0 + width, y1);
GeneralPath front = new GeneralPath();
front.moveTo((float) p0.getX(), (float) p0.getY());
front.lineTo((float) p1.getX(), (float) p1.getY());
front.lineTo((float) p01.getX(), (float) p01.getY());
front.lineTo((float) p00.getX(), (float) p00.getY());
front.closePath();
return front;
}
/**
* Calculates the item label anchor point. Taken from org.jfree.chart.renderer.category.BarRenderer
*
* @param anchor the anchor.
* @param bar the bar.
* @param orientation the plot orientation.
*
* @return The anchor point.
*/
private Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor,
Rectangle2D bar,
PlotOrientation orientation) {
Point2D result = null;
double offset = getItemLabelAnchorOffset();
double x0 = bar.getX() - offset;
double x1 = bar.getX();
double x2 = bar.getX() + offset;
double x3 = bar.getCenterX();
double x4 = bar.getMaxX() - offset;
double x5 = bar.getMaxX();
double x6 = bar.getMaxX() + offset;
double y0 = bar.getMaxY() + offset;
double y1 = bar.getMaxY();
double y2 = bar.getMaxY() - offset;
double y3 = bar.getCenterY();
double y4 = bar.getMinY() + offset;
double y5 = bar.getMinY();
double y6 = bar.getMinY() - offset;
if (anchor == ItemLabelAnchor.CENTER) {
result = new Point2D.Double(x3, y3);
}
else if (anchor == ItemLabelAnchor.INSIDE1) {
result = new Point2D.Double(x4, y4);
}
else if (anchor == ItemLabelAnchor.INSIDE2) {
result = new Point2D.Double(x4, y4);
}
else if (anchor == ItemLabelAnchor.INSIDE3) {
result = new Point2D.Double(x4, y3);
}
else if (anchor == ItemLabelAnchor.INSIDE4) {
result = new Point2D.Double(x4, y2);
}
else if (anchor == ItemLabelAnchor.INSIDE5) {
result = new Point2D.Double(x4, y2);
}
else if (anchor == ItemLabelAnchor.INSIDE6) {
result = new Point2D.Double(x3, y2);
}
else if (anchor == ItemLabelAnchor.INSIDE7) {
result = new Point2D.Double(x2, y2);
}
else if (anchor == ItemLabelAnchor.INSIDE8) {
result = new Point2D.Double(x2, y2);
}
else if (anchor == ItemLabelAnchor.INSIDE9) {
result = new Point2D.Double(x2, y3);
}
else if (anchor == ItemLabelAnchor.INSIDE10) {
result = new Point2D.Double(x2, y4);
}
else if (anchor == ItemLabelAnchor.INSIDE11) {
result = new Point2D.Double(x2, y4);
}
else if (anchor == ItemLabelAnchor.INSIDE12) {
result = new Point2D.Double(x3, y4);
}
else if (anchor == ItemLabelAnchor.OUTSIDE1) {
result = new Point2D.Double(x5, y6);
}
else if (anchor == ItemLabelAnchor.OUTSIDE2) {
result = new Point2D.Double(x6, y5);
}
else if (anchor == ItemLabelAnchor.OUTSIDE3) {
result = new Point2D.Double(x6, y3);
}
else if (anchor == ItemLabelAnchor.OUTSIDE4) {
result = new Point2D.Double(x6, y1);
}
else if (anchor == ItemLabelAnchor.OUTSIDE5) {
result = new Point2D.Double(x5, y0);
}
else if (anchor == ItemLabelAnchor.OUTSIDE6) {
result = new Point2D.Double(x3, y0);
}
else if (anchor == ItemLabelAnchor.OUTSIDE7) {
result = new Point2D.Double(x1, y0);
}
else if (anchor == ItemLabelAnchor.OUTSIDE8) {
result = new Point2D.Double(x0, y1);
}
else if (anchor == ItemLabelAnchor.OUTSIDE9) {
result = new Point2D.Double(x0, y3);
}
else if (anchor == ItemLabelAnchor.OUTSIDE10) {
result = new Point2D.Double(x0, y5);
}
else if (anchor == ItemLabelAnchor.OUTSIDE11) {
result = new Point2D.Double(x1, y6);
}
else if (anchor == ItemLabelAnchor.OUTSIDE12) {
result = new Point2D.Double(x3, y6);
}
return result;
}
}