Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2005, 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: * CategoryStepRenderer.java 29: * ------------------------- 30: * 31: * (C) Copyright 2004, 2005, by Brian Cole and Contributors. 32: * 33: * Original Author: Brian Cole; 34: * Contributor(s): David Gilbert (for Object Refinery Limited); 35: * 36: * $Id: CategoryStepRenderer.java,v 1.5.2.1 2005/10/25 20:54:16 mungady Exp $ 37: * 38: * Changes 39: * ------- 40: * 21-Apr-2004 : Version 1, contributed by Brian Cole (DG); 41: * 22-Apr-2004 : Fixed Checkstyle complaints (DG); 42: * 05-Nov-2004 : Modified drawItem() signature (DG); 43: * 08-Mar-2005 : Added equals() method (DG); 44: * 45: */ 46: 47: package org.jfree.chart.renderer.category; 48: 49: import java.awt.Graphics2D; 50: import java.awt.geom.Line2D; 51: import java.awt.geom.Rectangle2D; 52: import java.io.Serializable; 53: 54: import org.jfree.chart.axis.CategoryAxis; 55: import org.jfree.chart.axis.ValueAxis; 56: import org.jfree.chart.event.RendererChangeEvent; 57: import org.jfree.chart.plot.CategoryPlot; 58: import org.jfree.chart.plot.PlotOrientation; 59: import org.jfree.chart.renderer.xy.XYStepRenderer; 60: import org.jfree.data.category.CategoryDataset; 61: import org.jfree.util.PublicCloneable; 62: 63: /** 64: * A "step" renderer similar to {@link XYStepRenderer} but 65: * that can be used with the {@link CategoryPlot} class. 66: * 67: * @author Brian Cole 68: */ 69: public class CategoryStepRenderer extends AbstractCategoryItemRenderer 70: implements Cloneable, PublicCloneable, 71: Serializable { 72: 73: /** For serialization. */ 74: private static final long serialVersionUID = -5121079703118261470L; 75: 76: /** The stagger width. */ 77: public static final int STAGGER_WIDTH = 5; // could make this configurable 78: 79: /** 80: * A flag that controls whether or not the steps for multiple series are 81: * staggered. 82: */ 83: private boolean stagger = false; 84: 85: /** A working line - need to remove this. */ 86: private transient Line2D line = new Line2D.Double(0.0, 0.0, 0.0, 0.0); 87: 88: /** 89: * Creates a new renderer (stagger defaults to <code>false</code>). 90: */ 91: public CategoryStepRenderer() { 92: this(false); 93: } 94: 95: /** 96: * Creates a new renderer. 97: * 98: * @param stagger should the horizontal part of the step be staggered by 99: * series? 100: */ 101: public CategoryStepRenderer(boolean stagger) { 102: this.stagger = stagger; 103: } 104: 105: /** 106: * Returns the flag that controls whether the series steps are staggered. 107: * 108: * @return A boolean. 109: */ 110: public boolean getStagger() { 111: return this.stagger; 112: } 113: 114: /** 115: * Sets the flag that controls whether or not the series steps are 116: * staggered and sends a {@link RendererChangeEvent} to all registered 117: * listeners. 118: * 119: * @param shouldStagger a boolean. 120: */ 121: public void setStagger(boolean shouldStagger) { 122: this.stagger = shouldStagger; 123: notifyListeners(new RendererChangeEvent(this)); 124: } 125: 126: /** 127: * Draws the line. 128: * 129: * @param g2 the graphics device. 130: * @param orientation the plot orientation. 131: * @param x0 the x-coordinate for the start of the line. 132: * @param y0 the y-coordinate for the start of the line. 133: * @param x1 the x-coordinate for the end of the line. 134: * @param y1 the y-coordinate for the end of the line. 135: */ 136: protected void drawLine(Graphics2D g2, PlotOrientation orientation, 137: double x0, double y0, double x1, double y1) { 138: 139: if (orientation == PlotOrientation.VERTICAL) { 140: this.line.setLine(x0, y0, x1, y1); 141: g2.draw(this.line); 142: } 143: else if (orientation == PlotOrientation.HORIZONTAL) { 144: this.line.setLine(y0, x0, y1, x1); // switch x and y 145: g2.draw(this.line); 146: } 147: // else unknown orientation (complain?) 148: } 149: 150: /** 151: * Draw a single data item. 152: * 153: * @param g2 the graphics device. 154: * @param state the renderer state. 155: * @param dataArea the area in which the data is drawn. 156: * @param plot the plot. 157: * @param domainAxis the domain axis. 158: * @param rangeAxis the range axis. 159: * @param dataset the dataset. 160: * @param row the row index (zero-based). 161: * @param column the column index (zero-based). 162: * @param pass the pass index. 163: */ 164: public void drawItem(Graphics2D g2, 165: CategoryItemRendererState state, 166: Rectangle2D dataArea, 167: CategoryPlot plot, 168: CategoryAxis domainAxis, 169: ValueAxis rangeAxis, 170: CategoryDataset dataset, 171: int row, 172: int column, 173: int pass) { 174: 175: Number value = dataset.getValue(row, column); 176: if (value == null) { 177: return; 178: } 179: PlotOrientation orientation = plot.getOrientation(); 180: 181: // current data point... 182: double x1s = domainAxis.getCategoryStart( 183: column, getColumnCount(), dataArea, plot.getDomainAxisEdge() 184: ); 185: double x1 = domainAxis.getCategoryMiddle( 186: column, getColumnCount(), dataArea, plot.getDomainAxisEdge() 187: ); 188: double x1e = 2 * x1 - x1s; // or: x1s + 2*(x1-x1s) 189: double y1 = rangeAxis.valueToJava2D( 190: value.doubleValue(), dataArea, plot.getRangeAxisEdge() 191: ); 192: g2.setPaint(getItemPaint(row, column)); 193: g2.setStroke(getItemStroke(row, column)); 194: 195: if (column != 0) { 196: Number previousValue = dataset.getValue(row, column - 1); 197: if (previousValue != null) { 198: // previous data point... 199: double previous = previousValue.doubleValue(); 200: double x0s = domainAxis.getCategoryStart( 201: column - 1, getColumnCount(), dataArea, 202: plot.getDomainAxisEdge() 203: ); 204: double x0 = domainAxis.getCategoryMiddle( 205: column - 1, getColumnCount(), dataArea, 206: plot.getDomainAxisEdge() 207: ); 208: double x0e = 2 * x0 - x0s; // or: x0s + 2*(x0-x0s) 209: double y0 = rangeAxis.valueToJava2D( 210: previous, dataArea, plot.getRangeAxisEdge() 211: ); 212: if (getStagger()) { 213: int xStagger = row * STAGGER_WIDTH; 214: if (xStagger > (x1s - x0e)) { 215: xStagger = (int) (x1s - x0e); 216: } 217: x1s = x0e + xStagger; 218: } 219: drawLine(g2, orientation, x0e, y0, x1s, y0); 220: // extend x0's flat bar 221: 222: drawLine(g2, orientation, x1s, y0, x1s, y1); // upright bar 223: } 224: } 225: drawLine(g2, orientation, x1s, y1, x1e, y1); // x1's flat bar 226: 227: // draw the item labels if there are any... 228: if (isItemLabelVisible(row, column)) { 229: drawItemLabel( 230: g2, orientation, dataset, row, column, x1, y1, 231: (value.doubleValue() < 0.0) 232: ); 233: } 234: /* This is how LineAndShapeRenderer.drawItem() handles tips and URLs, but 235: I omit it due to time pressure. It shouldn't be hard to put back 236: in. 237: 238: // collect entity and tool tip information... 239: if (state.getInfo() != null) { 240: EntityCollection entities = 241: state.getInfo().getOwner().getEntityCollection(); 242: if (entities != null && shape != null) { 243: String tip = null; 244: CategoryItemLabelGenerator generator = 245: getItemLabelGenerator(row, column); 246: if (generator != null) { 247: tip = generator.generateToolTip(dataset, row, column); 248: } 249: String url = null; 250: if (getItemURLGenerator(row, column) != null) 251: url = getItemURLGenerator(row, column).generateURL(dataset, row, 252: column); 253: } 254: CategoryItemEntity entity = new CategoryItemEntity( 255: shape, tip, url, dataset, row, 256: dataset.getColumnKey(column), column); 257: entities.addEntity(entity); 258: } 259: } 260: */ 261: 262: } 263: 264: /** 265: * Tests this renderer for equality with an arbitrary object. 266: * 267: * @param obj the object (<code>null</code> permitted). 268: * 269: * @return A boolean. 270: */ 271: public boolean equals(Object obj) { 272: if (obj == this) { 273: return true; 274: } 275: if (!(obj instanceof CategoryStepRenderer)) { 276: return false; 277: } 278: if (!super.equals(obj)) { 279: return false; 280: } 281: CategoryStepRenderer that = (CategoryStepRenderer) obj; 282: if (this.stagger != that.stagger) { 283: return false; 284: } 285: return true; 286: } 287: 288: }