diff --git a/MyTracks/res/layout/mytracks_elevation.xml b/MyTracks/res/layout/mytracks_charts.xml
similarity index 100%
rename from MyTracks/res/layout/mytracks_elevation.xml
rename to MyTracks/res/layout/mytracks_charts.xml
diff --git a/MyTracks/res/values/colors.xml b/MyTracks/res/values/colors.xml
index 1801e61b8..590c1bd59 100644
--- a/MyTracks/res/values/colors.xml
+++ b/MyTracks/res/values/colors.xml
@@ -30,18 +30,22 @@ limitations under the License.
- #FF00AA00
- #8000AA00
+ #FF339933
+ #40B3CFB3
-
- #FF401465
- #40401465
+
+ #FF0066FF
+ #40C8E0FF
+
+
+ #FFCC3300
+ #40E88A70
#FFF128F3
#40F128F3
-
- #FFFF0000
- #40FF0000
+
+ #FF401465
+ #40401465
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
index 121615121..25757e541 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
@@ -252,7 +252,7 @@ public class ChartActivity extends Activity implements
setVolumeControlStream(volumeStream);
requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.mytracks_elevation);
+ setContentView(R.layout.mytracks_charts);
ViewGroup layout = (ViewGroup) findViewById(R.id.elevation_chart);
cv = new ChartView(this);
cv.setMode(this.mode);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartValueSeries.java b/MyTracks/src/com/google/android/apps/mytracks/ChartValueSeries.java
index c7706b2ea..57b88125d 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartValueSeries.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartValueSeries.java
@@ -58,22 +58,6 @@ public class ChartValueSeries {
private final int absoluteMax;
private final int[] zoomLevels;
- public int getIntervals() {
- return intervals;
- }
-
- public int getAbsoluteMin() {
- return absoluteMin;
- }
-
- public int getAbsoluteMax() {
- return absoluteMax;
- }
-
- public int[] getZoomLevels() {
- return zoomLevels;
- }
-
public ZoomSettings(int intervals, int[] zoomLevels) {
this.intervals = intervals;
this.absoluteMin = Integer.MAX_VALUE;
@@ -100,6 +84,22 @@ public class ChartValueSeries {
}
}
}
+
+ public int getIntervals() {
+ return intervals;
+ }
+
+ public int getAbsoluteMin() {
+ return absoluteMin;
+ }
+
+ public int getAbsoluteMax() {
+ return absoluteMax;
+ }
+
+ public int[] getZoomLevels() {
+ return zoomLevels;
+ }
/**
* Calculates the interval between markings given the min and max values.
@@ -109,10 +109,10 @@ public class ChartValueSeries {
* @param min the minimum value in the series
* @param max the maximum value in the series
* @return the calculated interval for the given range
- *
- * TODO: Use the absolute values.
*/
public int calculateInterval(double min, double max) {
+ min = Math.min(min, absoluteMin);
+ max = Math.max(max, absoluteMax);
for (int i = 0; i < zoomLevels.length; ++i) {
int zoomLevel = zoomLevels[i];
int roundedMin = (int)(min / zoomLevel) * zoomLevel;
@@ -205,6 +205,8 @@ public class ChartValueSeries {
min = monitor.getMin();
max = monitor.getMax();
}
+ min = Math.min(min, zoomSettings.getAbsoluteMin());
+ max = Math.max(max, zoomSettings.getAbsoluteMax());
this.interval = zoomSettings.calculateInterval(min, max);
// Round it up.
@@ -214,7 +216,7 @@ public class ChartValueSeries {
if (min < 0) {
effectiveMin -= interval;
}
- spread = getMax() - effectiveMin;
+ spread = effectiveMax - effectiveMin;
}
/**
@@ -234,15 +236,10 @@ public class ChartValueSeries {
}
/**
- * @return The minimum of the rounded up max value and the effective max.
- *
- * TODO: Move to ZoomSettings.
+ * @return The rounded up maximum value
*/
public int getMax() {
- // Return the effective max if no absolute is set
- // or the effective max is less than the absolute.
- return zoomSettings.absoluteMax == Integer.MIN_VALUE || effectiveMax < zoomSettings.absoluteMax
- ? effectiveMax : zoomSettings.absoluteMax;
+ return effectiveMax;
}
/**
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
index aebc19d4c..948b5439d 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
@@ -213,30 +213,33 @@ public class ChartView extends View {
series[SPEED_SERIES] =
new ChartValueSeries(context,
"###,###",
- R.color.blue_transparent,
- R.color.blue,
- new ZoomSettings(MAX_INTERVALS, new int[] {5, 10, 20, 50}),
+ R.color.speed_fill,
+ R.color.speed_border,
+ new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
+ new int[] {5, 10, 20, 50}),
R.string.speed);
series[POWER_SERIES] =
new ChartValueSeries(context,
"###,###",
R.color.power_fill,
R.color.power_border,
- new ZoomSettings(MAX_INTERVALS, 0, 1500, new int[] {5, 50, 100, 200}),
+ new ZoomSettings(MAX_INTERVALS, 0, 1000, new int[] {5, 50, 100, 200}),
R.string.power);
series[CADENCE_SERIES] =
new ChartValueSeries(context,
"###,###",
R.color.cadence_fill,
R.color.cadence_border,
- new ZoomSettings(MAX_INTERVALS, new int[] {5, 10, 25, 50}),
+ new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
+ new int[] {5, 10, 25, 50}),
R.string.cadence);
series[HEART_RATE_SERIES] =
new ChartValueSeries(context,
"###,###",
R.color.heartrate_fill,
R.color.heartrate_border,
- new ZoomSettings(MAX_INTERVALS, new int[] {10, 50}),
+ new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
+ new int[] {25, 50}),
R.string.heart_rate);
}
@@ -302,7 +305,7 @@ public class ChartView extends View {
data.add(theData);
addDataPointInternal(theData);
updateDimensions();
- setupPath();
+ setUpPath();
}
private void addDataPointInternal(double[] theData) {
@@ -333,7 +336,7 @@ public class ChartView extends View {
addDataPointInternal(d);
}
updateDimensions();
- setupPath();
+ setUpPath();
}
/**
@@ -367,7 +370,7 @@ public class ChartView extends View {
public void zoomIn() {
if (canZoomIn()) {
zoomLevel++;
- setupPath();
+ setUpPath();
invalidate();
}
}
@@ -384,7 +387,7 @@ public class ChartView extends View {
scrollX = effectiveWidth * (zoomLevel - 1);
scrollTo(scrollX, 0);
}
- setupPath();
+ setUpPath();
invalidate();
}
}
@@ -555,7 +558,7 @@ public class ChartView extends View {
h = c.getHeight();
effectiveWidth = Math.max(0, w - leftBorder - RIGHT_BORDER);
effectiveHeight = Math.max(0, h - topBorder - bottomBorder);
- setupPath();
+ setUpPath();
}
c.save();
c.drawColor(Color.WHITE);
@@ -589,7 +592,7 @@ public class ChartView extends View {
final float x = getWaypointX(waypoint);
c.drawLine(x, h - bottomBorder, x, topBorder, gridPaint);
- c.translate(x - (markerWidth / 2), markerHeight);
+ c.translate(x - markerWidth / 2, markerHeight);
if (waypoints.get(i).getType() == Waypoint.TYPE_STATISTICS) {
statsMarker.draw(c);
} else {
@@ -607,18 +610,18 @@ public class ChartView extends View {
c.translate(getScrollX(), 0);
drawYAxis(c);
- int x = leftBorder - 5;
+ final int spacer = 5;
+ int x = leftBorder - spacer;
for (ChartValueSeries cvs : series) {
if (cvs.isEnabled() && cvs.hasData()) {
- drawYLabels(cvs, c, x);
+ x -= drawYLabels(cvs, c, x) + spacer;
}
- x -= 30;
}
c.restore();
- if (showPointer && data.size() > 0) {
+ if (showPointer && !data.isEmpty()) {
c.translate(getX(maxX) - pointer.getIntrinsicWidth() / 2,
- (getY(series[0], data.get(data.size() - 1)[1])
- - pointer.getIntrinsicHeight() / 2 - 12));
+ getY(series[0], data.get(data.size() - 1)[1])
+ - pointer.getIntrinsicHeight() / 2 - 12);
pointer.draw(c);
}
}
@@ -643,7 +646,7 @@ public class ChartView extends View {
* Sets up the path that is used to draw the histogram in onDraw(). The path
* needs to be updated any time after the data or histogram dimensions change.
*/
- private synchronized void setupPath() {
+ private synchronized void setUpPath() {
for (ChartValueSeries cvs : series) {
cvs.getPath().reset();
}
@@ -652,17 +655,20 @@ public class ChartView extends View {
}
// All of the data points to the respective series.
- for (int i = 0; i < data.size(); i++) {
+ // TODO: Come up with a better sampling than Math.max(1, (maxZoomLevel - zoomLevel + 1) / 2);
+ int sampling = 1;
+ for (int i = 0; i < data.size(); i += sampling) {
double[] d = data.get(i);
int min = Math.min(series.length, d.length - 1);
-
- for (int j = 0; j < min; j++) {
+ for (int j = 0; j < min; ++j) {
ChartValueSeries cvs = series[j];
Path path = cvs.getPath();
+ int x = getX(d[0]);
+ int y = getY(cvs, d[j + 1]);
if (i == 0) {
- path.moveTo(getX(d[0]), getY(cvs, d[j + 1]));
+ path.moveTo(x, y);
} else {
- path.lineTo(getX(d[0]), getY(cvs, d[j + 1]));
+ path.lineTo(x, y);
}
}
}
@@ -712,11 +718,15 @@ public class ChartView extends View {
for (ChartValueSeries cvs : series) {
cvs.updateDimension();
}
+ // TODO: This is totally broken. Make sure that we calculate based on measureText for each
+ // grid line, as the labels may vary across intervals.
int maxLength = 0;
for (ChartValueSeries cvs : series) {
- maxLength += cvs.getMaxLabelLength();
+ if (cvs.isEnabled() && cvs.hasData()) {
+ maxLength += cvs.getMaxLabelLength();
+ }
}
- leftBorder = 4 + 7 * maxLength;
+ leftBorder = 4 + 8 * maxLength;
effectiveWidth = w - leftBorder - RIGHT_BORDER;
float density = getContext().getResources().getDisplayMetrics().density;
bottomBorder = (int) (density * BOTTOM_BORDER);
@@ -757,11 +767,13 @@ public class ChartView extends View {
}
}
- private void drawYLabels(ChartValueSeries cvs, Canvas c, int x) {
+ private float drawYLabels(ChartValueSeries cvs, Canvas c, int x) {
int interval = cvs.getInterval();
+ float maxTextWidth = 0;
for (int i = 0; i < MAX_INTERVALS; ++i) {
- drawYLabel(cvs, c, x, i * interval + cvs.getMin());
+ maxTextWidth = Math.max(maxTextWidth, drawYLabel(cvs, c, x, i * interval + cvs.getMin()));
}
+ return maxTextWidth;
}
private void drawXLabel(Canvas c, double x, boolean shortFormat) {
@@ -778,13 +790,15 @@ public class ChartView extends View {
labelPaint);
}
- private void drawYLabel(ChartValueSeries cvs, Canvas c, int x, int y) {
+ private float drawYLabel(ChartValueSeries cvs, Canvas c, int x, int y) {
int desiredY = (int) ((y - cvs.getMin()) * effectiveHeight /
(cvs.getInterval() * MAX_INTERVALS));
- desiredY = topBorder + effectiveHeight + FONT_HEIGHT / 2 - desiredY;
+ desiredY = topBorder + effectiveHeight + FONT_HEIGHT / 2 - desiredY - 1;
Paint p = new Paint(cvs.getLabelPaint());
p.setTextAlign(Align.RIGHT);
- c.drawText(cvs.getFormat().format(y), x, desiredY, p);
+ String text = cvs.getFormat().format(y);
+ c.drawText(text, x, desiredY, p);
+ return p.measureText(text);
}
private void drawXAxis(Canvas canvas) {
@@ -792,13 +806,10 @@ public class ChartView extends View {
final int y = effectiveHeight + topBorder;
canvas.drawLine(leftBorder, y, rightEdge, y, borderPaint);
Context c = getContext();
- String s = (mode == Mode.BY_DISTANCE)
- ? (metricUnits ? c.getString(R.string.kilometer)
- : c.getString(R.string.mile)) : (c.getString(R.string.min));
- canvas.drawText(s,
- rightEdge,
- effectiveHeight + .2f * UNIT_BORDER + topBorder,
- labelPaint);
+ String s = mode == Mode.BY_DISTANCE
+ ? (metricUnits ? c.getString(R.string.kilometer) : c.getString(R.string.mile))
+ : c.getString(R.string.min);
+ canvas.drawText(s, rightEdge, effectiveHeight + .2f * UNIT_BORDER + topBorder, labelPaint);
}
private void drawYAxis(Canvas canvas) {
@@ -808,23 +819,15 @@ public class ChartView extends View {
canvas.drawLine(leftBorder, UNIT_BORDER + topBorder,
leftBorder, effectiveHeight + topBorder,
borderPaint);
- final int intervals = getIntervals();
- for (int i = 1; i < intervals; ++i) {
- int y = i * effectiveHeight / intervals + topBorder;
+ for (int i = 1; i < MAX_INTERVALS; ++i) {
+ int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
canvas.drawLine(leftBorder - 5, y, leftBorder, y, gridPaint);
}
Context c = getContext();
// TODO: This should really show units for all series.
- String s = metricUnits
- ? c.getString(R.string.meter)
- : c.getString(R.string.feet);
- canvas.drawText(s, leftBorder - UNIT_BORDER * .2f,
- UNIT_BORDER * .8f + topBorder, labelPaint);
- }
-
- private int getIntervals() {
- return 5;
+ String s = metricUnits ? c.getString(R.string.meter) : c.getString(R.string.feet);
+ canvas.drawText(s, leftBorder - UNIT_BORDER * .2f, UNIT_BORDER * .8f + topBorder, labelPaint);
}
private synchronized void drawGrid(Canvas c) {
@@ -833,9 +836,8 @@ public class ChartView extends View {
}
float rightEdge = getX(maxX);
- final int intervals = getIntervals();
- for (int i = 1; i < intervals; ++i) {
- int y = i * effectiveHeight / intervals + topBorder;
+ for (int i = 1; i < MAX_INTERVALS; ++i) {
+ int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
c.drawLine(leftBorder, y, rightEdge, y, gridBarPaint);
}
}