Source for org.jfree.chart.renderer.xy.XYLine3DRenderer

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, 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:  * XYLine3DRenderer.java
  29:  * ---------------------
  30:  * (C) Copyright 2005, 2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  Thomas Morgner;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 14-Jan-2005 : Added standard header (DG);
  38:  * 01-May-2007 : Fixed equals() and serialization bugs (DG);
  39:  * 
  40:  */
  41: 
  42: package org.jfree.chart.renderer.xy;
  43: 
  44: import java.awt.Color;
  45: import java.awt.Graphics2D;
  46: import java.awt.Paint;
  47: import java.awt.Shape;
  48: import java.io.IOException;
  49: import java.io.ObjectInputStream;
  50: import java.io.ObjectOutputStream;
  51: import java.io.Serializable;
  52: 
  53: import org.jfree.chart.Effect3D;
  54: import org.jfree.chart.event.RendererChangeEvent;
  55: import org.jfree.io.SerialUtilities;
  56: import org.jfree.util.PaintUtilities;
  57: 
  58: /**
  59:  * A XYLineAndShapeRenderer that adds a shadow line to the graph
  60:  * to emulate a 3D-effect.
  61:  */
  62: public class XYLine3DRenderer extends XYLineAndShapeRenderer 
  63:                               implements Effect3D, Serializable {
  64: 
  65:     /** For serialization. */
  66:     private static final long serialVersionUID = 588933208243446087L;
  67:     
  68:     /** The default x-offset for the 3D effect. */
  69:     public static final double DEFAULT_X_OFFSET = 12.0;
  70: 
  71:     /** The default y-offset for the 3D effect. */
  72:     public static final double DEFAULT_Y_OFFSET = 8.0;
  73: 
  74:     /** The default wall paint. */
  75:     public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
  76: 
  77:     /** The size of x-offset for the 3D effect. */
  78:     private double xOffset;
  79: 
  80:     /** The size of y-offset for the 3D effect. */
  81:     private double yOffset;
  82: 
  83:     /** The paint used to shade the left and lower 3D wall. */
  84:     private transient Paint wallPaint;
  85: 
  86:     /**
  87:      * Creates a new renderer.
  88:      */
  89:     public XYLine3DRenderer() {
  90:         this.wallPaint = DEFAULT_WALL_PAINT;
  91:         this.xOffset = DEFAULT_X_OFFSET;
  92:         this.yOffset = DEFAULT_Y_OFFSET;
  93:     }
  94: 
  95:     /**
  96:      * Returns the x-offset for the 3D effect.
  97:      *
  98:      * @return The 3D effect.
  99:      */
 100:     public double getXOffset() {
 101:         return this.xOffset;
 102:     }
 103: 
 104:     /**
 105:      * Returns the y-offset for the 3D effect.
 106:      *
 107:      * @return The 3D effect.
 108:      */
 109:     public double getYOffset() {
 110:         return this.yOffset;
 111:     }
 112: 
 113:     /**
 114:      * Sets the x-offset and sends a {@link RendererChangeEvent} to all 
 115:      * registered listeners.
 116:      * 
 117:      * @param xOffset  the x-offset.
 118:      */
 119:     public void setXOffset(double xOffset) {
 120:         this.xOffset = xOffset;
 121:         fireChangeEvent();
 122:     }
 123: 
 124:     /**
 125:      * Sets the y-offset and sends a {@link RendererChangeEvent} to all 
 126:      * registered listeners.
 127:      * 
 128:      * @param yOffset  the y-offset.
 129:      */
 130:     public void setYOffset(double yOffset) {
 131:         this.yOffset = yOffset;
 132:         fireChangeEvent();
 133:     }
 134: 
 135:     /**
 136:      * Returns the paint used to highlight the left and bottom wall in the plot
 137:      * background.
 138:      *
 139:      * @return The paint.
 140:      */
 141:     public Paint getWallPaint() {
 142:         return this.wallPaint;
 143:     }
 144: 
 145:     /**
 146:      * Sets the paint used to hightlight the left and bottom walls in the plot 
 147:      * background and sends a {@link RendererChangeEvent} to all registered
 148:      * listeners.
 149:      *
 150:      * @param paint  the paint.
 151:      */
 152:     public void setWallPaint(Paint paint) {
 153:         this.wallPaint = paint;
 154:         fireChangeEvent();
 155:     }
 156: 
 157:     /**
 158:      * Returns the number of passes through the data that the renderer requires 
 159:      * in order to draw the chart.  Most charts will require a single pass, 
 160:      * but some require two passes.
 161:      *
 162:      * @return The pass count.
 163:      */
 164:     public int getPassCount() {
 165:         return 3;
 166:     }
 167: 
 168:     /**
 169:      * Returns <code>true</code> if the specified pass involves drawing lines.
 170:      * 
 171:      * @param pass  the pass.
 172:      * 
 173:      * @return A boolean.
 174:      */
 175:     protected boolean isLinePass(int pass) {
 176:         return pass == 0 || pass == 1;
 177:     }
 178: 
 179:     /**
 180:      * Returns <code>true</code> if the specified pass involves drawing items.
 181:      * 
 182:      * @param pass  the pass.
 183:      * 
 184:      * @return A boolean.
 185:      */
 186:     protected boolean isItemPass(int pass) {
 187:         return pass == 2;
 188:     }
 189: 
 190:     /**
 191:      * Returns <code>true</code> if the specified pass involves drawing shadows.
 192:      * 
 193:      * @param pass  the pass.
 194:      * 
 195:      * @return A boolean.
 196:      */
 197:     protected boolean isShadowPass (int pass) {
 198:         return pass == 0;
 199:     }
 200: 
 201:     /**
 202:      * Overrides the method in the subclass to draw a shadow in the first pass.
 203:      * 
 204:      * @param g2  the graphics device.
 205:      * @param pass  the pass.
 206:      * @param series  the series index (zero-based).
 207:      * @param item  the item index (zero-based).
 208:      * @param shape  the shape.
 209:      */
 210:     protected void drawFirstPassShape(Graphics2D g2,
 211:                                       int pass,
 212:                                       int series,
 213:                                       int item,
 214:                                       Shape shape) {
 215:         if (isShadowPass(pass)) {
 216:             if (getWallPaint() != null) {
 217:                 g2.setStroke(getItemStroke(series, item));
 218:                 g2.setPaint(getWallPaint());
 219:                 g2.translate(getXOffset(), getYOffset());
 220:                 g2.draw(shape);
 221:                 g2.translate(-getXOffset(), -getYOffset());
 222:             }
 223:         }
 224:         else {
 225:             // now draw the real shape
 226:             super.drawFirstPassShape(g2, pass, series, item, shape);
 227:         }
 228:     }
 229: 
 230:     /**
 231:      * Tests this renderer for equality with an arbitrary object.
 232:      * 
 233:      * @param obj  the object (<code>null</code> permitted).
 234:      * 
 235:      * @return A boolean.
 236:      */
 237:     public boolean equals(Object obj) {
 238:         if (obj == this) {
 239:             return true;
 240:         }
 241:         if (!(obj instanceof XYLine3DRenderer)) {
 242:             return false;
 243:         }
 244:         XYLine3DRenderer that = (XYLine3DRenderer) obj;
 245:         if (this.xOffset != that.xOffset) {
 246:             return false;
 247:         }
 248:         if (this.yOffset != that.yOffset) {
 249:             return false;
 250:         }
 251:         if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
 252:             return false;
 253:         }
 254:         return super.equals(obj);
 255:     }
 256:     
 257:     /**
 258:      * Provides serialization support.
 259:      *
 260:      * @param stream  the input stream.
 261:      *
 262:      * @throws IOException  if there is an I/O error.
 263:      * @throws ClassNotFoundException  if there is a classpath problem.
 264:      */
 265:     private void readObject(ObjectInputStream stream) 
 266:             throws IOException, ClassNotFoundException {
 267:         stream.defaultReadObject();
 268:         this.wallPaint = SerialUtilities.readPaint(stream);
 269:     }
 270:     
 271:     /**
 272:      * Provides serialization support.
 273:      *
 274:      * @param stream  the output stream.
 275:      *
 276:      * @throws IOException  if there is an I/O error.
 277:      */
 278:     private void writeObject(ObjectOutputStream stream) throws IOException {
 279:         stream.defaultWriteObject();
 280:         SerialUtilities.writePaint(this.wallPaint, stream);
 281:     }
 282: 
 283: }