View Javadoc
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 }