KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > progra > charting > CoordSystem


1 /*
2     JOpenChart Java Charting Library and Toolkit
3     Copyright (C) 2001 Sebastian Müller
4     http://jopenchart.sourceforge.net
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2.1 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     Lesser General Public License for more details.
15
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20     CoordSystem.java
21     Created on 26. Juni 2001, 22:49
22  */

23
24 package de.progra.charting;
25
26 import de.progra.charting.render.AbstractRenderer;
27 import de.progra.charting.render.ChartRenderingHints;
28 import java.awt.Rectangle JavaDoc;
29 import java.awt.geom.Point2D JavaDoc;
30 import java.awt.geom.Rectangle2D JavaDoc;
31 import java.awt.geom.Line2D JavaDoc;
32 import java.awt.geom.AffineTransform JavaDoc;
33 import java.awt.Graphics2D JavaDoc;
34 import java.awt.Dimension JavaDoc;
35 import java.awt.Color JavaDoc;
36 import java.awt.Font JavaDoc;
37 import java.awt.font.FontRenderContext JavaDoc;
38 import java.awt.font.TextLayout JavaDoc;
39 import java.text.DecimalFormat JavaDoc;
40 import de.progra.charting.model.ChartDataModel;
41 import de.progra.charting.model.ChartDataModelConstraints;
42
43
44 /** This class defines a coordinate system. The CoordSystem class computes
45  * an AffineTransform for each y-axis, which translates the user space
46  * coordinates (ie. the data value coordinates) into pixel space coordinates.
47  * These AffineTransform classes make the PixelToPointTranslator obsolete,
48  * since it provides more flexibility. <code>getDefaultTransform</code> always
49  * computes the default transformation, whereas you can set another
50  * transformation via <code>setTransform</code>. This will be used to implement
51  * zooming and panning in the Swing classes.<p>
52  * All classes incl. this one, which render data will use the transformations
53  * to translate the coordinates. The transformations are not set up on
54  * instantiation of a CoordSystem, instead they're computed when setBounds
55  * is called, because they need this information of course. Afterwards you
56  * can set your own transformation or even better you can manipulate the
57  * existing ones by pre- or postconcatenating another AffineTransform.
58  */

