KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > krysalis > jcharts > nonAxisChart > RadarChart


1 /***********************************************************************************************
2  * Copyright 2002 (C) Nathaniel G. Auvil. All Rights Reserved.
3  *
4  * Redistribution and use of this software and associated documentation ("Software"), with or
5  * without modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain copyright statements and notices.
8  * Redistributions must also contain a copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
11  * conditions and the following disclaimer in the documentation and/or other materials
12  * provided with the distribution.
13  *
14  * 3. The name "jCharts" or "Nathaniel G. Auvil" must not be used to endorse or promote
15  * products derived from this Software without prior written permission of Nathaniel G.
16  * Auvil. For written permission, please contact nathaniel_auvil@users.sourceforge.net
17  *
18  * 4. Products derived from this Software may not be called "jCharts" nor may "jCharts" appear
19  * in their names without prior written permission of Nathaniel G. Auvil. jCharts is a
20  * registered trademark of Nathaniel G. Auvil.
21  *
22  * 5. Due credit should be given to the jCharts Project (http://jcharts.sourceforge.net/).
23  *
24  * THIS SOFTWARE IS PROVIDED BY Nathaniel G. Auvil AND CONTRIBUTORS ``AS IS'' AND ANY
25  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27  * jCharts OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
33  ************************************************************************************************/

34
35 package org.krysalis.jcharts.nonAxisChart;
36
37
38 import java.awt.Color JavaDoc;
39 import java.awt.Graphics2D JavaDoc;
40 import java.awt.Paint JavaDoc;
41 import java.awt.Polygon JavaDoc;
42 import java.awt.Rectangle JavaDoc;
43 import java.awt.RenderingHints JavaDoc;
44 import java.awt.font.FontRenderContext JavaDoc;
45 import java.awt.geom.Point2D JavaDoc;
46 import java.awt.geom.Rectangle2D JavaDoc;
47
48 import org.krysalis.jcharts.Chart;
49 import org.krysalis.jcharts.chartData.interfaces.IRadarChartDataSet;
50 import org.krysalis.jcharts.chartData.processors.RadarChartDataProcessor;
51 import org.krysalis.jcharts.properties.ChartProperties;
52 import org.krysalis.jcharts.properties.LegendProperties;
53 import org.krysalis.jcharts.properties.RadarChartProperties;
54 import org.krysalis.jcharts.properties.util.ChartFont;
55
56
57 /*************************************************************************************
58  * Represents a radar chart a.k.a. spider chart
59  *
60  * @author Rami Hansenne
61  * @version $Id: RadarChart.java,v 1.3 2003/08/28 14:36:28 nicolaken Exp $
62  * @since 1.0.0
63  ************************************************************************************/

