KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > krysalis > jcharts > axisChart > axis > XAxis


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
36 package org.krysalis.jcharts.axisChart.axis;
37
38
39 import org.krysalis.jcharts.axisChart.AxisChart;
40 import org.krysalis.jcharts.properties.*;
41 import org.krysalis.jcharts.test.HTMLGenerator;
42 import org.krysalis.jcharts.test.HTMLTestable;
43 import org.krysalis.jcharts.chartData.interfaces.IAxisPlotDataSet;
44 import org.krysalis.jcharts.chartData.interfaces.IAxisDataSeries;
45 import org.krysalis.jcharts.types.ChartType;
46
47 import java.awt.*;
48 import java.awt.geom.Line2D JavaDoc;
49 import java.lang.reflect.Field JavaDoc;
50 import java.util.Iterator JavaDoc;
51
52
53 /*************************************************************************************
54  *
55  * @author Nathaniel Auvil, John Thomson
56  * @version $Id: XAxis.java,v 1.3 2003/06/29 14:14:28 nathaniel_auvil Exp $
57  ************************************************************************************/

58 public class XAxis extends Axis implements HTMLTestable
59 {
60     //---indicates which labels to display 1=every, 2=every other, 3=every third, etc...
61
private int xLabelFilter = 1;
62
63     //---for some charts such as line, point, area, etc... we want to start plot at y-axis
64
private boolean startTicksAtAxis;
65
66
67     /**************************************************************************************************
68      *
69      * @param axisChart
70      * @param numberOfScaleItems
71      ***************************************************************************************************/

72     public XAxis( AxisChart axisChart, int numberOfScaleItems )
73     {
74         super( axisChart, numberOfScaleItems );
75     }
76
77
78     /*************************************************************************************************
79      * Computes the minimum pixel height required for the X-Axis.
80      * Includes space, if needed, for: axis title + padding, axis values + tick padding, and tick marks.
81      *
82      * @param axisTitle
83      **************************************************************************************************/

84     public void computeMinimumHeightNeeded( String JavaDoc axisTitle )
85     {
86         float heightNeeded = 0;
87         AxisProperties axisProperties = super.getAxisChart().getAxisProperties();
88         AxisTypeProperties axisTypeProperties = axisProperties.getXAxisProperties();
89
90
91         if( axisTypeProperties.showAxisLabels() )
92         {
93             if( axisProperties.xAxisLabelsAreVertical() )
94             {
95                 //---widest label for vertical labels
96
//heightNeeded = axisChartDataProcessor.getAxisLabelProcessor().getWidestLabel();
97
heightNeeded = super.getAxisLabelsGroup().getWidestLabel();
98             }
99             else
100             {
101                 //---tallest label for horizontal labels
102
//heightNeeded = axisChartDataProcessor.getAxisLabelProcessor().getTallestLabel();
103
heightNeeded = super.getAxisLabelsGroup().getTallestLabel();
104
105                 //---not sure why i need more padding
106
heightNeeded += 3;
107             }
108         }
109
110
111         if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
112         {
113             if( axisTypeProperties.showAxisLabels() )
114             {
115                 //---add the padding between scale labels and tick marks
116
heightNeeded += axisTypeProperties.getPaddingBetweenLabelsAndTicks();
117             }
118
119             //---add width of tick marks
120
heightNeeded += axisTypeProperties.getAxisTickMarkPixelLength();
121         }
122         else
123         {
124             //---use specified distance between labels and axis
125
heightNeeded += axisTypeProperties.getPaddingBetweenAxisAndLabels();
126         }
127
128
129         //---include axis title height if needed. Remember it is vertical for y-axis
130
if( axisTitle != null )
131         {
132             super.computeAxisTitleDimensions( axisTitle, axisTypeProperties.getTitleChartFont() );
133             heightNeeded += super.getTitleHeight();
134             heightNeeded += axisTypeProperties.getPaddingBetweenAxisTitleAndLabels();
135         }
136
137         super.setMinimumHeightNeeded( heightNeeded );
138     }
139
140
141     /*************************************************************************************************
142      * Computes the number of pixels between each value on the axis.
143      *
144      **************************************************************************************************
145      public void computeScalePixelWidth( int numberOfValuesOnXAxis )
146      {
147      super.setScalePixelWidth( super.getPixelLength() / numberOfValuesOnXAxis );
148      }
149
150
151      /****************************************************************************************************
152      *
153      * @param axisTitle
154      * @param graphics2D
155      * @param axisTypeProperties
156      ***************************************************************************************************/

157     private void renderAxisTitle( String JavaDoc axisTitle, Graphics2D graphics2D, AxisTypeProperties axisTypeProperties )
158     {
159         if( axisTitle != null )
160         {
161             float titleX;
162             float titleY = super.getAxisChart().getYAxis().getOrigin() + this.getMinimumHeightNeeded() - super.getTitleHeight();
163
164             //---if title is larger than the axis itself, place at top.
165
if( super.getTitleWidth() > super.getPixelLength() )
166             {
167                 titleX = ((super.getAxisChart().getImageWidth() - super.getTitleWidth()) / 2);
168             }
169             //---else, center on XAxis.
170
else
171             {
172                 titleX = super.getOrigin() + ((super.getPixelLength() - super.getTitleWidth()) / 2);
173             }
174
175
176             axisTypeProperties.getAxisTitleChartFont().setupGraphics2D( graphics2D );
177             graphics2D.drawString( axisTitle, titleX, titleY );
178         }
179     }
180
181
182     /***************************************************************************************
183      * Determines if we should start x-axis ticks at the y-axis or space it out a half
184      * a scale item width.
185      *
186      * @param iAxisDataSeries
187      * @param axisTypeProperties
188      **************************************************************************************/

189     public void computeShouldTickStartAtYAxis( IAxisDataSeries iAxisDataSeries,
190                                                              AxisTypeProperties axisTypeProperties )
191     {
192         //---if horizontal plot, x-axis is the data axis, so always start data points at y-axis
193
if( axisTypeProperties instanceof DataAxisProperties )
194         {
195             this.startTicksAtAxis= true;
196         }
197         else
198         {
199             this.startTicksAtAxis= true;
200
201             //---else, there are a couple of plots we do not start x-axis values at the y-axis
202
IAxisPlotDataSet iAxisPlotDataSet;
203             Iterator JavaDoc iterator= iAxisDataSeries.getIAxisPlotDataSetIterator();
204 //todo what about combo charts?
205
while( iterator.hasNext() )
206             {
207                 iAxisPlotDataSet= (IAxisPlotDataSet) iterator.next();
208                 if( iAxisPlotDataSet.getChartType().equals( ChartType.BAR )
209                     || iAxisPlotDataSet.getChartType().equals( ChartType.BAR_CLUSTERED )
210                     || iAxisPlotDataSet.getChartType().equals( ChartType.BAR_STACKED )
211                     || iAxisPlotDataSet.getChartType().equals( ChartType.LINE )
212                     || iAxisPlotDataSet.getChartType().equals( ChartType.POINT )
213                     || iAxisPlotDataSet.getChartType().equals( ChartType.STOCK ) )
214                 {
215                     this.startTicksAtAxis= false;
216                     break;
217                 }
218             }
219         }
220     }
221
222
223     /***************************************************************************************
224      * Computes the screen pixel location of the first tick mark
225      *
226      **************************************************************************************/

227     public void computeTickStart()
228     {
229         float tickStart= super.getOrigin();
230
231         if( ! this.startTicksAtAxis )
232         {
233             tickStart+= (super.getScalePixelWidth() / 2);
234         }
235
236       super.setTickStart( tickStart );
237     }
238
239
240     /*************************************************************************************************
241      * Computes the number of pixels between each value on the axis.
242      *
243      * @param axisTypeProperties
244      *************************************************************************************************/

245     public void computeScalePixelWidth( AxisTypeProperties axisTypeProperties )
246     {
247         if( this.startTicksAtAxis )
248         {
249             super.computeScalePixelWidthDataAxis( axisTypeProperties );
250         }
251         else
252         {
253             super.setScalePixelWidth( getPixelLength() / this.getNumberOfScaleItems() );
254         }
255     }
256
257
258     /*********************************************************************************************
259      * Renders the YAxis on the passes Graphics2D object
260      *
261      * @param graphics2D
262      * @param axisProperties
263      * @param axisTitle
264      **********************************************************************************************/

265     public void render( Graphics2D graphics2D,
266                               AxisProperties axisProperties,
267                               String JavaDoc axisTitle )
268     {
269         AxisTypeProperties axisTypeProperties = axisProperties.getXAxisProperties();
270
271
272         //---AXIS TITLE
273
this.renderAxisTitle( axisTitle, graphics2D, axisTypeProperties );
274
275         Line2D.Float JavaDoc line2D = new Line2D.Float JavaDoc( super.getTickStart(), 0.0f, super.getTickStart(), 0.0f );
276         float tickY1 = super.getAxisChart().getYAxis().getOrigin();
277         float tickY2 = super.getAxisChart().getYAxis().getOrigin() + axisTypeProperties.getAxisTickMarkPixelLength();
278         float gridLineY1 = super.getAxisChart().getYAxis().getOrigin();
279         float gridLineY2 = super.getAxisChart().getYAxis().getOrigin() - super.getAxisChart().getYAxis().getPixelLength();
280
281
282         float stringX = super.getTickStart();
283         float stringY = super.getAxisChart().getYAxis().getOrigin();
284         if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
285         {
286             stringY += axisTypeProperties.getAxisTickMarkPixelLength() + axisTypeProperties.getPaddingBetweenLabelsAndTicks();
287         }
288         else
289         {
290             stringY += axisTypeProperties.getPaddingBetweenAxisAndLabels();
291         }
292
293
294         if( axisTypeProperties.showAxisLabels() )
295         {
296             //---if the scale labels are horizontal, simply add the tallest label height.
297
//---Otherwise we will have to calculate it when we draw the label
298
if( !axisProperties.xAxisLabelsAreVertical() )
299             {
300                 stringY += super.getAxisLabelsGroup().getTallestLabel();
301                 graphics2D.setFont( axisTypeProperties.getScaleChartFont().getFont() );
302             }
303             else
304             {
305                 stringX -= super.getAxisLabelsGroup().getTextTag( 0 ).getFontDescent();
306                 graphics2D.setFont( axisTypeProperties.getScaleChartFont().deriveFont() );
307             }
308         }
309
310
311         //LOOP
312
//for( int i = 0; i < super.getAxisLabelsGroup().size(); i++ )
313
for( int i = 0; i < super.getNumberOfScaleItems(); i++ )
314         {
315             //---GRID LINES
316
if( axisTypeProperties.getShowGridLines() != AxisTypeProperties.GRID_LINES_NONE )
317             {
318                 if( ( i == 0 && !( axisTypeProperties instanceof DataAxisProperties ) )
319                     || ( i > 0 && ( (axisTypeProperties.getShowGridLines() == AxisTypeProperties.GRID_LINES_ALL) || (axisTypeProperties.getShowGridLines() == AxisTypeProperties.GRID_LINES_ONLY_WITH_LABELS && (i % this.xLabelFilter == 0)) ) ) )
320                 {
321                     line2D.y1 = gridLineY1;
322                     line2D.y2 = gridLineY2;
323
324                     if( i < super.getAxisLabelsGroup().size()
325                         || (i == super.getAxisLabelsGroup().size() && !axisTypeProperties.getShowEndBorder()) )
326                     {
327                         axisTypeProperties.getGridLineChartStroke().draw( graphics2D, line2D );
328                     }
329                 }
330             }
331
332             //---TICK MARKS
333
//if( i != super.getAxisLabelsGroup().size() )
334
if( i != super.getNumberOfScaleItems() )
335             {
336                 if( (axisTypeProperties.getShowTicks() == AxisTypeProperties.TICKS_ALL)
337                     || (axisTypeProperties.getShowTicks() == AxisTypeProperties.TICKS_ONLY_WITH_LABELS
338                     && (i % this.xLabelFilter == 0)) )
339                 {
340                     line2D.y1 = tickY1;
341                     line2D.y2 = tickY2;
342
343                     axisTypeProperties.getTickChartStroke().setupGraphics2D( graphics2D );
344                     graphics2D.draw( line2D );
345                 }
346             }
347
348             line2D.x1 += super.getScalePixelWidth();
349             line2D.x2 = line2D.x1;
350
351
352             //---AXIS LABEL
353
if( axisTypeProperties.showAxisLabels() && (i % this.xLabelFilter == 0) )
354             {
355                 graphics2D.setPaint( axisTypeProperties.getScaleChartFont().getPaint() );
356
357                 if( !axisProperties.xAxisLabelsAreVertical() )
358                 {
359                     //graphics2D.drawString( iDataSeries.getXAxisLabel( i ), stringX - super.getAxisLabelsGroup().getTextTag( i ).getWidth() / 2, stringY );
360
float x = stringX - super.getAxisLabelsGroup().getTextTag( i ).getWidth() / 2;
361
362                     //---we can not only look at the last label as there could be a filter and labels near the last might go off the edge of the screen.
363
if( x + super.getAxisLabelsGroup().getTextTag( i ).getWidth() < super.getAxisChart().getImageWidth() )
364                     {
365                         super.getAxisLabelsGroup().getTextTag( i ).render( graphics2D, x, stringY );
366                     }
367                 }
368                 else
369                 {
370                     float x = stringX + super.getAxisLabelsGroup().getTextTag( i ).getHeight() / 2;
371
372                     //---we can not only look at the last label as there could be a filter and labels near the last might go off the edge of the screen.
373
if( x + super.getAxisLabelsGroup().getTextTag( i ).getHeight() < super.getAxisChart().getImageWidth() )
374                     {
375                         graphics2D.drawString( super.getAxisLabelsGroup().getTextTag( i ).getText(), x, stringY + super.getAxisLabelsGroup().getTextTag( i ).getWidth() );
376                     }
377                 }
378             }
379             stringX += super.getScalePixelWidth();
380         }
381
382
383         //---RIGHT BORDER-----------------------------------------------------------
384
if( axisTypeProperties.getShowEndBorder() )
385         {
386             //---make sure no rounding errors
387
line2D.x1 = super.getOrigin() + super.getPixelLength();
388             line2D.x2 = line2D.x1;
389             line2D.y1 = gridLineY1;
390             line2D.y2 = gridLineY2;
391             axisProperties.getYAxisProperties().getAxisStroke().draw( graphics2D, line2D );
392         }
393
394
395         //---AXIS-------------------------------------------------------------------
396
line2D.x1 = super.getOrigin();
397         line2D.x2 = super.getOrigin() + super.getPixelLength();
398         line2D.y1 = super.getAxisChart().getYAxis().getOrigin();
399         line2D.y2 = line2D.y1;
400         axisTypeProperties.getAxisStroke().setupGraphics2D( graphics2D );
401         graphics2D.draw( line2D );
402
403
404         //---ZERO LINE-----------------------------------------------------------------
405
if( axisTypeProperties instanceof DataAxisProperties )
406         {
407             DataAxisProperties dataAxisProperties = (DataAxisProperties) axisTypeProperties;
408
409             if( dataAxisProperties.showZeroLine()
410                 && super.getScaleCalculator().getMinValue() < 0.0d
411                 && super.getScaleCalculator().getMaxValue() > 0.0d )
412             {
413                 line2D.x1 = super.getZeroLineCoordinate();
414                 line2D.x2 = line2D.x1;
415                 line2D.y1 = super.getAxisChart().getYAxis().getOrigin();
416                 line2D.y2 = super.getAxisChart().getYAxis().getOrigin() - super.getAxisChart().getYAxis().getPixelLength();
417                 dataAxisProperties.getZeroLineChartStroke().draw( graphics2D, line2D );
418             }
419         }
420     }
421
422
423     /************************************************************************************************
424      * Method to compute the filter to use on the x-axis label display so labels do not overlap
425      *
426      *************************************************************************************************/

427     public void computeLabelFilter()
428     {
429         if( super.getAxisChart().getAxisProperties().getXAxisProperties().showAxisLabels() )
430         {
431             float widestLabelSize;
432             AxisTypeProperties axisTypeProperties = super.getAxisChart().getAxisProperties().getXAxisProperties();
433
434             if( super.getAxisChart().getAxisProperties().xAxisLabelsAreVertical() )
435             {
436                 widestLabelSize = super.getAxisLabelsGroup().getTallestLabel();
437             }
438             else
439             {
440                 widestLabelSize = super.getAxisLabelsGroup().getWidestLabel();
441             }
442
443             double numberLabelsCanDisplay = this.getPixelLength() / (widestLabelSize + axisTypeProperties.getPaddingBetweenAxisLabels());
444             this.xLabelFilter = (int) Math.ceil( super.getAxisLabelsGroup().size() / numberLabelsCanDisplay );
445         }
446         else
447         {
448             this.xLabelFilter= 1;
449         }
450     }
451
452
453     /*********************************************************************************************
454      * Enables the testing routines to display the contents of this Object.
455      *
456      * @param htmlGenerator
457      **********************************************************************************************/

458     public void toHTML( HTMLGenerator htmlGenerator )
459     {
460         htmlGenerator.propertiesTableStart( this.getClass().getName() );
461
462         super.toHTML( htmlGenerator );
463
464         Field JavaDoc[] fields = this.getClass().getDeclaredFields();
465         for( int i = 0; i < fields.length; i++ )
466         {
467             try
468             {
469                 htmlGenerator.addField( fields[ i ].getName(), fields[ i ].get( this ) );
470             }
471             catch( IllegalAccessException JavaDoc illegalAccessException )
472             {
473                 illegalAccessException.printStackTrace();
474             }
475         }
476
477         htmlGenerator.propertiesTableEnd();
478     }
479
480
481     /*************************************************************************************************
482      * Takes a value and determines the screen coordinate it should be drawn at. THe only difference
483      * between this and the y-axis is we add to the origin versus subtract from it.
484      *
485      * @param origin
486      * @param value
487      * @param axisMinValue the minimum value on the axis
488      * @return float the screen pixel coordinate
489      **************************************************************************************************/

490     public float computeAxisCoordinate( float origin, double value, double axisMinValue )
491     {
492         double returnValue = origin + (value - axisMinValue) * this.getOneUnitPixelSize();
493 //System.out.println( "computeAxisCoordinate( " + origin + ", " + value + ", " + axisMinValue + " ) = " + returnValue );
494
return (float) returnValue;
495     }
496
497 }
498
Popular Tags