From: David G. <mu...@us...> - 2006-06-21 14:12:10
|
Update of /cvsroot/jfreechart/jfreechart/source/org/jfree/chart/renderer/xy In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv15448/source/org/jfree/chart/renderer/xy Modified Files: Tag: STABLE_1-0-0 XYBarRenderer.java Log Message: 2006-06-21 David Gilbert <dav...@ob...> * source/org/jfree/chart/renderer/xy/XYBarRenderer.java (positiveItemLabelPositionFallback): New field, (negativeItemLabelPositionFallback): Likewise, (getPositiveItemLabelPositionFallback): New method, (setPositiveItemLabelPositionFallback): Likewise, (getNegativeItemLabelPositionFallback): Likewise, (setNegativeItemLabelPositionFallback): Likewise, (drawItem): Call new drawItemLabel() method, (drawItemLabel): New method, (calculateLabelAnchorPoint): New method, (isInternalAnchor): New method, (equals): Updated for new fields, * source/org/jfree/chart/renderer/xy/junit/XYBarRendererTests.java (testEquals): Extended to cover new fields, (testSerialization2): New test. Index: XYBarRenderer.java =================================================================== RCS file: /cvsroot/jfreechart/jfreechart/source/org/jfree/chart/renderer/xy/XYBarRenderer.java,v retrieving revision 1.14.2.4 retrieving revision 1.14.2.5 diff -C2 -d -r1.14.2.4 -r1.14.2.5 *** XYBarRenderer.java 28 Nov 2005 12:06:35 -0000 1.14.2.4 --- XYBarRenderer.java 21 Jun 2006 14:12:03 -0000 1.14.2.5 *************** *** 3,7 **** * =========================================================== * ! * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html --- 3,7 ---- * =========================================================== * ! * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html *************** *** 28,32 **** * XYBarRenderer.java * ------------------ ! * (C) Copyright 2001-2005, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); --- 28,32 ---- * XYBarRenderer.java * ------------------ ! * (C) Copyright 2001-2006, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); *************** *** 72,75 **** --- 72,77 ---- * 19-May-2005 : Added minimal item label implementation - needs improving (DG); * 14-Oct-2005 : Fixed rendering problem with inverted axes (DG); + * ------------- JFREECHART 1.0.0 --------------------------------------------- + * 21-Jun-2006 : Improved item label handling - see bug 1501768 (DG); * */ *************** *** 77,80 **** --- 79,83 ---- package org.jfree.chart.renderer.xy; + import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics2D; *************** *** 82,85 **** --- 85,89 ---- import java.awt.Shape; import java.awt.Stroke; + import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; *************** *** 93,96 **** --- 97,103 ---- import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.event.RendererChangeEvent; + import org.jfree.chart.labels.ItemLabelAnchor; + import org.jfree.chart.labels.ItemLabelPosition; + import org.jfree.chart.labels.XYItemLabelGenerator; import org.jfree.chart.labels.XYSeriesLabelGenerator; import org.jfree.chart.labels.XYToolTipGenerator; *************** *** 104,107 **** --- 111,115 ---- import org.jfree.data.xy.XYDataset; import org.jfree.io.SerialUtilities; + import org.jfree.text.TextUtilities; import org.jfree.ui.GradientPaintTransformer; import org.jfree.ui.RectangleEdge; *************** *** 118,125 **** */ public class XYBarRenderer extends AbstractXYItemRenderer ! implements XYItemRenderer, ! Cloneable, ! PublicCloneable, ! Serializable { /** For serialization. */ --- 126,130 ---- */ public class XYBarRenderer extends AbstractXYItemRenderer ! implements XYItemRenderer, Cloneable, PublicCloneable, Serializable { /** For serialization. */ *************** *** 189,192 **** --- 194,209 ---- private transient Shape legendBar; + /** + * The fallback position if a positive item label doesn't fit inside the + * bar. + */ + private ItemLabelPosition positiveItemLabelPositionFallback; + + /** + * The fallback position if a negative item label doesn't fit inside the + * bar. + */ + private ItemLabelPosition negativeItemLabelPositionFallback; + /** * The default constructor. *************** *** 341,344 **** --- 358,415 ---- /** + * Returns the fallback position for positive item labels that don't fit + * within a bar. + * + * @return The fallback position (<code>null</code> possible). + * + * @since 1.0.2 + */ + public ItemLabelPosition getPositiveItemLabelPositionFallback() { + return this.positiveItemLabelPositionFallback; + } + + /** + * Sets the fallback position for positive item labels that don't fit + * within a bar, and sends a {@link RendererChangeEvent} to all registered + * listeners. + * + * @param position the position (<code>null</code> permitted). + * + * @since 1.0.2 + */ + public void setPositiveItemLabelPositionFallback( + ItemLabelPosition position) { + this.positiveItemLabelPositionFallback = position; + notifyListeners(new RendererChangeEvent(this)); + } + + /** + * Returns the fallback position for negative item labels that don't fit + * within a bar. + * + * @return The fallback position (<code>null</code> possible). + * + * @since 1.0.2 + */ + public ItemLabelPosition getNegativeItemLabelPositionFallback() { + return this.negativeItemLabelPositionFallback; + } + + /** + * Sets the fallback position for negative item labels that don't fit + * within a bar, and sends a {@link RendererChangeEvent} to all registered + * listeners. + * + * @param position the position (<code>null</code> permitted). + * + * @since 1.0.2 + */ + public void setNegativeItemLabelPositionFallback( + ItemLabelPosition position) { + this.negativeItemLabelPositionFallback = position; + notifyListeners(new RendererChangeEvent(this)); + } + + /** * Initialises the renderer and returns a state object that should be * passed to all subsequent calls to the drawItem() method. Here we *************** *** 355,372 **** * @return A state object. */ ! public XYItemRendererState initialise(Graphics2D g2, ! Rectangle2D dataArea, ! XYPlot plot, ! XYDataset dataset, ! PlotRenderingInfo info) { XYBarRendererState state = new XYBarRendererState(info); ValueAxis rangeAxis = plot.getRangeAxisForDataset(plot.indexOf(dataset)); ! state.setG2Base( ! rangeAxis.valueToJava2D( ! this.base, dataArea, plot.getRangeAxisEdge() ! ) ! ); return state; --- 426,437 ---- * @return A state object. */ ! public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea, ! XYPlot plot, XYDataset dataset, PlotRenderingInfo info) { XYBarRendererState state = new XYBarRendererState(info); ValueAxis rangeAxis = plot.getRangeAxisForDataset(plot.indexOf(dataset)); ! state.setG2Base(rangeAxis.valueToJava2D(this.base, dataArea, ! plot.getRangeAxisEdge())); return state; *************** *** 394,405 **** if (getLegendItemToolTipGenerator() != null) { toolTipText = getLegendItemToolTipGenerator().generateLabel( ! dataset, series ! ); } String urlText = null; if (getLegendItemURLGenerator() != null) { urlText = getLegendItemURLGenerator().generateLabel( ! dataset, series ! ); } Shape shape = this.legendBar; --- 459,468 ---- if (getLegendItemToolTipGenerator() != null) { toolTipText = getLegendItemToolTipGenerator().generateLabel( ! dataset, series); } String urlText = null; if (getLegendItemURLGenerator() != null) { urlText = getLegendItemURLGenerator().generateLabel( ! dataset, series); } Shape shape = this.legendBar; *************** *** 464,473 **** } ! double translatedValue0 = rangeAxis.valueToJava2D( ! value0, dataArea, plot.getRangeAxisEdge() ! ); ! double translatedValue1 = rangeAxis.valueToJava2D( ! value1, dataArea, plot.getRangeAxisEdge() ! ); RectangleEdge location = plot.getDomainAxisEdge(); --- 527,534 ---- } ! double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, ! plot.getRangeAxisEdge()); ! double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, ! plot.getRangeAxisEdge()); RectangleEdge location = plot.getDomainAxisEdge(); *************** *** 477,482 **** } double translatedStartX = domainAxis.valueToJava2D( ! startXNumber.doubleValue(), dataArea, location ! ); Number endXNumber = intervalDataset.getEndX(series, item); --- 538,542 ---- } double translatedStartX = domainAxis.valueToJava2D( ! startXNumber.doubleValue(), dataArea, location); Number endXNumber = intervalDataset.getEndX(series, item); *************** *** 485,494 **** } double translatedEndX = domainAxis.valueToJava2D( ! endXNumber.doubleValue(), dataArea, location ! ); ! double translatedWidth = Math.max( ! 1, Math.abs(translatedEndX - translatedStartX) ! ); double translatedHeight = Math.abs(translatedValue1 - translatedValue0); --- 545,552 ---- } double translatedEndX = domainAxis.valueToJava2D( ! endXNumber.doubleValue(), dataArea, location); ! double translatedWidth = Math.max(1, Math.abs(translatedEndX ! - translatedStartX)); double translatedHeight = Math.abs(translatedValue1 - translatedValue0); *************** *** 533,542 **** } - // TODO: we need something better for the item labels if (isItemLabelVisible(series, item)) { ! drawItemLabel( ! g2, orientation, dataset, series, item, bar.getCenterX(), ! bar.getY(), value1 < 0.0 ! ); } --- 591,599 ---- } if (isItemLabelVisible(series, item)) { ! XYItemLabelGenerator generator = getItemLabelGenerator(series, ! item); ! drawItemLabel(g2, dataset, series, item, plot, generator, bar, ! value1 < 0.0); } *************** *** 565,568 **** --- 622,830 ---- /** + * Draws an item label. This method is overridden so that the bar can be + * used to calculate the label anchor point. + * + * @param g2 the graphics device. + * @param data the dataset. + * @param series the series index. + * @param item the item index. + * @param plot the plot. + * @param generator the label generator. + * @param bar the bar. + * @param negative a flag indicating a negative value. + */ + protected void drawItemLabel(Graphics2D g2, XYDataset dataset, + int series, int item, XYPlot plot, XYItemLabelGenerator generator, + Rectangle2D bar, boolean negative) { + + String label = generator.generateLabel(dataset, series, item); + if (label == null) { + return; // nothing to do + } + + Font labelFont = getItemLabelFont(series, item); + g2.setFont(labelFont); + Paint paint = getItemLabelPaint(series, item); + g2.setPaint(paint); + + // find out where to place the label... + ItemLabelPosition position = null; + if (!negative) { + position = getPositiveItemLabelPosition(series, item); + } + else { + position = getNegativeItemLabelPosition(series, item); + } + + // work out the label anchor point... + Point2D anchorPoint = calculateLabelAnchorPoint( + position.getItemLabelAnchor(), bar, plot.getOrientation()); + + if (isInternalAnchor(position.getItemLabelAnchor())) { + Shape bounds = TextUtilities.calculateRotatedStringBounds(label, + g2, (float) anchorPoint.getX(), (float) anchorPoint.getY(), + position.getTextAnchor(), position.getAngle(), + position.getRotationAnchor()); + + if (bounds != null) { + if (!bar.contains(bounds.getBounds2D())) { + if (!negative) { + position = getPositiveItemLabelPositionFallback(); + } + else { + position = getNegativeItemLabelPositionFallback(); + } + if (position != null) { + anchorPoint = calculateLabelAnchorPoint( + position.getItemLabelAnchor(), bar, + plot.getOrientation()); + } + } + } + + } + + if (position != null) { + TextUtilities.drawRotatedString(label, g2, + (float) anchorPoint.getX(), (float) anchorPoint.getY(), + position.getTextAnchor(), position.getAngle(), + position.getRotationAnchor()); + } + } + + /** + * Calculates the item label anchor point. + * + * @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; + + } + + /** + * Returns <code>true</code> if the specified anchor point is inside a bar. + * + * @param anchor the anchor point. + * + * @return A boolean. + */ + private boolean isInternalAnchor(ItemLabelAnchor anchor) { + return anchor == ItemLabelAnchor.CENTER + || anchor == ItemLabelAnchor.INSIDE1 + || anchor == ItemLabelAnchor.INSIDE2 + || anchor == ItemLabelAnchor.INSIDE3 + || anchor == ItemLabelAnchor.INSIDE4 + || anchor == ItemLabelAnchor.INSIDE5 + || anchor == ItemLabelAnchor.INSIDE6 + || anchor == ItemLabelAnchor.INSIDE7 + || anchor == ItemLabelAnchor.INSIDE8 + || anchor == ItemLabelAnchor.INSIDE9 + || anchor == ItemLabelAnchor.INSIDE10 + || anchor == ItemLabelAnchor.INSIDE11 + || anchor == ItemLabelAnchor.INSIDE12; + } + + /** * Returns the lower and upper bounds (range) of the x-values in the * specified dataset. Since this renderer uses the x-interval in the *************** *** 637,640 **** --- 899,910 ---- return false; } + if (!ObjectUtilities.equal(this.positiveItemLabelPositionFallback, + that.positiveItemLabelPositionFallback)) { + return false; + } + if (!ObjectUtilities.equal(this.negativeItemLabelPositionFallback, + that.negativeItemLabelPositionFallback)) { + return false; + } return true; } |