64
65 public class RadarChart
66     extends Chart
67 {
68
69     private IRadarChartDataSet iRadarChartDataSet;
70     private RadarChartDataProcessor radarChartDataProcessor;
71     private RadarChartProperties props;
72     private double radius, step;
73     private Point2D JavaDoc center;
74
75     // scale max value and increment
76
private double scaleMax, scaleIncrement;
77
78     // default number of scale increments if no user defined increment
79
private static final int DEFAULT_NR_OF_INCREMENTS = 10;
80
81
82     /************************************************************************************************
83      * Constructor
84      *
85      * @param iRadarChartDataSet
86      * @param legendProperties
87      * @param chartProperties general chart properties
88      * @param pixelWidth
89      * @param pixelHeight
90      ************************************************************************************************/

91     public RadarChart( IRadarChartDataSet iRadarChartDataSet,
92                              LegendProperties legendProperties,
93                              ChartProperties chartProperties,
94                              int pixelWidth,
95                              int pixelHeight )
96     {
97         super( legendProperties, chartProperties, pixelWidth, pixelHeight );
98         this.iRadarChartDataSet = iRadarChartDataSet;
99         props = (RadarChartProperties) iRadarChartDataSet.getChartTypeProperties();
100         if( props == null )
101         {
102             props = new RadarChartProperties();
103         }
104     }
105
106
107     /************************************************************************************************
108      * Draws the chart
109      *
110      ************************************************************************************************/

111     protected void renderChart()
112     {
113         Graphics2D JavaDoc g2d = getGraphics2D();
114
115         // turn anti-aliasing on
116
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
117
118
119 //todo : render legend, use scale processor classes,...
120

121         FontRenderContext JavaDoc fontRenderContext = super.getGraphics2D().
122             getFontRenderContext();
123
124         //---render the TITLE. If no title, this will return zero.
125
float chartTitleHeight = super.renderChartTitle( this.iRadarChartDataSet.
126                                                                          getChartTitle(), fontRenderContext );
127
128         this.radarChartDataProcessor = new RadarChartDataProcessor( this.iRadarChartDataSet );
129         this.radarChartDataProcessor.processData();
130
131         // set scale max value
132
if( Double.isNaN( props.getScaleMaxValue() ) )
133             this.scaleMax = radarChartDataProcessor.getMaxValue();
134         else
135             scaleMax = props.getScaleMaxValue();
136
137         // set scale increment
138
if( Double.isNaN( props.getScaleIncrement() ) )
139             this.scaleIncrement = scaleMax / DEFAULT_NR_OF_INCREMENTS;
140         else
141             scaleIncrement = props.getScaleIncrement();
142
143         //todo : adjust chart space in order to correctly render title & legend
144
Rectangle JavaDoc chartSpace = new Rectangle JavaDoc( getImageWidth(), getImageHeight() );
145
146         center = new Point2D.Double JavaDoc(
147             chartSpace.getWidth() / 2 - chartSpace.getX(),
148             chartSpace.getHeight() / 2 - chartSpace.getY() );
149         radius = Math.min( chartSpace.getWidth(), chartSpace.getHeight() );
150         radius = ( radius - ( radius * 10 ) / 100 ) / 2;
151         step = 2 * Math.PI / iRadarChartDataSet.getNumberOfDataItems();
152
153         if( props.getShowGridLines() )
154         {
155             drawGridLines( g2d );
156         }
157         drawAxis( g2d );
158         drawRadar( g2d );
159     }
160
161
162     private void drawRadar(
163         Graphics2D JavaDoc g )
164     {
165
166         for( int dataset = 0; dataset < iRadarChartDataSet.getNumberOfDataSets();
167               dataset++ )
168         {
169
170             double currentValue;
171             double previousValue = scaleValue( iRadarChartDataSet.getValue( dataset,
172                                                                                                  iRadarChartDataSet.getNumberOfDataItems() -
173                                                                                                  1 ) );
174
175             Paint JavaDoc paint = iRadarChartDataSet.getPaint( dataset );
176
177             for( int di = 0; di < iRadarChartDataSet.getNumberOfDataItems(); di++ )
178             {
179                 currentValue = previousValue;
180                 previousValue = scaleValue( iRadarChartDataSet.getValue( dataset, di ) );
181                 g.setPaint( paint );
182
183                 int c0 = (int) Math.round( center.getX() );
184                 int c1 = (int) Math.round( center.getY() );
185                 int x0 = getX( di + 1, previousValue );
186                 int y0 = getY( di + 1, previousValue );
187                 int x1 = getX( di, currentValue );
188                 int y1 = getY( di, currentValue );
189
190                 if( props.getFillRadar() )
191                 {
192                     Polygon JavaDoc p = new Polygon JavaDoc();
193                     p.addPoint( c0, c1 );
194                     p.addPoint( x0, y0 );
195                     p.addPoint( x1, y1 );
196                     // make color translucent
197
if( paint instanceof Color JavaDoc )
198                     {
199                         Color JavaDoc color = (Color JavaDoc) paint;
200                         g.setPaint( new Color JavaDoc( color.getRed(), color.getGreen(),
201                                                       color.getBlue(), 100 ) );
202                     }
203                     g.fillPolygon( p );
204                     g.setPaint( paint );
205                 }
206                 g.drawLine( x0, y0, x1, y1 );
207             }
208         }
209     }
210
211
212     private void drawGridLines( Graphics2D JavaDoc g )
213     {
214         g.setColor( Color.lightGray );
215         for( int di = 0; di < iRadarChartDataSet.getNumberOfDataItems();
216               di++ )
217         {
218             for( double i = scaleIncrement; i <= scaleMax; i += scaleIncrement )
219             {
220                 double pos = scaleValue( i );
221                 g.drawLine(
222                     getX( di + 1, pos ),
223                     getY( di + 1, pos ),
224                     getX( di, pos ),
225                     getY( di, pos ) );
226             }
227         }
228     }
229
230
231     private void drawAxis( Graphics2D JavaDoc g )
232     {
233         g.setColor( Color.darkGray );
234         for( int index = 0; index < iRadarChartDataSet.getNumberOfDataItems();
235               index++ )
236         {
237             String JavaDoc label = iRadarChartDataSet.getAxisLabel( index );
238             g.drawLine(
239                 (int) center.getX(),
240                 (int) center.getY(),
241                 getX( index, 1 ),
242                 getY( index, 1 ) );
243
244             Rectangle2D JavaDoc bounds = g.getFontMetrics().getStringBounds( label, g );
245
246             // draw axis label
247
ChartFont cfont = props.getTitleChartFont();
248             if( cfont != null )
249             {
250                 g.setFont( cfont.getFont() );
251
252             }
253             g.drawString(
254                 label,
255                 (int) ( getX( index + 1, 1 ) - bounds.getWidth() / 2 ),
256                 getY( index + 1, 1 ) );
257         }
258
259         // draw gridline labels
260
g.setColor( Color.darkGray );
261         g.setFont( ChartFont.DEFAULT_AXIS_VALUE.getFont() );
262         int selectedLine = (int) iRadarChartDataSet.getNumberOfDataItems() / 2;
263         for( double i = scaleIncrement; i <= scaleMax; i += scaleIncrement )
264         {
265             double pos = scaleValue( i );
266             Rectangle2D JavaDoc bounds = g.getFont().getStringBounds( "1",
267                                                                               g.getFontRenderContext() );
268             g.drawString( props.getGridLabelFormat().format( i ),
269                               getX( selectedLine, pos ),
270                               (int) Math.round( getY( selectedLine, pos ) + bounds.getHeight() ) );
271         }
272
273     }
274
275
276     private int getX( int dataset, double factor )
277     {
278         return (int) Math.round( center.getX() + radius * factor * Math.sin( step * dataset ) );
279     }
280
281
282     private int getY( int dataset, double factor )
283     {
284         return (int) Math.round( center.getY() + radius * factor * Math.cos( step * dataset ) );
285     }
286
287
288     private double scaleValue( double value )
289     {
290         if( value > scaleMax )
291             value = scaleMax;
292         if( scaleMax == 0 )
293             return 0;
294         return value / scaleMax;
295     }
296
297 }
298
Popular Tags