59 public class CoordSystem extends AbstractRenderer {
60     
61     /** The x-axis caption string. */
62     protected String JavaDoc xaxis_unit = "x";
63     /** The y-axis caption string. */
64     protected String JavaDoc yaxis_unit = "y";
65     
66     /** The Font used in the CoordSystem. */
67     protected Font JavaDoc font = new Font JavaDoc("sans", Font.PLAIN, 9);
68     
69     /** FontRenderContext used througout the CoordSystem*/
70     protected final FontRenderContext JavaDoc frc = new FontRenderContext JavaDoc(null, false, false);
71     /** DecimalFormat used throught on the Yaxis of the CoordSystem*/
72     protected DecimalFormat JavaDoc dfY;
73     /** DecimalFormat used throught on the Xaxis of the CoordSystem*/
74     protected DecimalFormat JavaDoc dfX;
75     /** if true, the arrows will be drawn at the end of the axi*/
76     protected boolean shouldDrawArrows = true;
77     /** if true, the increment will be painted at each tick mark*/
78     protected boolean shouldPaintAltTick = true;
79     /** if true only the tick will be painted on the yaxis. Alternately, if false, a
80      * light grey line will paint across the background of the chart.*/

81     protected boolean shouldPaintOnlyTick = true;
82     
83     /** If true, the labels will be painted. If false, only the ticks will display. */
84     protected boolean shouldPaintLabels = true;
85     
86     /** The left margin */
87     protected int leftmargin = 50;
88     /** The top margin. */
89     protected int topmargin = 20;
90     
91     /** The right margin. */
92     protected int rightmargin = 30;
93     /** The bottom margin. */
94     protected int bottommargin = 30;
95     /** The minimal margin constant. */
96     public final int MINIMALMARGIN = 20;
97     /** The arrow length constant. */
98     public final int ARROWLENGTH = 15;
99     
100     /** The ChartDataModel constraints of the first y-axis and the x-axis. */
101     protected ChartDataModelConstraints constraints;
102     /** The ChartDataModel constraints of the second y-axis and the x-axis. */
103     protected ChartDataModelConstraints constraints2;
104     
105     /** The DataModel class. */
106     protected ChartDataModel model;
107     
108     /** The utilities class, which contains all the rendering methods etc. */
109     protected CoordSystemUtilities c;
110     
111     /** The xaxis.*/
112     protected Axis xaxis;
113     /** The first y-axis. */
114     protected Axis yaxis;
115     /** The second y-axis. */
116     protected Axis yaxis2;
117     
118     /** The multiplication matrix for the first y-axis and the x-axis. */
119     protected AffineTransform JavaDoc y1transform;
120     /** The multiplication matrix for the second y-axis and the x-axis. */
121     protected AffineTransform JavaDoc y2transform;
122     
123     /** the axis binding constant for the first y-axis
124      */

125     public static final int FIRST_YAXIS = 0;
126     /** the axis binding constant for the second y-axis
127      */

128     public static final int SECOND_YAXIS = 1;
129     
130     /** Creates a new CoordSystem using the given model constraints.
131      * Also creates default linear x and y-axis. Note that the length
132      * of the axis are set on the first call to
133      * setBounds().
134      * @param c the ChartDataModel needed to compute the DataConstraints.
135      */

136     public CoordSystem(ChartDataModel cdm) {
137         this.constraints = cdm.getChartDataModelConstraints(FIRST_YAXIS);
138         this.constraints2 = cdm.getChartDataModelConstraints(SECOND_YAXIS);
139         
140         this.model = cdm;
141         
142         xaxis = new Axis(Axis.HORIZONTAL, constraints);
143         yaxis = new Axis(Axis.VERTICAL, constraints);
144         
145         c = new CoordSystemUtilities(this, constraints, constraints2, model);
146         
147         dfY = new DecimalFormat JavaDoc();
148         dfX = new DecimalFormat JavaDoc();
149     }
150     
151     /** Creates a new CoordSystem using the given model constraints.
152      * Also creates default linear x and y-axis. Note that the length
153      * of the axis are set on the first call to
154      * setBounds().
155      * @param c the ChartDataModel needed to compute the DataConstraints.
156      * @param xtext the x-axis unit
157      * @param ytext the y-axis unit
158      */

159     public CoordSystem(ChartDataModel c, String JavaDoc xunit, String JavaDoc yunit) {
160         this(c);
161
162         setXAxisUnit(xunit);
163         setYAxisUnit(yunit);
164     }
165     
166     /**
167      * Create a new CoordSystem with alternate painting parameters.
168      * @param c the ChartDataModel needed to compute the DataConstraints.
169      * @param drawArrows if true the arrows will be drawn at the end of the axis
170      * @param paintAltYTick if true the caption will paint on alternate ticks of the
171      * yaxis instead of on every one.
172      * @param paintOnlyYTick if true the horizontal lightgray line will <i>not</i>
173      * appear behind the chart at each yaxis tick mark.
174      */

175     public CoordSystem(ChartDataModel c, DecimalFormat JavaDoc yAxisFormat,
176             boolean drawArrows, boolean paintAltYTick, boolean paintOnlyYTick) {
177         this(c);
178         dfY = yAxisFormat;
179         shouldDrawArrows = drawArrows;
180         shouldPaintAltTick = paintAltYTick;
181         shouldPaintOnlyTick = paintOnlyYTick;
182     }
183
184     /** Sets the coordinate transformation for any y-coordinate.
185      * @param at the AffineTransform that transforms the coordinates into pixel
186      * space
187      * @axis defines for which y-axis the transform is computed
188      */

189     public void setTransform(AffineTransform JavaDoc at, int axis) {
190         switch(axis) {
191             case(FIRST_YAXIS): y1transform = at; break;
192             case(SECOND_YAXIS): y2transform = at; break;
193         }
194     }
195     
196     /** Returns the currently defined AffineTransform for any y-axis.
197      * @param axis the y-axis to be used.
198      */

199     public AffineTransform JavaDoc getTransform(int axis) {
200         switch(axis) {
201             case(FIRST_YAXIS): return y1transform;
202             case(SECOND_YAXIS): return y2transform;
203         }
204         
205         return null;
206     }
207     
208     /** This method computes the default transform which transforms the
209      * user space coordinates of this coordinate system to the pixel
210      * space coordinates used in the Graphics object.
211      * All rendering in the CoordinateSystem and the ChartRenderers
212      * will rely on this transform.
213      * @param axis defines which y-axis to use.
214      */

215     public AffineTransform JavaDoc getDefaultTransform(int axis) {
216         double x_pt2px = 0;
217         double y_pt2px = 0;
218         double xcoord0 = 0;
219         double ycoord0 = 0;
220         
221         x_pt2px = 1 / getXAxis().getPointToPixelRatio();
222         //System.out.println("** x_pt2px = "+getXAxis().getPointToPixelRatio());
223
xcoord0 = getBounds().getX() + getLeftMargin() + getXAxis().getPixelForValue(0.0);
224         
225         switch(axis) {
226             case FIRST_YAXIS:
227                 y_pt2px = 1 / getFirstYAxis().getPointToPixelRatio();
228                 ycoord0 = getBounds().getY() + getBounds().getHeight() - getBottomMargin() -
229                 getFirstYAxis().getPixelForValue(0.0);
230                 break;
231             case SECOND_YAXIS:
232                 y_pt2px = 1 / getSecondYAxis().getPointToPixelRatio();
233                 ycoord0 = getBounds().getY() + getBounds().getHeight() - getBottomMargin() -
234                 getSecondYAxis().getPixelForValue(0.0);
235                 break;
236         }
237         return new AffineTransform JavaDoc(x_pt2px, 0f, 0f,
238         -y_pt2px, xcoord0, ycoord0);
239     }
240     
241     /** Sets the x-axis.
242      * @param a the x-axis
243      */

244     public void setXAxis(Axis a) {
245         xaxis = a;
246     }
247     
248     /** Returns the x axis.
249      * @return the x-axis
250      */

251     public Axis getXAxis() {
252         return xaxis;
253     }
254
255     /** Sets the x-axis unit string.
256      * @param xtext the unit string
257      */

258     public void setXAxisUnit(String JavaDoc xunit) {
259         this.xaxis_unit = xunit;
260     }
261     
262     /** Gets the x-axis unit string.
263      * @return the label String
264      */

265     public String JavaDoc getXAxisUnit() {
266         return xaxis_unit;
267     }
268     
269     /** Sets the y-axis unit string.
270      * @param ytext the unit string
271      */

272     public void setYAxisUnit(String JavaDoc yunit) {
273         this.yaxis_unit = yunit;
274     }
275     
276     /** Gets the y-axis label.
277      * @return the label String
278      */

279     public String JavaDoc getYAxisUnit() {
280         return yaxis_unit;
281     }
282     
283     /** Sets the font for the axis labels.
284      * @param f the Font to be used
285      */

286     public void setFont(Font JavaDoc f) {
287         font = f;
288     }
289     
290     /** Returns the font used for the axis labels.
291      * @return the Font object
292      */

293     public Font JavaDoc getFont() {
294         return font;
295     }
296
297     /** Sets the left y-axis and computes the matrix transformation.
298      * @param a the left y-axis
299      */

300     public void setFirstYAxis(Axis a) {
301         yaxis = a;
302     }
303     
304     /** Returns the first y-axis.
305      * @return the left y-axis
306      */

307     public Axis getFirstYAxis() {
308         return yaxis;
309     }
310     
311     /** Sets the second y-axis and computes the matrix transformation.
312      * @param a the right y-axis
313      */

314     public void setSecondYAxis(Axis a) {
315         yaxis2 = a;
316     }
317     
318     /** Returns the second y-axis.
319      * @return the right y-axis
320      */

321     public Axis getSecondYAxis() {
322         return yaxis2;
323     }
324     
325     /** Returns the inner margin, ie the bounds minus the margins.
326      * @return a Rectangle object defining the inner bounds.
327      */

328     public Rectangle JavaDoc getInnerBounds() {
329         Rectangle JavaDoc b = getBounds();
330         Rectangle JavaDoc i = new Rectangle JavaDoc((int)b.getX() + getLeftMargin() - 1,
331         (int)b.getY() + getTopMargin() - 1,
332         (int)b.getWidth() - (getLeftMargin() + getRightMargin()) + 2,
333         (int)b.getHeight() - (getTopMargin() + getBottomMargin()) + 2);
334         return i;
335     }
336     
337     /** Computes all margins, initializes the length of the Axis and
338      * calls <code>super.setBounds</code>. Additionally, it sets the
339      * default AffineTransforms for every y-axis.
340      * @param bounds <CODE>Rectangle</CODE> object defining the bounds
341      */

342     public void setBounds(Rectangle JavaDoc bounds) {
343         super.setBounds(bounds);
344     
345     setRightMargin(c.computeRightMargin());
346     setLeftMargin(c.computeLeftMargin());
347     
348     setTopMargin(c.computeTopMargin());
349     setBottomMargin(c.computeBottomMargin());
350         
351         xaxis.setLength((int)(bounds.getWidth()) - getLeftMargin() - getRightMargin());
352         //System.out.println("** xaxis.length = "+xaxis.getLength());
353
yaxis.setLength((int)(bounds.getHeight()) - getTopMargin() - getBottomMargin());
354         //System.out.println("** yaxis.length = "+yaxis.getLength());
355
setTransform(getDefaultTransform(FIRST_YAXIS), FIRST_YAXIS);
356         if(yaxis2 != null) {
357             yaxis2.setLength((int)(bounds.getHeight()) - getTopMargin() - getBottomMargin());
358             setTransform(getDefaultTransform(SECOND_YAXIS), SECOND_YAXIS);
359         }
360     }
361     
362     /** Returns the preferred size needed for the renderer.
363      * @return a Dimension with the minimum Integer values.
364      */

365     public Dimension JavaDoc getPreferredSize() {
366         return new Dimension JavaDoc(Integer.MIN_VALUE, Integer.MIN_VALUE);
367     }
368     
369     /** Overrides the method to just call <code>paintDefault</code>.
370      * @param g the <CODE>Graphics2D</CODE> object to paint in
371      */

372     public void render(Graphics2D JavaDoc g) {
373         paintDefault(g);
374     }
375     
376     /** This method is called by the paint method to do the actual painting.
377      * The painting is supposed to start at point (0,0) and the size is
378      * always the same as the preferred size. The paint method performs
379      * the possible scaling.
380      * @param g the <CODE>Graphics2D</CODE> object to paint in
381      */

382     public void paintDefault(Graphics2D JavaDoc g) {
383         g.setColor(Color.black);
384         
385         Line2D JavaDoc x = c.getXAxisLine2D();
386         Line2D JavaDoc y = c.getYAxisLine2D();
387         
388         g.draw(x);
389         g.draw(y);
390         
391         // draw X-Axis Arrow
392
if(shouldDrawArrows) {
393             g.drawLine((int)x.getX2(), (int)x.getY2(), (int)x.getX2() + ARROWLENGTH, (int)x.getY2());
394             g.fillPolygon(new int[] {(int)(x.getX2() + ARROWLENGTH / 3.0),
395                         (int)(x.getX2() + ARROWLENGTH / 3.0),
396                         (int)(x.getX2() + ARROWLENGTH)},
397                         new int[] {(int)x.getY2() - 3, (int)x.getY2() + 3, (int)x.getY2()},
398                         3);
399         }
400         
401         // draw X-Axis label right below the Arrow ?!
402
g.setColor(Color.black);
403         TextLayout JavaDoc layoutX = new TextLayout JavaDoc(getXAxisUnit(), getFont(),
404                                            new FontRenderContext JavaDoc(null, true, false));
405         layoutX.draw(g, (float)x.getX2() + (float)ARROWLENGTH / 3, (float)x.getY2() + (float)layoutX.getBounds().getHeight() + 5);
406         
407         // draw Y-Axis Arrow
408
if(shouldDrawArrows) {
409             g.drawLine((int)y.getX1(), (int)y.getY1(), (int)y.getX1(), (int)y.getY1() - ARROWLENGTH);
410             g.fillPolygon(new int[] {(int)(y.getX1() - 3),
411                         (int)(y.getX1() + 3),
412                         (int)(y.getX1())},
413                         new int[] {(int)(y.getY1() - ARROWLENGTH / 3.0),
414                         (int)(y.getY1() - ARROWLENGTH / 3.0),
415                         (int)y.getY1() - ARROWLENGTH},
416                         3);
417         }
418
419         // draw Y-Axis label right below the Arrow ?!
420
g.setColor(Color.black);
421         TextLayout JavaDoc layoutY = new TextLayout JavaDoc(getYAxisUnit(), getFont(),
422                                            new FontRenderContext JavaDoc(null, true, false));
423         layoutY.draw(g, (float)y.getX1()-6-(float)layoutY.getBounds().getWidth(),
424                         (float)y.getY1() - layoutX.getDescent() - 3);
425         
426         if(getSecondYAxis() != null) {
427             Line2D JavaDoc y2 = c.getSecondYAxisLine2D();
428             g.draw(y2);
429         }
430         
431         if(model.isColumnNumeric())
432             c.drawNumericalXAxisTicks(g);
433         else
434             c.drawXAxisTicks(g);
435         
436         c.drawYAxisTicks(g);
437     }
438     
439     /** Returns a new PointToPixelTranslator for the given axis.
440      * Please notice that this method is deprecated since release 0.92.
441      * The PointToPixelTranslator interface has been replaced with
442      * AffineTransforms.
443      * @param y the y-axis identifier used to choose the right Point / Pixel ratio
444      * @return a PointToPixelTranslator object or null if the resulting
445      * Point is not within the Bounds of the Coordinate System
446      * @deprecated
447      */

448     public PointToPixelTranslator getPointToPixelTranslator(int yaxis) {
449         final Axis x = this.getXAxis();
450         final Axis y;
451         if(yaxis == CoordSystem.FIRST_YAXIS)
452             y = this.getFirstYAxis();
453         else
454             y = this.getSecondYAxis();
455         
456         return new PointToPixelTranslator() {
457             public Point2D JavaDoc getPixelCoord(Point2D JavaDoc pt) {
458                 double x0 = 0.0;
459                 double y0 = 0.0;
460                 
461                 x0 = getBounds().getX()+getLeftMargin()+
462                 x.getPixelForValue(pt.getX());
463                 
464                 y0 = getBounds().getY()+getBounds().getHeight() - getBottomMargin() -
465                 y.getPixelForValue(pt.getY());
466                 Point2D JavaDoc p = new Point2D.Double JavaDoc(x0, y0);
467                 
468                 if(getInnerBounds().contains(p))
469                     return p;
470                 else
471                     return null;
472             }
473         };
474     }
475     
476     /** Returns the left margin. */
477     protected int getLeftMargin() {
478         return leftmargin;
479     }
480     
481     /** Returns the right margin. */
482     protected int getRightMargin() {
483         return rightmargin;
484     }
485     
486     /** Returns the top margin. */
487     protected int getTopMargin() {
488         return topmargin;
489     }
490     
491     /** Returns the bottom margin. */
492     protected int getBottomMargin() {
493         return bottommargin;
494     }
495     
496     /** Sets the left margin.
497      * @param margin the new margin value
498      */

499     protected void setLeftMargin(int margin) {
500         leftmargin = margin;
501     }
502     
503     /** Sets the right margin.
504      * @param margin the new margin value
505      */

506     protected void setRightMargin(int margin) {
507         rightmargin = margin;
508     }
509     
510     /** Sets the top margin.
511      * @param margin the new margin value
512      */

513     protected void setTopMargin(int margin) {
514         topmargin = margin;
515     }
516     
517     /** Sets the bottom margin.
518      * @param margin the new margin value
519      */

520     public void setBottomMargin(int margin) {
521         bottommargin = margin;
522     }
523     
524     /** Returns the FontRenderContext used througout the CoordSystem*/
525     public FontRenderContext JavaDoc getFontRenderContext() {
526         return frc;
527     }
528     
529     /** Returns the DecimalFormat used throught on the Yaxis of the CoordSystem*/
530     public DecimalFormat JavaDoc getYDecimalFormat() {
531         return dfY;
532     }
533     
534     /** Returns the DecimalFormat used throught on the Xaxis of the CoordSystem*/
535     public DecimalFormat JavaDoc getXDecimalFormat() {
536         return dfX;
537     }
538     
539     /** if true, the arrows will be drawn at the end of the axis*/
540     public boolean isDrawArrows() {
541         return shouldDrawArrows;
542     }
543     
544     /** if true, the increment will be painted at each tick mark*/
545     public boolean isPaintAltTick() {
546         return shouldPaintAltTick;
547     }
548     
549     /** if true only the tick will be painted on the yaxis. Alternately a
550      * light grey line will paint across the background of the chart.*/

551     public boolean isPaintOnlyTick() {
552         return shouldPaintOnlyTick;
553     }
554    
555     public boolean isPaintLabels() {
556         return shouldPaintLabels;
557     }
558     
559     public void setPaintLabels(boolean label) {
560         shouldPaintLabels = label;
561     }
562     
563     /** Returns the used ChartDataModelConstraints. */
564     public ChartDataModelConstraints getChartDataModelConstraints(int axis) {
565         if(axis == FIRST_YAXIS)
566             return constraints;
567         else if(axis == SECOND_YAXIS)
568             return constraints2;
569         else
570             return null;
571     }
572 }
573
Popular Tags