Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors. 6: * 7: * Project Info: http://www.jfree.org/jfreechart/index.html 8: * 9: * This library is free software; you can redistribute it and/or modify it 10: * under the terms of the GNU Lesser General Public License as published by 11: * the Free Software Foundation; either version 2.1 of the License, or 12: * (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17: * License for more details. 18: * 19: * You should have received a copy of the GNU Lesser General Public 20: * License along with this library; if not, write to the Free Software 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22: * USA. 23: * 24: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * --------------------------- 28: * ClusteredXYBarRenderer.java 29: * --------------------------- 30: * (C) Copyright 2003-2006, by Paolo Cova and Contributors. 31: * 32: * Original Author: Paolo Cova; 33: * Contributor(s): David Gilbert (for Object Refinery Limited); 34: * Christian W. Zuckschwerdt; 35: * Matthias Rose; 36: * 37: * $Id: ClusteredXYBarRenderer.java,v 1.8.2.2 2006/06/21 15:10:25 mungady Exp $ 38: * 39: * Changes 40: * ------- 41: * 24-Jan-2003 : Version 1, contributed by Paolo Cova (DG); 42: * 25-Mar-2003 : Implemented Serializable (DG); 43: * 01-May-2003 : Modified drawItem() method signature (DG); 44: * 30-Jul-2003 : Modified entity constructor (CZ); 45: * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG); 46: * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 47: * 07-Oct-2003 : Added renderer state (DG); 48: * 03-Nov-2003 : In draw method added state parameter and y==null value 49: * handling (MR); 50: * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); 51: * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 52: * getYValue() (DG); 53: * 01-Oct-2004 : Fixed bug where 'drawBarOutline' flag is ignored (DG); 54: * 16-May-2005 : Fixed to used outline stroke for bar outlines. Removed some 55: * redundant code with the result that the renderer now respects 56: * the 'base' setting from the super-class. Added an equals() 57: * method (DG); 58: * 19-May-2005 : Added minimal item label implementation - needs improving (DG); 59: * 60: */ 61: 62: package org.jfree.chart.renderer.xy; 63: 64: import java.awt.Graphics2D; 65: import java.awt.Paint; 66: import java.awt.geom.Rectangle2D; 67: import java.io.Serializable; 68: 69: import org.jfree.chart.axis.ValueAxis; 70: import org.jfree.chart.entity.EntityCollection; 71: import org.jfree.chart.entity.XYItemEntity; 72: import org.jfree.chart.labels.XYItemLabelGenerator; 73: import org.jfree.chart.labels.XYToolTipGenerator; 74: import org.jfree.chart.plot.CrosshairState; 75: import org.jfree.chart.plot.PlotOrientation; 76: import org.jfree.chart.plot.PlotRenderingInfo; 77: import org.jfree.chart.plot.XYPlot; 78: import org.jfree.data.xy.IntervalXYDataset; 79: import org.jfree.data.xy.XYDataset; 80: import org.jfree.ui.RectangleEdge; 81: import org.jfree.util.PublicCloneable; 82: 83: /** 84: * An extension of {@link XYBarRenderer} that displays bars for different 85: * series values at the same x next to each other. The assumption here is 86: * that for each x (time or else) there is a y value for each series. If 87: * this is not the case, there will be spaces between bars for a given x. 88: * <P> 89: * This renderer does not include code to calculate the crosshair point for the 90: * plot. 91: * 92: * @author Paolo Cova 93: */ 94: public class ClusteredXYBarRenderer extends XYBarRenderer 95: implements Cloneable, PublicCloneable, 96: Serializable { 97: 98: /** For serialization. */ 99: private static final long serialVersionUID = 5864462149177133147L; 100: 101: /** Determines whether bar center should be interval start. */ 102: private boolean centerBarAtStartValue; 103: 104: /** 105: * Default constructor. Bar margin is set to 0.0. 106: */ 107: public ClusteredXYBarRenderer() { 108: this(0.0, false); 109: } 110: 111: /** 112: * Constructs a new XY clustered bar renderer. 113: * 114: * @param margin the percentage amount to trim from the width of each bar. 115: * @param centerBarAtStartValue if true, bars will be centered on the start 116: * of the time period. 117: */ 118: public ClusteredXYBarRenderer(double margin, 119: boolean centerBarAtStartValue) { 120: super(margin); 121: this.centerBarAtStartValue = centerBarAtStartValue; 122: } 123: 124: /** 125: * Draws the visual representation of a single data item. This method 126: * is mostly copied from the superclass, the change is that in the 127: * calculated space for a singe bar we draw bars for each series next to 128: * each other. The width of each bar is the available width divided by 129: * the number of series. Bars for each series are drawn in order left to 130: * right. 131: * 132: * @param g2 the graphics device. 133: * @param state the renderer state. 134: * @param dataArea the area within which the plot is being drawn. 135: * @param info collects information about the drawing. 136: * @param plot the plot (can be used to obtain standard color 137: * information etc). 138: * @param domainAxis the domain axis. 139: * @param rangeAxis the range axis. 140: * @param dataset the dataset. 141: * @param series the series index. 142: * @param item the item index. 143: * @param crosshairState crosshair information for the plot 144: * (<code>null</code> permitted). 145: * @param pass the pass index. 146: */ 147: public void drawItem(Graphics2D g2, 148: XYItemRendererState state, 149: Rectangle2D dataArea, 150: PlotRenderingInfo info, 151: XYPlot plot, 152: ValueAxis domainAxis, 153: ValueAxis rangeAxis, 154: XYDataset dataset, int series, int item, 155: CrosshairState crosshairState, 156: int pass) { 157: 158: IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 159: 160: Paint seriesPaint = getItemPaint(series, item); 161: 162: double value0; 163: double value1; 164: if (getUseYInterval()) { 165: value0 = intervalDataset.getStartYValue(series, item); 166: value1 = intervalDataset.getEndYValue(series, item); 167: } 168: else { 169: value0 = getBase(); 170: value1 = intervalDataset.getYValue(series, item); 171: } 172: if (Double.isNaN(value0) || Double.isNaN(value1)) { 173: return; 174: } 175: 176: double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, 177: plot.getRangeAxisEdge()); 178: double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, 179: plot.getRangeAxisEdge()); 180: 181: RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 182: double x1 = intervalDataset.getStartXValue(series, item); 183: double translatedX1 = domainAxis.valueToJava2D(x1, dataArea, 184: xAxisLocation); 185: 186: double x2 = intervalDataset.getEndXValue(series, item); 187: double translatedX2 = domainAxis.valueToJava2D(x2, dataArea, 188: xAxisLocation); 189: 190: double translatedWidth = Math.max(1, Math.abs(translatedX2 191: - translatedX1)); 192: double translatedHeight = Math.abs(translatedValue0 - translatedValue1); 193: 194: if (this.centerBarAtStartValue) { 195: translatedX1 -= translatedWidth / 2; 196: } 197: 198: PlotOrientation orientation = plot.getOrientation(); 199: double m = getMargin(); 200: if (m > 0.0) { 201: double cut = translatedWidth * getMargin(); 202: translatedWidth = translatedWidth - cut; 203: if (orientation == PlotOrientation.HORIZONTAL) 204: translatedX1 = translatedX1 - cut / 2; 205: else 206: translatedX1 = translatedX1 + cut / 2; 207: } 208: 209: int numSeries = dataset.getSeriesCount(); 210: double seriesBarWidth = translatedWidth / numSeries; 211: 212: Rectangle2D bar = null; 213: if (orientation == PlotOrientation.HORIZONTAL) { 214: bar = new Rectangle2D.Double(Math.min(translatedValue0, 215: translatedValue1), translatedX1 - seriesBarWidth 216: * (numSeries - series), translatedHeight, seriesBarWidth); 217: } 218: else if (orientation == PlotOrientation.VERTICAL) { 219: bar = new Rectangle2D.Double(translatedX1 + seriesBarWidth * series, 220: Math.min(translatedValue0, translatedValue1), 221: seriesBarWidth, translatedHeight); 222: } 223: g2.setPaint(seriesPaint); 224: g2.fill(bar); 225: if (isDrawBarOutline() && Math.abs(translatedX2 - translatedX1) > 3) { 226: g2.setStroke(getItemOutlineStroke(series, item)); 227: g2.setPaint(getItemOutlinePaint(series, item)); 228: g2.draw(bar); 229: } 230: 231: if (isItemLabelVisible(series, item)) { 232: XYItemLabelGenerator generator = getItemLabelGenerator(series, 233: item); 234: drawItemLabel(g2, dataset, series, item, plot, generator, bar, 235: value1 < 0.0); 236: } 237: 238: // add an entity for the item... 239: if (info != null) { 240: EntityCollection entities = info.getOwner().getEntityCollection(); 241: if (entities != null) { 242: String tip = null; 243: XYToolTipGenerator generator 244: = getToolTipGenerator(series, item); 245: if (generator != null) { 246: tip = generator.generateToolTip(dataset, series, item); 247: } 248: String url = null; 249: if (getURLGenerator() != null) { 250: url = getURLGenerator().generateURL(dataset, series, item); 251: } 252: XYItemEntity entity = new XYItemEntity(bar, dataset, series, 253: item, tip, url); 254: entities.add(entity); 255: } 256: } 257: 258: } 259: 260: /** 261: * Tests this renderer for equality with an arbitrary object, returning 262: * <code>true</code> if <code>obj</code> is a 263: * <code>ClusteredXYBarRenderer</code> with the same settings as this 264: * renderer, and <code>false</code> otherwise. 265: * 266: * @param obj the object (<code>null</code> permitted). 267: * 268: * @return A boolean. 269: */ 270: public boolean equals(Object obj) { 271: if (obj == this) { 272: return true; 273: } 274: if (!(obj instanceof ClusteredXYBarRenderer)) { 275: return false; 276: } 277: if (!super.equals(obj)) { 278: return false; 279: } 280: ClusteredXYBarRenderer that = (ClusteredXYBarRenderer) obj; 281: if (this.centerBarAtStartValue != that.centerBarAtStartValue) { 282: return false; 283: } 284: return true; 285: } 286: 287: /** 288: * Returns a clone of the renderer. 289: * 290: * @return A clone. 291: * 292: * @throws CloneNotSupportedException if the renderer cannot be cloned. 293: */ 294: public Object clone() throws CloneNotSupportedException { 295: return super.clone(); 296: } 297: 298: }