KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JSci > swing > JLineTrace


1 package JSci.swing;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import java.awt.geom.Point2D JavaDoc;
6 import java.text.DecimalFormat JavaDoc;
7 import java.text.NumberFormat JavaDoc;
8 import java.text.ParseException JavaDoc;
9 import java.util.Iterator JavaDoc;
10 import java.util.List JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import JSci.awt.*;import JSci.maths.ExtraMath;
13
14 /**
15 * A line trace Swing component.
16 * @version 1.4
17 * @author Mark Hale
18 */

19 public final class JLineTrace extends JDoubleBufferedComponent {
20         /**
21         * Data points.
22         */

23         private final List JavaDoc dataPoints = new ArrayList JavaDoc();
24         /**
25         * Sampling interval.
26         */

27         private float samplingInterval;
28         /**
29         * Axis numbering.
30         */

31         private boolean numbering=true;
32         private NumberFormat JavaDoc xNumberFormat = new DecimalFormat JavaDoc("##0.0");
33         private NumberFormat JavaDoc yNumberFormat = new DecimalFormat JavaDoc("##0.0");
34         /**
35         * Origin.
36         */

37         private Point origin=new Point();
38         /**
39         * Min and max data points.
40         */

41         private float minX,minY,maxX,maxY;
42         /**
43         * Axis scaling.
44         */

45         private float xScale,yScale;
46         private final float xIncPixels = 40.0f;
47         private final float yIncPixels = 40.0f;
48         /**
49         * Padding.
50         */

51         private final int scalePad=5;
52         private final int axisPad=25;
53         private int leftAxisPad;
54         /**
55         * Constructs a line trace.
56         */

57         public JLineTrace(float minx,float maxx,float miny,float maxy) {
58                 addMouseMotionListener(new MouseLineAdapter());
59                 setXExtrema(minx,maxx);
60                 setYExtrema(miny,maxy);
61                 setSamplingInterval(0.2f);
62         }
63         /**
64         * Gets the data sampled by this line trace.
65         */

66         public Graph2DModel getModel() {
67                 final Point2DListModel model=new Point2DListModel();
68                 model.setData(dataPoints);
69                 return model;
70         }
71         /**
72         * Turns axis numbering on/off.
73         */

74         public final void setNumbering(boolean flag) {
75                 numbering=flag;
76                 leftAxisPad=axisPad;
77                 if(numbering && getFont() != null) {
78                         // adjust leftAxisPad to accomodate y-axis numbering
79
final FontMetrics metrics = getFontMetrics(getFont());
80                         final int maxYNumLen = metrics.stringWidth(yNumberFormat.format(maxY));
81                         final int minYNumLen = metrics.stringWidth(yNumberFormat.format(minY));
82                         int yNumPad = Math.max(minYNumLen, maxYNumLen);
83                         if(minX<0.0f) {
84                                 final int negXLen = (int)((Math.max(getSize().width,getMinimumSize().width)-2*(axisPad+scalePad))*minX/(minX-maxX));
85                                 yNumPad = Math.max(yNumPad-negXLen, 0);
86                         }
87                         leftAxisPad += yNumPad;
88                 }
89         }
90         public void addNotify() {
91                 super.addNotify();
92                 // getFont() is now not null
93
// recalculate padding
94
setNumbering(numbering);
95         }
96         /**
97         * Sets the display format used for axis numbering.
98         * Convenience method.
99         * @see #setXNumberFormat(NumberFormat)
100         * @see #setYNumberFormat(NumberFormat)
101         */

102         public final void setNumberFormat(NumberFormat JavaDoc format) {
103                 xNumberFormat = format;
104                 yNumberFormat = format;
105                 setNumbering(numbering);
106         }
107         /**
108         * Sets the display format used for x-axis numbering.
109         */

110         public final void setXNumberFormat(NumberFormat JavaDoc format) {
111                 xNumberFormat = format;
112                 setNumbering(numbering);
113         }
114         /**
115         * Sets the display format used for y-axis numbering.
116         */

117         public final void setYNumberFormat(NumberFormat JavaDoc format) {
118                 yNumberFormat = format;
119                 setNumbering(numbering);
120         }
121         /**
122         * Sets the minimum/maximum values on the x-axis.
123         */

124         public void setXExtrema(float min,float max) {
125                 if(max<min)
126                         throw new IllegalArgumentException JavaDoc("Maximum should be greater than minimum; max = "+max+" and min = "+min);
127                 minX=min;
128                 maxX=max;
129                 rescale();
130         }
131         /**
132         * Sets the minimum/maximum values on the y-axis.
133         */

134         public void setYExtrema(float min,float max) {
135                 if(max<min)
136                         throw new IllegalArgumentException JavaDoc("Maximum should be greater than minimum; max = "+max+" and min = "+min);
137                 minY=min;
138                 maxY=max;
139                 rescale();
140         }
141         /**
142         * Sets the sampling interval.
143         * Smaller values give a more accurate trace, but more susceptible to mouse noise.
144         */

145         public void setSamplingInterval(float interval) {
146                 samplingInterval = interval;
147         }
148         /**
149         * Clears the current trace.
150         */

151         public void clear() {
152                 dataPoints.clear();
153                 redraw();
154         }
155         /**
156         * Reshapes the line trace to the specified bounding box.
157         */

158         public final void setBounds(int x,int y,int width,int height) {
159                 super.setBounds(x,y,width,height);
160                 rescale();
161         }
162         /**
163         * Rescales the line trace.
164         */

165         private void rescale() {
166                 final Dimension s=getMinimumSize();
167                 // Swing optimised
168
final int thisWidth=Math.max(getWidth(),s.width);
169                 final int thisHeight=Math.max(getHeight(),s.height);
170                 xScale = (float) ((double)(thisWidth-(leftAxisPad+axisPad)) / (double)(maxX-minX));
171                 yScale = (float) ((double)(thisHeight-2*axisPad) / (double)(maxY-minY));
172                 origin.x=leftAxisPad-Math.round(minX*xScale);
173                 origin.y=thisHeight-axisPad+Math.round(minY*yScale);
174                 redraw();
175         }
176         /**
177         * Returns the preferred size of this component.
178         */

179         public Dimension getPreferredSize() {
180                 return getMinimumSize();
181         }
182         /**
183         * Returns the minimum size of this component.
184         */

185         public Dimension getMinimumSize() {
186                 return new Dimension(200,200);
187         }
188         /**
189         * Converts a screen point to data coordinates.
190         */

191         private Point2D.Float JavaDoc screenToData(Point p) {
192                 double x = (double)(p.x-origin.x) / (double)xScale;
193                 double y = (double)(origin.y-p.y) / (double)yScale;
194                 return new Point2D.Float JavaDoc((float)x, (float)y);
195         }
196         /**
197         * Converts a data point to screen coordinates.
198         */

199         private Point dataToScreen(Point2D.Float JavaDoc p) {
200                 return new Point(origin.x+Math.round(xScale*p.x),origin.y-Math.round(yScale*p.y));
201         }
202         private Point dataToScreen(float x, float y) {
203                 return new Point(origin.x+Math.round(xScale*x),origin.y-Math.round(yScale*y));
204         }
205         /**
206         * Paint the trace.
207         */

208         protected void offscreenPaint(Graphics g) {
209                 drawAxes(g);
210 // lines
211
Point p1,p2;
212                 Iterator JavaDoc iter = dataPoints.iterator();
213                 if(iter.hasNext()) {
214                         p1 = dataToScreen((Point2D.Float JavaDoc) iter.next());
215                         while(iter.hasNext()) {
216                                 p2 = dataToScreen((Point2D.Float JavaDoc) iter.next());
217                                 g.drawLine(p1.x, p1.y, p2.x, p2.y);
218                                 p1 = p2;
219                         }
220                 }
221         }
222         /**
223         * Draws the graph axes.
224         */

225         private void drawAxes(Graphics g) {
226 // axis - Swing optimised
227
g.setColor(getForeground());
228                 if(minY>0.0f)
229                         g.drawLine(leftAxisPad-scalePad,getHeight()-axisPad,getWidth()-(axisPad-scalePad),getHeight()-axisPad);
230                 else
231                         g.drawLine(leftAxisPad-scalePad,origin.y,getWidth()-(axisPad-scalePad),origin.y);
232                 if(minX>0.0f)
233                         g.drawLine(leftAxisPad,axisPad-scalePad,leftAxisPad,getHeight()-(axisPad-scalePad));
234                 else
235                         g.drawLine(origin.x,axisPad-scalePad,origin.x,getHeight()-(axisPad-scalePad));
236 // numbering
237
if(numbering) {
238                         final FontMetrics metrics=g.getFontMetrics();
239                         final int strHeight=metrics.getHeight();
240 // x-axis numbering
241
float dx = (float) ExtraMath.round((double)xIncPixels/(double)xScale, 1);
242                         if(dx == 0.0f)
243                                 dx = Float.MIN_VALUE;
244                         for(double x=(minX>0.0f)?minX:dx; x<=maxX; x+=dx) {
245                                 String JavaDoc str = xNumberFormat.format((float)x);
246 // add a + prefix to compensate for - prefix in negative number strings when calculating length
247
int strWidth=metrics.stringWidth('+'+str);
248                                 Point p=dataToScreen((float)x, (minY>0.0f)?minY:0.0f);
249                                 g.drawLine(p.x,p.y,p.x,p.y+5);
250                                 g.drawString(str,p.x-strWidth/2,p.y+5+strHeight);
251                         }
252                         for(double x=-dx; x>=minX; x-=dx) {
253                                 String JavaDoc str = xNumberFormat.format((float)x);
254                                 int strWidth=metrics.stringWidth(str);
255                                 Point p=dataToScreen((float)x, (minY>0.0f)?minY:0.0f);
256                                 g.drawLine(p.x,p.y,p.x,p.y+5);
257                                 g.drawString(str,p.x-strWidth/2,p.y+5+strHeight);
258                         }
259 // y-axis numbering
260
float dy = (float) ExtraMath.round((double)yIncPixels/(double)yScale, 1);
261                         if(dy == 0.0f)
262                                 dy = Float.MIN_VALUE;
263                         for(double y=(minY>0.0f)?minY:dy; y<=maxY; y+=dy) {
264                                 String JavaDoc str = yNumberFormat.format((float)y);
265                                 int strWidth=metrics.stringWidth(str);
266                                 Point p=dataToScreen((minX>0.0f)?minX:0.0f, (float)y);
267                                 g.drawLine(p.x,p.y,p.x-5,p.y);
268                                 g.drawString(str,p.x-8-strWidth,p.y+strHeight/4);
269                         }
270                         for(double y=-dy; y>=minY; y-=dy) {
271                                 String JavaDoc str = yNumberFormat.format((float)y);
272                                 int strWidth=metrics.stringWidth(str);
273                                 Point p=dataToScreen((minX>0.0f)?minX:0.0f, (float)y);
274                                 g.drawLine(p.x,p.y,p.x-5,p.y);
275                                 g.drawString(str,p.x-8-strWidth,p.y+strHeight/4);
276                         }
277                 }
278         }
279         class MouseLineAdapter extends MouseMotionAdapter {
280                 public void mouseDragged(MouseEvent evt) {
281                         Point2D.Float JavaDoc p=screenToData(evt.getPoint());
282                         final int i = dataPoints.size()-1;
283                         if(p.x >= i*samplingInterval+minX && p.x <= maxX) {
284                                 dataPoints.add(p);
285                         }
286                         redraw();
287                 }
288         }
289 }
290
Popular Tags