4 import java.awt.Dimension;
5 import java.awt.Graphics;
6 import java.awt.event.MouseEvent;
8 import tim.prune.I18nManager;
9 import tim.prune.data.Altitude;
10 import tim.prune.data.AltitudeRange;
11 import tim.prune.data.Track;
12 import tim.prune.data.TrackInfo;
15 * Chart component for the profile display
17 public class ProfileChart extends GenericChart
19 private double _xScaleFactor = 0.0;
20 private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
21 private static final Color COLOR_LINES = Color.GRAY;
22 private static final Color COLOR_ALT_BARS = Color.BLUE;
23 private static final Color COLOR_SELECTED = Color.RED;
24 private static final Color COLOR_SELECTED_BG = Color.ORANGE;
25 private static final Color COLOR_ALT_SCALE = Color.RED;
30 * @param inTrackInfo Track info object
32 public ProfileChart(TrackInfo inTrackInfo)
35 MINIMUM_SIZE = new Dimension(200, 100);
36 addMouseListener(this);
41 * Override paint method to draw map
42 * @param g Graphics object
44 public void paint(Graphics g)
47 if (_track != null && _track.getNumPoints() > 0)
49 int width = getWidth();
50 int height = getHeight();
51 AltitudeRange altitudeRange = _track.getAltitudeRange();
52 int minAltitude = altitudeRange.getMinimum();
53 int maxAltitude = altitudeRange.getMaximum();
55 // message if no altitudes in track
56 if (minAltitude < 0 || maxAltitude < 0
57 || minAltitude == maxAltitude)
59 g.setColor(COLOR_LINES);
60 g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
65 int numPoints = _track.getNumPoints();
66 _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH) / numPoints;
67 double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) /
68 (altitudeRange.getMaximum() - minAltitude);
69 int barWidth = (int) (_xScaleFactor + 1.0);
70 int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
72 // horizontal lines for scale - set to round numbers eg 500m
73 int lineScale = getLineScale(minAltitude, maxAltitude);
78 g.setColor(COLOR_LINES);
79 while (altitude < maxAltitude)
81 if (altitude > minAltitude)
83 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
84 g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
86 altitude += lineScale;
92 // loop through points
93 Altitude.Format chartFormat = altitudeRange.getFormat();
94 for (int p = 0; p < numPoints; p++)
96 int x = (int) (_xScaleFactor * p);
97 if (p == selectedPoint)
99 g.setColor(COLOR_SELECTED_BG);
100 g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
101 g.setColor(COLOR_SELECTED);
105 g.setColor(COLOR_ALT_BARS);
107 if (_track.getPoint(p).getAltitude().isValid())
109 altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
110 y = (int) (yScaleFactor * (altitude - minAltitude));
111 g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
115 catch (NullPointerException npe) { // ignore, probably due to data being changed
117 // Draw numbers on top of the graph to mark scale
120 int textHeight = g.getFontMetrics().getHeight();
123 g.setColor(COLOR_ALT_SCALE);
124 while (altitude < maxAltitude)
126 if (altitude > minAltitude)
128 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
129 // Limit y so String isn't above border
130 if (y < (BORDER_WIDTH + textHeight))
132 y = BORDER_WIDTH + textHeight;
134 g.drawString(""+altitude, BORDER_WIDTH + 5, y);
136 altitude += lineScale;
144 * Work out the scale for the horizontal lines
145 * @param inMin min altitude of data
146 * @param inMax max altitude of data
147 * @return scale separation, or -1 for no scale
149 private int getLineScale(int inMin, int inMax)
151 if ((inMax - inMin) < 50 || inMax < 0)
155 int numScales = ALTITUDE_SCALES.length;
159 for (int i=0; i<numScales; i++)
161 scale = ALTITUDE_SCALES[i];
166 while (altitude < inMax)
169 if (altitude > inMin)
180 // no suitable scale found so just use minimum
181 return ALTITUDE_SCALES[numScales-1];
186 * Method to inform map that data has changed
187 * @param inTrack track object
189 public void dataUpdated(Track inTrack)
197 * React to click on profile display
199 public void mouseClicked(MouseEvent e)
201 // ignore right clicks
202 if (_track != null && !e.isMetaDown())
204 int xClick = e.getX();
205 int yClick = e.getY();
206 // Check click is within main area (not in border)
207 if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
208 && yClick < (getHeight() - BORDER_WIDTH))
210 // work out which data point is nearest and select it
211 int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
212 _trackInfo.getSelection().selectPoint(pointNum);