KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > renderer > CyclicXYItemRenderer


1 /* ======================================
2  * JFreeChart : a free Java chart library
3  * ======================================
4  *
5  * Project Info: http://www.jfree.org/jfreechart/index.html
6  * Project Lead: David Gilbert (david.gilbert@object-refinery.com);
7  *
8  * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it under the terms
11  * of the GNU Lesser General Public License as published by the Free Software Foundation;
12  * either version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License along with this
19  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * ---------------------------
23  * CyclicXYItemRenderer.java
24  * ---------------------------
25  * (C) Copyright 2003, by Nicolas Brodu and Contributors.
26  *
27  * Original Author: Nicolas Brodu;
28  * Contributor(s): -
29  *
30  * $Id: CyclicXYItemRenderer.java,v 1.1 2003/11/20 08:54:13 brodu Exp $
31  *
32  * Changes
33  * -------
34  * 19-Nov-2003 : Initial import to JFreeChart from the JSynoptic project (NB);
35  *
36  */

37
38 package org.jfree.chart.renderer;
39
40 import java.awt.Graphics2D JavaDoc;
41 import java.awt.geom.Rectangle2D JavaDoc;
42
43 import org.jfree.chart.CrosshairInfo;
44 import org.jfree.chart.axis.CyclicNumberAxis;
45 import org.jfree.chart.axis.ValueAxis;
46 import org.jfree.chart.labels.XYToolTipGenerator;
47 import org.jfree.chart.plot.PlotRenderingInfo;
48 import org.jfree.chart.plot.XYPlot;
49 import org.jfree.chart.urls.XYURLGenerator;
50 import org.jfree.data.DatasetChangeListener;
51 import org.jfree.data.DatasetGroup;
52 import org.jfree.data.XYDataset;
53
54 /**
55  * The Cyclic XY item renderer is specially designed to handle cyclic axis.
56  * While the standard renderer would draw a line across the plot when a cycling occurs, the cyclic
57  * renderer splits the line at each cycle end instead. This is done by interpolating new points at
58  * cycle boundary. Thus, correct appearance is restored.
59  *
60  * The Cyclic XY item renderer works exactly like a standard XY item renderer with non-cyclic axis.
61  *
62  * @author Nicolas Brodu
63  */

