?? pieplot.java
字號:
public void setURLGenerator(PieURLGenerator generator) {
this.urlGenerator = generator;
}
/**
* Draws the plot on a Java 2D graphics device (such as the screen or a printer).
*
* @param g2 the graphics device.
* @param plotArea the area within which the plot should be drawn.
* @param info collects info about the drawing.
*/
public void draw(Graphics2D g2, Rectangle2D plotArea, ChartRenderingInfo info) {
// adjust for insets...
Insets insets = getInsets();
if (insets != null) {
plotArea.setRect(plotArea.getX() + insets.left,
plotArea.getY() + insets.top,
plotArea.getWidth() - insets.left - insets.right,
plotArea.getHeight() - insets.top - insets.bottom);
}
if (info != null) {
info.setPlotArea(plotArea);
info.setDataArea(plotArea);
}
drawBackground(g2, plotArea);
drawOutline(g2, plotArea);
Shape savedClip = g2.getClip();
g2.clip(plotArea);
Composite originalComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getForegroundAlpha()));
if (this.dataset != null) {
if (!DatasetUtilities.isEmptyOrNull(this.dataset)) {
drawPie(g2, plotArea, info, 0, this.dataset, null);
}
else {
drawNoDataMessage(g2, plotArea);
}
}
else {
drawMultiplePies(g2, plotArea, info);
}
g2.clip(savedClip);
g2.setComposite(originalComposite);
drawOutline(g2, plotArea);
}
/**
* Draws the pie.
*
* @param g2 the graphics device.
* @param plotArea the plot area.
* @param info chart rendering info.
* @param pieIndex the pie index.
* @param data the data.
* @param label the label.
*/
protected void drawPie(Graphics2D g2, Rectangle2D plotArea, ChartRenderingInfo info,
int pieIndex, PieDataset data, String label) {
// adjust the plot area by the interior spacing value
double gapHorizontal = plotArea.getWidth() * this.interiorGap;
double gapVertical = plotArea.getHeight() * this.interiorGap;
double pieX = plotArea.getX() + gapHorizontal / 2;
double pieY = plotArea.getY() + gapVertical / 2;
double pieW = plotArea.getWidth() - gapHorizontal;
double pieH = plotArea.getHeight() - gapVertical;
// make the pie area a square if the pie chart is to be circular...
if (circular) {
double min = Math.min(pieW, pieH) / 2;
pieX = (pieX + pieX + pieW) / 2 - min;
pieY = (pieY + pieY + pieH) / 2 - min;
pieW = 2 * min;
pieH = 2 * min;
}
Rectangle2D explodedPieArea = new Rectangle2D.Double(pieX, pieY, pieW, pieH);
double explodeHorizontal = (1 - radius) * pieW;
double explodeVertical = (1 - radius) * pieH;
Rectangle2D pieArea = new Rectangle2D.Double(pieX + explodeHorizontal / 2,
pieY + explodeVertical / 2,
pieW - explodeHorizontal,
pieH - explodeVertical);
// plot the data (unless the dataset is null)...
if ((data != null) && (data.getKeys().size() > 0)) {
// get a list of categories...
List keys = data.getKeys();
// compute the total value of the data series skipping over the negative values
double totalValue = DatasetUtilities.getPieDatasetTotal(data);
// For each positive value in the dataseries, compute and draw the corresponding arc.
double runningTotal = 0;
int section = 0;
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
Comparable currentKey = (Comparable) iterator.next();
Number dataValue = data.getValue(currentKey);
if (dataValue != null) {
double value = dataValue.doubleValue();
if (value > 0) {
// draw the pie section...
double angle1 = startAngle
+ (direction.getFactor() * (runningTotal * 360)
/ totalValue);
double angle2 = startAngle
+ (direction.getFactor() * (runningTotal + value) * 360
/ totalValue);
runningTotal += value;
double angle = (angle2 - angle1);
if (Math.abs(angle) > this.minimumArcAngleToDraw) {
Rectangle2D arcBounds = getArcBounds(pieArea, explodedPieArea,
angle1, angle2 - angle1,
getExplodePercent(section));
Arc2D.Double arc = new Arc2D.Double(arcBounds, angle1, angle2 - angle1,
Arc2D.PIE);
Paint paint = getPaint(section);
Paint outlinePaint = getOutlinePaint(section);
Stroke outlineStroke = getOutlineStroke(section);
g2.setPaint(paint);
g2.fill(arc);
g2.setStroke(outlineStroke);
g2.setPaint(outlinePaint);
g2.draw(arc);
// add a tooltip for the pie section...
if (info != null) {
EntityCollection entities = info.getEntityCollection();
if (entities != null) {
String tip = null;
if (this.itemLabelGenerator != null) {
tip = this.itemLabelGenerator.generateToolTip(data,
currentKey, pieIndex);
}
String url = null;
if (this.urlGenerator != null) {
url = this.urlGenerator.generateURL(data, currentKey,
pieIndex);
}
PieSectionEntity entity = new PieSectionEntity(
arc, dataset, pieIndex, section, currentKey, tip, url
);
entities.addEntity(entity);
}
}
}
// then draw the label...
if (this.sectionLabelType != NO_LABELS) {
drawLabel(g2, pieArea, explodedPieArea, data, value,
section, angle1, angle2 - angle1);
}
}
}
section = section + 1;
}
// draw the series label
if (label != null) {
g2.setPaint(seriesLabelPaint);
g2.setFont(seriesLabelFont);
Rectangle2D bounds = g2.getFontMetrics().getStringBounds(label, g2);
double labelX = pieX + (pieW / 2) - (bounds.getWidth() / 2);
double labelY = pieY + pieH + 2 * bounds.getHeight();
g2.drawString(label, (int) labelX, (int) labelY);
}
}
else {
drawNoDataMessage(g2, plotArea);
}
}
/**
* Draws a plot containing multiple pies.
*
* @param g2 the graphics device.
* @param plotArea the plot area.
* @param info an (optional) carrier for return information about the chart structure.
*/
protected void drawMultiplePies(Graphics2D g2, Rectangle2D plotArea, ChartRenderingInfo info) {
// check that there is some data to display...
if (DatasetUtilities.isEmptyOrNull(this.multiDataset)) {
drawNoDataMessage(g2, plotArea);
return;
}
int pieCount = 0;
if (this.extractType == PER_ROW) {
pieCount = this.multiDataset.getRowCount();
}
else {
pieCount = this.multiDataset.getColumnCount();
}
// the columns variable is always >= rows
int columns = (int) Math.ceil(Math.sqrt(pieCount));
int rows = (int) Math.ceil((double) pieCount / (double) columns);
// swap rows and columns to match plotArea shape
if (columns > rows && plotArea.getWidth() < plotArea.getHeight()) {
int temp = columns;
columns = rows;
rows = temp;
}
int fontHeight = g2.getFontMetrics(seriesLabelFont).getHeight() * 2;
int x = (int) plotArea.getX();
int y = (int) plotArea.getY();
int width = ((int) plotArea.getWidth()) / columns;
int height = ((int) plotArea.getHeight()) / rows;
int row = 0;
int column = 0;
int diff = (rows * columns) - pieCount;
int xoffset = 0;
Rectangle rect = new Rectangle ();
for (int pieIndex = 0; pieIndex < pieCount; pieIndex++) {
rect.setBounds(x + xoffset + (width * column),
y + (height * row), width, height - fontHeight);
PieDataset dd = new CategoryToPieDataset(this.multiDataset, this.extractType,
pieIndex);
String title = null;
if (this.extractType == PER_ROW) {
title = this.multiDataset.getRowKey(pieIndex).toString();
}
else {
title = this.multiDataset.getColumnKey(pieIndex).toString();
}
drawPie(g2, rect, info, pieIndex, dd, title);
++column;
if (column == columns) {
column = 0;
++row;
if (row == rows - 1 && diff != 0) {
xoffset = (diff * width) / 2;
}
}
}
}
/**
* Draws the label for one pie section.
* <P>
* You can control the label type using the <code>setSectionLabelType()</code> method.
*
* @param g2 the graphics device.
* @param pieArea the area for the unexploded pie sections.
* @param explodedPieArea the area for the exploded pie section.
* @param data the data for the plot.
* @param value the value of the label.
* @param section the section (zero-based index).
* @param startAngle the starting angle.
* @param extent the extent of the arc.
*/
protected void drawLabel(Graphics2D g2,
Rectangle2D pieArea, Rectangle2D explodedPieArea,
PieDataset data, double value,
int section, double startAngle, double extent) {
// handle label drawing...
FontRenderContext frc = g2.getFontRenderContext();
String label = "";
if (this.sectionLabelType == NAME_LABELS) {
label = data.getKey(section).toString();
}
else if (this.sectionLabelType == VALUE_LABELS) {
label = valueFormatter.format(value);
}
else if (this.sectionLabelType == PERCENT_LABELS) {
label = percentFormatter.format(extent / 360 * this.direction.getFactor());
}
else if (this.sectionLabelType == NAME_AND_VALUE_LABELS) {
label = data.getKey(section).toString()
+ " (" + valueFormatter.format(value) + ")";
}
else if (this.sectionLabelType == NAME_AND_PERCENT_LABELS) {
label = data.getKey(section).toString()
+ " (" + percentFormatter.format(extent / 360 * this.direction.getFactor())
+ ")";
}
else if (this.sectionLabelType == VALUE_AND_PERCENT_LABELS) {
label = valueFormatter.format(value)
+ " (" + percentFormatter.format(extent / 360 * this.direction.getFactor())
+ ")";
}
Rectangle2D labelBounds = this.sectionLabelFont.getStringBounds(label, frc);
LineMetrics lm = this.sectionLabelFont.getLineMetrics(label, frc);
double ascent = lm.getAscent();
Point2D labelLocation = calculateLabelLocation(labelBounds, ascent,
pieArea, explodedPieArea,
startAngle, extent,
getExplodePercent(section));
Composite saveComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
g2.setPaint(this.sectionLabelPaint);
g2.setFont(this.sectionLabelFont);
g2.drawString(label, (float) labelLocation.getX(), (float) labelLocation.getY());
g2.setComposite(saveComposite);
}
/**
* Returns a short string describing the type of plot.
*
* @return the plot type.
*/
public String getPlotType() {
return localizationResources.getString("Pie_Plot");
}
/**
* A zoom method that does nothing.
* <p>
* Plots are required to support the zoom operation. In the case of a pie
* chart, it doesn't make sense to zoom in or out, so the method is empty.
*
* @param percent the zoom percentage.
*/
public void zoom(double percent) {
}
/**
* Returns a rectangle that can be used to create a pie section (taking
* into account the amount by which the pie section is 'exploded').
*
* @param unexploded the area inside which the unexploded pie sections are drawn.
* @param exploded the area inside which the exploded pie sections are drawn.
* @param startAngle the start angle.
* @param extent the extent of the arc.
* @param explodePercent the amount by which the pie section is exploded.
*
* @return a rectangle that can be used to create a pie section.
*/
protected Rectangle2D getArcBounds(Rectangle2D unexploded, Rectangle2D exploded,
double startAngle, double extent, double explodePercent) {
if (explodePercent == 0.0) {
return unexploded;
}
else {
Arc2D arc1 = new Arc2D.Double(unexploded, startAngle, extent / 2, Arc2D.OPEN);
Point2D point1 = arc1.getEndPoint();
Arc2D.Double arc2 = new Arc2D.Double(exploded, startAngle, extent / 2, Arc2D.OPEN);
Point2D point2 = arc2.getEndPoint();
double deltaX = (point1.getX() - point2.getX()) * explodePercent;
double deltaY = (point1.getY() - point2.getY()) * explodePercent;
return new Rectangle2D.Double(unexploded.getX() - deltaX,
unexploded.getY() - deltaY,
unexploded.getWidth(),
unexploded.getHeight());
}
}
/**
* Returns the location for a label, taking into account whether or not the
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -