1 /* 2 * Licensed under the GPL License. You may not use this file except in compliance with the License. 3 * You may obtain a copy of the License at 4 * 5 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html 6 * 7 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 8 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 9 * PURPOSE. 10 */ 11 12 /* =========================================================== 13 * JFreeChart : a free chart library for the Java(tm) platform 14 * =========================================================== 15 * 16 * (C) Copyright 2000-2016, by Object Refinery Limited and Contributors. 17 * 18 * Project Info: http://www.jfree.org/jfreechart/index.html 19 * 20 * This library is free software; you can redistribute it and/or modify it 21 * under the terms of the GNU Lesser General Public License as published by 22 * the Free Software Foundation; either version 2.1 of the License, or 23 * (at your option) any later version. 24 * 25 * This library is distributed in the hope that it will be useful, but 26 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 27 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 28 * License for more details. 29 * 30 * You should have received a copy of the GNU Lesser General Public 31 * License along with this library; if not, write to the Free Software 32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 33 * USA. 34 * 35 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 36 * Other names may be trademarks of their respective owners.] 37 * 38 * --------------------- 39 * XYLine3DRenderer.java 40 * --------------------- 41 * (C) Copyright 2005-2008, by Object Refinery Limited. 42 * 43 * Original Author: Thomas Morgner; 44 * Contributor(s): David Gilbert (for Object Refinery Limited); 45 * 46 * Changes 47 * ------- 48 * 14-Jan-2005 : Added standard header (DG); 49 * 01-May-2007 : Fixed equals() and serialization bugs (DG); 50 * 15-Sep-2019 : Copied from original Jfreechart as code obsoleted and necessary for visuals 51 * in Psi Probe without extra rework (JWL); 52 * 53 */ 54 package psiprobe.jfreechart; 55 56 import java.awt.Color; 57 import java.awt.Graphics2D; 58 import java.awt.Paint; 59 import java.awt.Shape; 60 import java.io.IOException; 61 import java.io.ObjectInputStream; 62 import java.io.ObjectOutputStream; 63 import java.io.Serializable; 64 65 import org.jfree.chart.event.RendererChangeEvent; 66 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; 67 import org.jfree.chart.util.PaintUtils; 68 import org.jfree.chart.util.SerialUtils; 69 70 /** 71 * A XYLineAndShapeRenderer that adds a shadow line to the graph to emulate a 3D-effect. 72 */ 73 public class XYLine3DRenderer extends XYLineAndShapeRenderer implements Effect3D, Serializable { 74 75 /** For serialization. */ 76 private static final long serialVersionUID = 588933208243446087L; 77 78 /** The default x-offset for the 3D effect. */ 79 public static final double DEFAULT_X_OFFSET = 12.0; 80 81 /** The default y-offset for the 3D effect. */ 82 public static final double DEFAULT_Y_OFFSET = 8.0; 83 84 /** The default wall paint. */ 85 public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD); 86 87 /** The size of x-offset for the 3D effect. */ 88 private double xOffset; 89 90 /** The size of y-offset for the 3D effect. */ 91 private double yOffset; 92 93 /** The paint used to shade the left and lower 3D wall. */ 94 private transient Paint wallPaint; 95 96 /** 97 * Creates a new renderer. 98 */ 99 public XYLine3DRenderer() { 100 this.wallPaint = DEFAULT_WALL_PAINT; 101 this.xOffset = DEFAULT_X_OFFSET; 102 this.yOffset = DEFAULT_Y_OFFSET; 103 } 104 105 /** 106 * Returns the x-offset for the 3D effect. 107 * 108 * @return The 3D effect. 109 */ 110 @Override 111 public double getXOffset() { 112 return this.xOffset; 113 } 114 115 /** 116 * Returns the y-offset for the 3D effect. 117 * 118 * @return The 3D effect. 119 */ 120 @Override 121 public double getYOffset() { 122 return this.yOffset; 123 } 124 125 /** 126 * Sets the x-offset and sends a {@link RendererChangeEvent} to all registered listeners. 127 * 128 * @param xOffset the x-offset. 129 */ 130 public void setXOffset(double xOffset) { 131 this.xOffset = xOffset; 132 fireChangeEvent(); 133 } 134 135 /** 136 * Sets the y-offset and sends a {@link RendererChangeEvent} to all registered listeners. 137 * 138 * @param yOffset the y-offset. 139 */ 140 public void setYOffset(double yOffset) { 141 this.yOffset = yOffset; 142 fireChangeEvent(); 143 } 144 145 /** 146 * Returns the paint used to highlight the left and bottom wall in the plot background. 147 * 148 * @return The paint. 149 */ 150 public Paint getWallPaint() { 151 return this.wallPaint; 152 } 153 154 /** 155 * Sets the paint used to hightlight the left and bottom walls in the plot background and sends a 156 * {@link RendererChangeEvent} to all registered listeners. 157 * 158 * @param paint the paint. 159 */ 160 public void setWallPaint(Paint paint) { 161 this.wallPaint = paint; 162 fireChangeEvent(); 163 } 164 165 /** 166 * Returns the number of passes through the data that the renderer requires in order to draw the 167 * chart. Most charts will require a single pass, but some require two passes. 168 * 169 * @return The pass count. 170 */ 171 @Override 172 public int getPassCount() { 173 return 3; 174 } 175 176 /** 177 * Returns {@code true} if the specified pass involves drawing lines. 178 * 179 * @param pass the pass. 180 * 181 * @return A boolean. 182 */ 183 @Override 184 protected boolean isLinePass(int pass) { 185 return pass == 0 || pass == 1; 186 } 187 188 /** 189 * Returns {@code true} if the specified pass involves drawing items. 190 * 191 * @param pass the pass. 192 * 193 * @return A boolean. 194 */ 195 @Override 196 protected boolean isItemPass(int pass) { 197 return pass == 2; 198 } 199 200 /** 201 * Returns {@code true} if the specified pass involves drawing shadows. 202 * 203 * @param pass the pass. 204 * 205 * @return A boolean. 206 */ 207 protected boolean isShadowPass(int pass) { 208 return pass == 0; 209 } 210 211 /** 212 * Overrides the method in the subclass to draw a shadow in the first pass. 213 * 214 * @param g2 the graphics device. 215 * @param pass the pass. 216 * @param series the series index (zero-based). 217 * @param item the item index (zero-based). 218 * @param shape the shape. 219 */ 220 @Override 221 protected void drawFirstPassShape(Graphics2D g2, int pass, int series, int item, Shape shape) { 222 if (isShadowPass(pass)) { 223 if (getWallPaint() != null) { 224 g2.setStroke(getItemStroke(series, item)); 225 g2.setPaint(getWallPaint()); 226 g2.translate(getXOffset(), getYOffset()); 227 g2.draw(shape); 228 g2.translate(-getXOffset(), -getYOffset()); 229 } 230 } else { 231 // now draw the real shape 232 super.drawFirstPassShape(g2, pass, series, item, shape); 233 } 234 } 235 236 /** 237 * Tests this renderer for equality with an arbitrary object. 238 * 239 * @param obj the object ({@code null} permitted). 240 * 241 * @return A boolean. 242 */ 243 @Override 244 public boolean equals(Object obj) { 245 if (obj == this) { 246 return true; 247 } 248 if (!(obj instanceof XYLine3DRenderer)) { 249 return false; 250 } 251 XYLine3DRenderer that = (XYLine3DRenderer) obj; 252 if (this.xOffset != that.xOffset || this.yOffset != that.yOffset 253 || !PaintUtils.equal(this.wallPaint, that.wallPaint)) { 254 return false; 255 } 256 return super.equals(obj); 257 } 258 259 /** 260 * Provides serialization support. 261 * 262 * @param stream the input stream. 263 * 264 * @throws IOException if there is an I/O error. 265 * @throws ClassNotFoundException if there is a classpath problem. 266 */ 267 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 268 stream.defaultReadObject(); 269 this.wallPaint = SerialUtils.readPaint(stream); 270 } 271 272 /** 273 * Provides serialization support. 274 * 275 * @param stream the output stream. 276 * 277 * @throws IOException if there is an I/O error. 278 */ 279 private void writeObject(ObjectOutputStream stream) throws IOException { 280 stream.defaultWriteObject(); 281 SerialUtils.writePaint(this.wallPaint, stream); 282 } 283 284 }