I think this is better than the default behavior of JFreeChart, which is creating the Legends and put them all together on screen.
Take a look at the picture.
http://picasaweb.google.com.br/ricardo. ... 5334564226
Code: Select all
package br.com.crmsoft.finstock.chart.plot;
import static br.com.crmsoft.finstock.Constantes.FONT_LEGEND_TITLE;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisSpace;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockParams;
import org.jfree.chart.block.LengthConstraintType;
import org.jfree.chart.block.LineBorder;
import org.jfree.chart.block.RectangleConstraint;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.PlotState;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.Title;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.Size2D;
import org.jfree.ui.VerticalAlignment;
/**
* <p>Classe que herda todas as caracteristicas do XYPlot e permite que seja incluído uma legenda para cada Plot, ao invés
* de uma para o {@link JFreeChart}. Com esta melhoria é possível utilizar com o {@link CombinedDomainXYPlot} e ter a separação
* dos plots pela legenda.</p>
*
* @author Celso Ricardo - CRMSoft Projetos e Consultoria
* @version $Id$
*/
public class FinStockXYPlot extends XYPlot {
private static final long serialVersionUID = 826606319967789395L;
/**
* The chart innerSubtitles (zero, one or many). This field should never be <code>null</code>.
*/
protected LegendTitle legendTitle;
protected boolean legendTitleVisible = true;
public FinStockXYPlot() {
super();
}
public FinStockXYPlot(XYDataset dataset, ValueAxis domainAxis, ValueAxis rangeAxis, XYItemRenderer renderer) {
this(dataset, domainAxis, rangeAxis, renderer, true);
}
public FinStockXYPlot(XYDataset dataset, ValueAxis domainAxis, ValueAxis rangeAxis, XYItemRenderer renderer, boolean legendTitleVisible) {
super(dataset, domainAxis, rangeAxis, renderer);
this.legendTitleVisible = legendTitleVisible;
this.legendTitle = new LegendTitle(this);
this.legendTitle.setItemFont(FONT_LEGEND_TITLE);
this.legendTitle.setHorizontalAlignment(HorizontalAlignment.LEFT);
this.legendTitle.setPosition(RectangleEdge.TOP);
this.legendTitle.setMargin(new RectangleInsets(1.0, 0, 1.0, 0));
this.legendTitle.setFrame(new LineBorder(Color.GRAY, new BasicStroke(1.0f), new RectangleInsets()));
this.legendTitle.setBackgroundPaint(Color.white);
this.setLegendTitle(this.legendTitle);
}
public void setLegendTitle(LegendTitle legendTitle) {
this.legendTitle = legendTitle;
}
public boolean isLegendTitleVisible() {
return legendTitleVisible;
}
public void setLegendTitleVisible(boolean legendTitleVisible) {
this.legendTitleVisible = legendTitleVisible;
this.fireChangeEvent();
}
@Override
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
// Desenhando legenda
AxisSpace space = new AxisSpace();
space = calculateRangeAxisSpace(g2, area, space);
if (this.isLegendTitleVisible() && this.legendTitle != null) {
if (this.legendTitle.isVisible()) {
this.drawTitle(this.legendTitle, g2, area, space);
}
}
// Desenhando o plot
super.draw(g2, area, anchor, parentState, info);
}
/**
* Draws a title. The title should be drawn at the top, bottom, left or right of the specified area, and the area should be
* updated to reflect the amount of space used by the title.
*
* @param t
* the title (<code>null</code> not permitted).
* @param g2
* the graphics device (<code>null</code> not permitted).
* @param area
* the chart area, excluding any existing titles (<code>null</code> not permitted).
* @param space
*/
protected void drawTitle(Title t, Graphics2D g2, Rectangle2D area, AxisSpace space) {
if (t == null) {
throw new IllegalArgumentException("Null 't' argument.");
}
if (area == null) {
throw new IllegalArgumentException("Null 'area' argument.");
}
Rectangle2D titleArea = new Rectangle2D.Double();
RectangleEdge position = t.getPosition();
double ww = area.getWidth();
if (ww <= 0.0) {
return;
}
double hh = area.getHeight();
if (hh <= 0.0) {
return;
}
RectangleConstraint constraint = new RectangleConstraint(ww, new Range(0.0, ww), LengthConstraintType.RANGE, hh,
new Range(0.0, hh), LengthConstraintType.RANGE);
BlockParams p = new BlockParams();
if (position == RectangleEdge.TOP) {
Size2D size = t.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, area, space, t.getHorizontalAlignment(), VerticalAlignment.TOP);
t.draw(g2, titleArea, p);
area.setRect(area.getX(), Math.min(area.getY() + size.height, area.getMaxY()), area.getWidth(), Math.max(area
.getHeight()
- size.height, 0));
} else if (position == RectangleEdge.BOTTOM) {
Size2D size = t.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, area, space, t.getHorizontalAlignment(), VerticalAlignment.BOTTOM);
t.draw(g2, titleArea, p);
area.setRect(area.getX(), area.getY(), area.getWidth(), area.getHeight() - size.height);
} else if (position == RectangleEdge.RIGHT) {
Size2D size = t.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, area, space, HorizontalAlignment.RIGHT, t.getVerticalAlignment());
t.draw(g2, titleArea, p);
area.setRect(area.getX(), area.getY(), area.getWidth() - size.width, area.getHeight());
}
else if (position == RectangleEdge.LEFT) {
Size2D size = t.arrange(g2, constraint);
titleArea = createAlignedRectangle2D(size, area, space, HorizontalAlignment.LEFT, t.getVerticalAlignment());
t.draw(g2, titleArea, p);
area.setRect(area.getX() + size.width, area.getY(), area.getWidth() - size.width, area.getHeight());
} else {
throw new RuntimeException("Unrecognised title position.");
}
}
/**
* Creates a rectangle that is aligned to the frame.
*
* @param dimensions
* the dimensions for the rectangle.
* @param frame
* the frame to align to.
* @param space
* @param hAlign
* the horizontal alignment.
* @param vAlign
* the vertical alignment.
*
* @return A rectangle.
*/
private Rectangle2D createAlignedRectangle2D(Size2D dimensions, Rectangle2D frame, AxisSpace space, HorizontalAlignment hAlign,
VerticalAlignment vAlign) {
double x = Double.NaN;
double y = Double.NaN;
if (hAlign == HorizontalAlignment.LEFT) {
x = frame.getX();
} else if (hAlign == HorizontalAlignment.CENTER) {
x = frame.getCenterX() - (dimensions.width / 2.0);
} else if (hAlign == HorizontalAlignment.RIGHT) {
x = frame.getMaxX() - dimensions.width;
}
if (vAlign == VerticalAlignment.TOP) {
y = frame.getY();
} else if (vAlign == VerticalAlignment.CENTER) {
y = frame.getCenterY() - (dimensions.height / 2.0);
} else if (vAlign == VerticalAlignment.BOTTOM) {
y = frame.getMaxY() - dimensions.height;
}
return new Rectangle2D.Double(x + space.getLeft(), y, frame.getWidth() - space.getLeft() - space.getRight(), dimensions.height);
}
}