64 public class CyclicXYItemRenderer extends StandardXYItemRenderer {
65
66     /** Overloaded contructor. See StandardXYItemRenderer */
67     public CyclicXYItemRenderer() {
68         super();
69     }
70
71     /** Overloaded contructor. See StandardXYItemRenderer */
72     public CyclicXYItemRenderer(int type) {
73         super(type);
74     }
75
76     /** Overloaded contructor. See StandardXYItemRenderer */
77     public CyclicXYItemRenderer(int type, XYToolTipGenerator toolTipGenerator) {
78         super(type, toolTipGenerator);
79     }
80
81     /** Overloaded contructor. See StandardXYItemRenderer */
82     public CyclicXYItemRenderer(int type, XYToolTipGenerator toolTipGenerator,
83             XYURLGenerator urlGenerator) {
84         super(type, toolTipGenerator, urlGenerator);
85     }
86
87     
88     /** Draws the visual representation of a single data item.
89      * When using cyclic axis, do not draw a line from right to left when cycling as would a
90      * standard XY item renderer, but instead draw a line from the previous point to the cycle bound
91      * in the last cycle, and a line from the cycle bound to current point in the current cycle.
92      * @see org.jfree.chart.renderer.XYItemRenderer#drawItem(java.awt.Graphics2D, org.jfree.chart.renderer.XYItemRendererState, java.awt.geom.Rectangle2D, org.jfree.chart.plot.PlotRenderingInfo, org.jfree.chart.plot.XYPlot, org.jfree.chart.axis.ValueAxis, org.jfree.chart.axis.ValueAxis, org.jfree.data.XYDataset, int, int, org.jfree.chart.CrosshairInfo, int)
93      */

94     public void drawItem(Graphics2D JavaDoc g2, XYItemRendererState state,
95             Rectangle2D JavaDoc dataArea, PlotRenderingInfo info, XYPlot plot,
96             ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
97             int series, int item, CrosshairInfo crosshairInfo, int pass) {
98
99         if ((!getPlotLines()) || ((!(domainAxis instanceof CyclicNumberAxis)) && (!(rangeAxis instanceof CyclicNumberAxis))) || (item<=0)) {
100             super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairInfo, pass);
101             return;
102         }
103
104         // get the previous data point...
105
Number JavaDoc xn = dataset.getXValue(series, item - 1);
106         Number JavaDoc yn = dataset.getYValue(series, item - 1);
107         // If null, don't draw line => then delegate to parent
108
if (yn == null || xn == null) {
109             super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairInfo, pass);
110             return;
111         }
112         double[] x = new double[2];
113         double[] y = new double[2];
114         x[0] = xn.doubleValue();
115         y[0] = yn.doubleValue();
116         
117         // get the data point...
118
xn = dataset.getXValue(series, item);
119         yn = dataset.getYValue(series, item);
120         // If null, don't draw line at all
121
if (yn == null || xn == null) {
122             return;
123         }
124         x[1] = xn.doubleValue();
125         y[1] = yn.doubleValue();
126
127         // Now split the segment as needed
128
double xcycleBound = Double.NaN;
129         double ycycleBound = Double.NaN;
130         boolean xBoundMapping = false, yBoundMapping = false;
131         CyclicNumberAxis cnax = null, cnay = null;
132
133         if (domainAxis instanceof CyclicNumberAxis) {
134             cnax = (CyclicNumberAxis)domainAxis;
135             xcycleBound = cnax.getCycleBound();
136             xBoundMapping = cnax.isBoundMappedToLastCycle();
137             // If the segment must be splitted, insert a new point
138
// Strict test forces to have real segments (not 2 equal points) and avoids division by 0
139
if ((x[0]!=x[1]) && ((xcycleBound>=x[0]) && (xcycleBound<=x[1]) || (xcycleBound>=x[1]) && (xcycleBound<=x[0]))) {
140                 double[] nx = new double[3];
141                 double[] ny = new double[3];
142                 nx[0] = x[0]; nx[2] = x[1]; ny[0] = y[0]; ny[2] = y[1];
143                 nx[1] = xcycleBound;
144                 ny[1] = (y[1] - y[0]) * (xcycleBound - x[0]) / (x[1] - x[0]) + y[0];
145                 x = nx; y = ny;
146             }
147         }
148
149         if (rangeAxis instanceof CyclicNumberAxis) {
150             cnay = (CyclicNumberAxis)rangeAxis;
151             ycycleBound = cnay.getCycleBound();
152             yBoundMapping = cnay.isBoundMappedToLastCycle();
153             // The split may occur in either x splitted segments, if any, but not in both
154
if ((y[0]!=y[1]) && ((ycycleBound>=y[0]) && (ycycleBound<=y[1]) || (ycycleBound>=y[1]) && (ycycleBound<=y[0]))) {
155                 double[] nx = new double[x.length+1];
156                 double[] ny = new double[y.length+1];
157                 nx[0] = x[0]; nx[2] = x[1]; ny[0] = y[0]; ny[2] = y[1];
158                 ny[1] = ycycleBound;
159                 nx[1] = (x[1] - x[0]) * (ycycleBound - y[0]) / (y[1] - y[0]) + x[0];
160                 if (x.length==3) {
161                     nx[3] = x[2]; ny[3] = y[2];
162                 }
163                 x = nx; y = ny;
164             }
165             else if ((x.length==3) && (y[1]!=y[2]) && ((ycycleBound>=y[1]) && (ycycleBound<=y[2]) || (ycycleBound>=y[2]) && (ycycleBound<=y[1]))) {
166                 double[] nx = new double[4];
167                 double[] ny = new double[4];
168                 nx[0] = x[0]; nx[1] = x[1]; nx[3] = x[2];
169                 ny[0] = y[0]; ny[1] = y[1]; ny[3] = y[2];
170                 ny[2] = ycycleBound;
171                 nx[2] = (x[2] - x[1]) * (ycycleBound - y[1]) / (y[2] - y[1]) + x[1];
172                 x = nx; y = ny;
173             }
174         }
175         
176         // If the line is not wrapping, then parent is OK
177
if (x.length==2) {
178             super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairInfo, pass);
179             return;
180         }
181
182         OverwriteDataSet newset = new OverwriteDataSet(x,y,dataset);
183
184         if (cnax!=null) {
185             if (xcycleBound==x[0]) cnax.setBoundMappedToLastCycle(x[1] <= xcycleBound);
186             if (xcycleBound==x[1]) cnax.setBoundMappedToLastCycle(x[0] <= xcycleBound);
187         }
188         if (cnay!=null) {
189             if (ycycleBound==y[0]) cnay.setBoundMappedToLastCycle(y[1] <= ycycleBound);
190             if (ycycleBound==y[1]) cnay.setBoundMappedToLastCycle(y[0] <= ycycleBound);
191         }
192         super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, newset, series, 1, crosshairInfo, pass);
193
194         if (cnax!=null) {
195             if (xcycleBound==x[1]) cnax.setBoundMappedToLastCycle(x[2] <= xcycleBound);
196             if (xcycleBound==x[2]) cnax.setBoundMappedToLastCycle(x[1] <= xcycleBound);
197         }
198         if (cnay!=null) {
199             if (ycycleBound==y[1]) cnay.setBoundMappedToLastCycle(y[2] <= ycycleBound);
200             if (ycycleBound==y[2]) cnay.setBoundMappedToLastCycle(y[1] <= ycycleBound);
201         }
202         super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, newset, series, 2, crosshairInfo, pass);
203
204         if (x.length==4) {
205             if (cnax!=null) {
206                 if (xcycleBound==x[2]) cnax.setBoundMappedToLastCycle(x[3] <= xcycleBound);
207                 if (xcycleBound==x[3]) cnax.setBoundMappedToLastCycle(x[2] <= xcycleBound);
208             }
209             if (cnay!=null) {
210                 if (ycycleBound==y[2]) cnay.setBoundMappedToLastCycle(y[3] <= ycycleBound);
211                 if (ycycleBound==y[3]) cnay.setBoundMappedToLastCycle(y[2] <= ycycleBound);
212             }
213             super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, newset, series, 3, crosshairInfo, pass);
214         }
215         
216         if (cnax!=null) cnax.setBoundMappedToLastCycle(xBoundMapping);
217         if (cnay!=null) cnay.setBoundMappedToLastCycle(yBoundMapping);
218     }
219
220     /** A dataset to hold the interpolated points when drawing new lines */
221     protected static class OverwriteDataSet implements XYDataset {
222         
223         protected XYDataset delegateSet;
224         Double JavaDoc [] x, y;
225         
226         public OverwriteDataSet(double [] x, double[] y, XYDataset delegateSet) {
227             this.delegateSet = delegateSet;
228             this.x = new Double JavaDoc[x.length]; this.y = new Double JavaDoc[y.length];
229             for (int i=0; i<x.length; ++i) {
230                 this.x[i] = new Double JavaDoc(x[i]);
231                 this.y[i] = new Double JavaDoc(y[i]);
232             }
233         }
234
235         public int getItemCount(int series) {
236             return x.length;
237         }
238
239         public Number JavaDoc getXValue(int series, int item) {
240             return x[item];
241         }
242
243         public Number JavaDoc getYValue(int series, int item) {
244             return y[item];
245         }
246
247         public int getSeriesCount() {
248             return delegateSet.getSeriesCount();
249         }
250
251         public String JavaDoc getSeriesName(int series) {
252             return delegateSet.getSeriesName(series);
253         }
254
255         public void addChangeListener(DatasetChangeListener listener) {
256             // unused in parent
257
}
258
259         public void removeChangeListener(DatasetChangeListener listener) {
260             // unused in parent
261
}
262
263         public DatasetGroup getGroup() {
264             // unused but must return something, so while we are at it...
265
return delegateSet.getGroup();
266         }
267
268         public void setGroup(DatasetGroup group) {
269             // unused in parent
270
}
271         
272     }
273     
274 }
275
276
277
Popular Tags