001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * --------------------- 028 * XYLine3DRenderer.java 029 * --------------------- 030 * (C) Copyright 2005-2008, by Object Refinery Limited. 031 * 032 * Original Author: Thomas Morgner; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * Changes 036 * ------- 037 * 14-Jan-2005 : Added standard header (DG); 038 * 01-May-2007 : Fixed equals() and serialization bugs (DG); 039 * 040 */ 041 042package org.jfree.chart.renderer.xy; 043 044import java.awt.Color; 045import java.awt.Graphics2D; 046import java.awt.Paint; 047import java.awt.Shape; 048import java.io.IOException; 049import java.io.ObjectInputStream; 050import java.io.ObjectOutputStream; 051import java.io.Serializable; 052 053import org.jfree.chart.Effect3D; 054import org.jfree.chart.event.RendererChangeEvent; 055import org.jfree.io.SerialUtilities; 056import org.jfree.util.PaintUtilities; 057 058/** 059 * A XYLineAndShapeRenderer that adds a shadow line to the graph 060 * to emulate a 3D-effect. 061 */ 062public class XYLine3DRenderer extends XYLineAndShapeRenderer 063 implements Effect3D, Serializable { 064 065 /** For serialization. */ 066 private static final long serialVersionUID = 588933208243446087L; 067 068 /** The default x-offset for the 3D effect. */ 069 public static final double DEFAULT_X_OFFSET = 12.0; 070 071 /** The default y-offset for the 3D effect. */ 072 public static final double DEFAULT_Y_OFFSET = 8.0; 073 074 /** The default wall paint. */ 075 public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD); 076 077 /** The size of x-offset for the 3D effect. */ 078 private double xOffset; 079 080 /** The size of y-offset for the 3D effect. */ 081 private double yOffset; 082 083 /** The paint used to shade the left and lower 3D wall. */ 084 private transient Paint wallPaint; 085 086 /** 087 * Creates a new renderer. 088 */ 089 public XYLine3DRenderer() { 090 this.wallPaint = DEFAULT_WALL_PAINT; 091 this.xOffset = DEFAULT_X_OFFSET; 092 this.yOffset = DEFAULT_Y_OFFSET; 093 } 094 095 /** 096 * Returns the x-offset for the 3D effect. 097 * 098 * @return The 3D effect. 099 */ 100 @Override 101 public double getXOffset() { 102 return this.xOffset; 103 } 104 105 /** 106 * Returns the y-offset for the 3D effect. 107 * 108 * @return The 3D effect. 109 */ 110 @Override 111 public double getYOffset() { 112 return this.yOffset; 113 } 114 115 /** 116 * Sets the x-offset and sends a {@link RendererChangeEvent} to all 117 * registered listeners. 118 * 119 * @param xOffset the x-offset. 120 */ 121 public void setXOffset(double xOffset) { 122 this.xOffset = xOffset; 123 fireChangeEvent(); 124 } 125 126 /** 127 * Sets the y-offset and sends a {@link RendererChangeEvent} to all 128 * registered listeners. 129 * 130 * @param yOffset the y-offset. 131 */ 132 public void setYOffset(double yOffset) { 133 this.yOffset = yOffset; 134 fireChangeEvent(); 135 } 136 137 /** 138 * Returns the paint used to highlight the left and bottom wall in the plot 139 * background. 140 * 141 * @return The paint. 142 */ 143 public Paint getWallPaint() { 144 return this.wallPaint; 145 } 146 147 /** 148 * Sets the paint used to hightlight the left and bottom walls in the plot 149 * background and sends a {@link RendererChangeEvent} to all registered 150 * listeners. 151 * 152 * @param paint the paint. 153 */ 154 public void setWallPaint(Paint paint) { 155 this.wallPaint = paint; 156 fireChangeEvent(); 157 } 158 159 /** 160 * Returns the number of passes through the data that the renderer requires 161 * in order to draw the chart. Most charts will require a single pass, 162 * but some require two passes. 163 * 164 * @return The pass count. 165 */ 166 @Override 167 public int getPassCount() { 168 return 3; 169 } 170 171 /** 172 * Returns <code>true</code> if the specified pass involves drawing lines. 173 * 174 * @param pass the pass. 175 * 176 * @return A boolean. 177 */ 178 @Override 179 protected boolean isLinePass(int pass) { 180 return pass == 0 || pass == 1; 181 } 182 183 /** 184 * Returns <code>true</code> if the specified pass involves drawing items. 185 * 186 * @param pass the pass. 187 * 188 * @return A boolean. 189 */ 190 @Override 191 protected boolean isItemPass(int pass) { 192 return pass == 2; 193 } 194 195 /** 196 * Returns <code>true</code> if the specified pass involves drawing shadows. 197 * 198 * @param pass the pass. 199 * 200 * @return A boolean. 201 */ 202 protected boolean isShadowPass (int pass) { 203 return pass == 0; 204 } 205 206 /** 207 * Overrides the method in the subclass to draw a shadow in the first pass. 208 * 209 * @param g2 the graphics device. 210 * @param pass the pass. 211 * @param series the series index (zero-based). 212 * @param item the item index (zero-based). 213 * @param shape the shape. 214 */ 215 @Override 216 protected void drawFirstPassShape(Graphics2D g2, int pass, int series, 217 int item, Shape shape) { 218 if (isShadowPass(pass)) { 219 if (getWallPaint() != null) { 220 g2.setStroke(getItemStroke(series, item)); 221 g2.setPaint(getWallPaint()); 222 g2.translate(getXOffset(), getYOffset()); 223 g2.draw(shape); 224 g2.translate(-getXOffset(), -getYOffset()); 225 } 226 } 227 else { 228 // now draw the real shape 229 super.drawFirstPassShape(g2, pass, series, item, shape); 230 } 231 } 232 233 /** 234 * Tests this renderer for equality with an arbitrary object. 235 * 236 * @param obj the object (<code>null</code> permitted). 237 * 238 * @return A boolean. 239 */ 240 @Override 241 public boolean equals(Object obj) { 242 if (obj == this) { 243 return true; 244 } 245 if (!(obj instanceof XYLine3DRenderer)) { 246 return false; 247 } 248 XYLine3DRenderer that = (XYLine3DRenderer) obj; 249 if (this.xOffset != that.xOffset) { 250 return false; 251 } 252 if (this.yOffset != that.yOffset) { 253 return false; 254 } 255 if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) { 256 return false; 257 } 258 return super.equals(obj); 259 } 260 261 /** 262 * Provides serialization support. 263 * 264 * @param stream the input stream. 265 * 266 * @throws IOException if there is an I/O error. 267 * @throws ClassNotFoundException if there is a classpath problem. 268 */ 269 private void readObject(ObjectInputStream stream) 270 throws IOException, ClassNotFoundException { 271 stream.defaultReadObject(); 272 this.wallPaint = SerialUtilities.readPaint(stream); 273 } 274 275 /** 276 * Provides serialization support. 277 * 278 * @param stream the output stream. 279 * 280 * @throws IOException if there is an I/O error. 281 */ 282 private void writeObject(ObjectOutputStream stream) throws IOException { 283 stream.defaultWriteObject(); 284 SerialUtilities.writePaint(this.wallPaint, stream); 285 } 286 287}