forked from upstream-mirrors/OpenTracks
Fixing a few of the issues in chart drawing.
This commit is contained in:
@@ -259,13 +259,13 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
|||||||
// TODO: Account for segment splits?
|
// TODO: Account for segment splits?
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case BY_DISTANCE:
|
case BY_DISTANCE:
|
||||||
timeOrDistance = profileLength;
|
timeOrDistance = profileLength / 1000.0;
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
double d = lastLocation.distanceTo(location);
|
double d = lastLocation.distanceTo(location);
|
||||||
if (metricUnits) {
|
if (metricUnits) {
|
||||||
profileLength += d / 1000.0;
|
profileLength += d;
|
||||||
} else {
|
} else {
|
||||||
profileLength += d * UnitConversions.KM_TO_MI / 1000.0;
|
profileLength += d * UnitConversions.KM_TO_MI;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -361,9 +361,16 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
|||||||
lastLocation = null;
|
lastLocation = null;
|
||||||
startTime = -1;
|
startTime = -1;
|
||||||
elevationBuffer.reset();
|
elevationBuffer.reset();
|
||||||
speedBuffer.reset();
|
|
||||||
chartView.reset();
|
chartView.reset();
|
||||||
|
speedBuffer.reset();
|
||||||
pendingPoints.clear();
|
pendingPoints.clear();
|
||||||
|
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
chartView.resetScroll();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009 Google Inc.
|
* Copyright 2009 Google Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
* the License at
|
* the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
@@ -48,7 +48,7 @@ public class ChartValueSeries {
|
|||||||
private double spread;
|
private double spread;
|
||||||
private int interval;
|
private int interval;
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class controls how effective min/max values of a {@link ChartValueSeries} are calculated.
|
* This class controls how effective min/max values of a {@link ChartValueSeries} are calculated.
|
||||||
*/
|
*/
|
||||||
@@ -70,10 +70,10 @@ public class ChartValueSeries {
|
|||||||
this.intervals = intervals;
|
this.intervals = intervals;
|
||||||
this.absoluteMin = absoluteMin;
|
this.absoluteMin = absoluteMin;
|
||||||
this.absoluteMax = absoluteMax;
|
this.absoluteMax = absoluteMax;
|
||||||
this.zoomLevels = zoomLevels;
|
this.zoomLevels = zoomLevels;
|
||||||
checkArgs();
|
checkArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkArgs() {
|
private void checkArgs() {
|
||||||
if (intervals <= 0 || zoomLevels == null || zoomLevels.length == 0) {
|
if (intervals <= 0 || zoomLevels == null || zoomLevels.length == 0) {
|
||||||
throw new IllegalArgumentException("Expecing positive intervals and non-empty zoom levels");
|
throw new IllegalArgumentException("Expecing positive intervals and non-empty zoom levels");
|
||||||
@@ -100,12 +100,12 @@ public class ChartValueSeries {
|
|||||||
public int[] getZoomLevels() {
|
public int[] getZoomLevels() {
|
||||||
return zoomLevels;
|
return zoomLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the interval between markings given the min and max values.
|
* Calculates the interval between markings given the min and max values.
|
||||||
* This function attempts to find the smallest zoom level that fits [min,max] after rounding
|
* This function attempts to find the smallest zoom level that fits [min,max] after rounding
|
||||||
* it to the current zoom level.
|
* it to the current zoom level.
|
||||||
*
|
*
|
||||||
* @param min the minimum value in the series
|
* @param min the minimum value in the series
|
||||||
* @param max the maximum value in the series
|
* @param max the maximum value in the series
|
||||||
* @return the calculated interval for the given range
|
* @return the calculated interval for the given range
|
||||||
@@ -136,7 +136,7 @@ public class ChartValueSeries {
|
|||||||
* @param fill The paint for filling the chart
|
* @param fill The paint for filling the chart
|
||||||
* @param stroke The paint for stroking the outside the chart, optional
|
* @param stroke The paint for stroking the outside the chart, optional
|
||||||
* @param zoomSettings The settings related to zooming
|
* @param zoomSettings The settings related to zooming
|
||||||
*
|
*
|
||||||
* TODO: Get rid of Context and inject appropriate values instead.
|
* TODO: Get rid of Context and inject appropriate values instead.
|
||||||
*/
|
*/
|
||||||
public ChartValueSeries(Context context, String formatString, int fillColor, int strokeColor,
|
public ChartValueSeries(Context context, String formatString, int fillColor, int strokeColor,
|
||||||
@@ -207,7 +207,7 @@ public class ChartValueSeries {
|
|||||||
}
|
}
|
||||||
min = Math.min(min, zoomSettings.getAbsoluteMin());
|
min = Math.min(min, zoomSettings.getAbsoluteMin());
|
||||||
max = Math.max(max, zoomSettings.getAbsoluteMax());
|
max = Math.max(max, zoomSettings.getAbsoluteMax());
|
||||||
|
|
||||||
this.interval = zoomSettings.calculateInterval(min, max);
|
this.interval = zoomSettings.calculateInterval(min, max);
|
||||||
// Round it up.
|
// Round it up.
|
||||||
effectiveMax = ((int) (max / interval)) * interval + interval;
|
effectiveMax = ((int) (max / interval)) * interval + interval;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Google Inc.
|
* Copyright 2008 Google Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
* the License at
|
* the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
@@ -28,9 +28,9 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.DashPathEffect;
|
import android.graphics.DashPathEffect;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.Paint.Align;
|
import android.graphics.Paint.Align;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Path;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
||||||
@@ -66,36 +66,38 @@ public class ChartView extends View {
|
|||||||
private int maxZoomLevel = 10;
|
private int maxZoomLevel = 10;
|
||||||
|
|
||||||
private static final int MAX_INTERVALS = 5;
|
private static final int MAX_INTERVALS = 5;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Borders, margins, dimensions (in pixels):
|
* Borders, margins, dimensions (in pixels):
|
||||||
*/
|
*/
|
||||||
private int leftBorder = -1;
|
private int leftBorder = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unscaled top border of the chart.
|
* Unscaled top border of the chart.
|
||||||
*/
|
*/
|
||||||
private static final int TOP_BORDER = 15;
|
private static final int TOP_BORDER = 15;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device scaled top border of the chart.
|
* Device scaled top border of the chart.
|
||||||
*/
|
*/
|
||||||
private int topBorder;
|
private int topBorder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unscaled bottom border of the chart.
|
* Unscaled bottom border of the chart.
|
||||||
*/
|
*/
|
||||||
private static final float BOTTOM_BORDER = 40;
|
private static final float BOTTOM_BORDER = 40;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device scaled bottom border of the chart.
|
* Device scaled bottom border of the chart.
|
||||||
*/
|
*/
|
||||||
private int bottomBorder;
|
private int bottomBorder;
|
||||||
|
|
||||||
private static final int RIGHT_BORDER = 17;
|
private static final int RIGHT_BORDER = 17;
|
||||||
|
|
||||||
/** Space to leave for drawing the unit labels */
|
/** Space to leave for drawing the unit labels */
|
||||||
private static final int UNIT_BORDER = 15;
|
private static final int UNIT_BORDER = 15;
|
||||||
private static final int FONT_HEIGHT = 10;
|
private static final int FONT_HEIGHT = 10;
|
||||||
|
|
||||||
private int w = 0;
|
private int w = 0;
|
||||||
private int h = 0;
|
private int h = 0;
|
||||||
private int effectiveWidth = 0;
|
private int effectiveWidth = 0;
|
||||||
@@ -118,11 +120,11 @@ public class ChartView extends View {
|
|||||||
private ChartValueSeries[] series;
|
private ChartValueSeries[] series;
|
||||||
|
|
||||||
private final ExtremityMonitor xMonitor = new ExtremityMonitor();
|
private final ExtremityMonitor xMonitor = new ExtremityMonitor();
|
||||||
private final NumberFormat xFormat = new DecimalFormat("###,###");
|
private static final NumberFormat X_FORMAT = new DecimalFormat("###,###");
|
||||||
private final NumberFormat xShortFormat = new DecimalFormat("#.0");
|
private static final NumberFormat X_SHORT_FORMAT = new DecimalFormat("#.0");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Paints etc. used when drawing the histogram:
|
* Paints etc. used when drawing the chart:
|
||||||
*/
|
*/
|
||||||
private final Paint borderPaint = new Paint();
|
private final Paint borderPaint = new Paint();
|
||||||
private final Paint labelPaint = new Paint();
|
private final Paint labelPaint = new Paint();
|
||||||
@@ -174,7 +176,7 @@ public class ChartView extends View {
|
|||||||
|
|
||||||
gridBarPaint.set(gridPaint);
|
gridBarPaint.set(gridPaint);
|
||||||
gridBarPaint.setPathEffect(new DashPathEffect(new float[] {3, 2}, 0));
|
gridBarPaint.setPathEffect(new DashPathEffect(new float[] {3, 2}, 0));
|
||||||
|
|
||||||
clearPaint.setStyle(Style.FILL);
|
clearPaint.setStyle(Style.FILL);
|
||||||
clearPaint.setColor(context.getResources().getColor(R.color.white));
|
clearPaint.setColor(context.getResources().getColor(R.color.white));
|
||||||
clearPaint.setAntiAlias(false);
|
clearPaint.setAntiAlias(false);
|
||||||
@@ -271,49 +273,12 @@ public class ChartView extends View {
|
|||||||
: R.string.pace_label));
|
: R.string.pace_label));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the data that is displayed by the chart.
|
|
||||||
*
|
|
||||||
* @return an array list with data points
|
|
||||||
*/
|
|
||||||
public ArrayList<double[]> getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the data that is to be displayed by the chart.
|
|
||||||
*
|
|
||||||
* @param theData an array list of data points
|
|
||||||
*/
|
|
||||||
public synchronized void setDataPoints(ArrayList<double[]> theData) {
|
|
||||||
scrollTo(0, 0);
|
|
||||||
zoomLevel = 1;
|
|
||||||
data.clear();
|
|
||||||
xMonitor.reset();
|
|
||||||
for (ChartValueSeries cvs : series) {
|
|
||||||
cvs.reset();
|
|
||||||
}
|
|
||||||
addDataPoints(theData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new data point to the chart.
|
|
||||||
*
|
|
||||||
* @param theData a data point
|
|
||||||
*/
|
|
||||||
public synchronized void addDataPoint(double[] theData) {
|
|
||||||
data.add(theData);
|
|
||||||
addDataPointInternal(theData);
|
|
||||||
updateDimensions();
|
|
||||||
setUpPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDataPointInternal(double[] theData) {
|
private void addDataPointInternal(double[] theData) {
|
||||||
xMonitor.update(theData[0]);
|
xMonitor.update(theData[0]);
|
||||||
int min = Math.min(series.length, theData.length - 1);
|
int min = Math.min(series.length, theData.length - 1);
|
||||||
for (int i = 0; i < min; i++) {
|
for (int i = 1; i <= min; i++) {
|
||||||
if (!Double.isNaN(theData[i + 1])) {
|
if (!Double.isNaN(theData[i])) {
|
||||||
series[i].update(theData[i + 1]);
|
series[i - 1].update(theData[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fill in the extra's if needed.
|
// Fill in the extra's if needed.
|
||||||
@@ -329,25 +294,32 @@ public class ChartView extends View {
|
|||||||
*
|
*
|
||||||
* @param theData an array list of data points to be added
|
* @param theData an array list of data points to be added
|
||||||
*/
|
*/
|
||||||
public synchronized void addDataPoints(ArrayList<double[]> theData) {
|
public void addDataPoints(ArrayList<double[]> theData) {
|
||||||
data.addAll(theData);
|
synchronized (data) {
|
||||||
for (int i = 0; i < theData.size(); i++) {
|
data.addAll(theData);
|
||||||
double d[] = theData.get(i);
|
for (int i = 0; i < theData.size(); i++) {
|
||||||
addDataPointInternal(d);
|
double d[] = theData.get(i);
|
||||||
|
addDataPointInternal(d);
|
||||||
|
}
|
||||||
|
updateDimensions();
|
||||||
|
setUpPath();
|
||||||
}
|
}
|
||||||
updateDimensions();
|
|
||||||
setUpPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all data.
|
* Clears all data.
|
||||||
* Call this only from the UI thread!
|
|
||||||
*/
|
*/
|
||||||
public synchronized void reset() {
|
public void reset() {
|
||||||
data.clear();
|
synchronized (data) {
|
||||||
zoomLevel = 1;
|
data.clear();
|
||||||
|
xMonitor.reset();
|
||||||
|
zoomLevel = 1;
|
||||||
|
updateDimensions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetScroll() {
|
||||||
scrollTo(0, 0);
|
scrollTo(0, 0);
|
||||||
updateDimensions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -392,13 +364,6 @@ public class ChartView extends View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the current zoom level (1 equals to showing all data points)
|
|
||||||
*/
|
|
||||||
public int getZoomLevel() {
|
|
||||||
return zoomLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates flinging.
|
* Initiates flinging.
|
||||||
*
|
*
|
||||||
@@ -427,14 +392,6 @@ public class ChartView extends View {
|
|||||||
scrollTo(scrollX, 0);
|
scrollTo(scrollX, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the scroll position of the chart. This will trigger a redraw.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void scrollTo(int x, int y) {
|
|
||||||
super.scrollTo(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the current display mode (by distance, by time)
|
* @return the current display mode (by distance, by time)
|
||||||
*/
|
*/
|
||||||
@@ -551,80 +508,82 @@ public class ChartView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized void onDraw(Canvas c) {
|
protected void onDraw(Canvas c) {
|
||||||
if (w != c.getWidth() || h != c.getHeight()) {
|
synchronized (data) {
|
||||||
// Dimensions have changed (for example due to orientation change).
|
if (w != c.getWidth() || h != c.getHeight()) {
|
||||||
w = c.getWidth();
|
// Dimensions have changed (for example due to orientation change).
|
||||||
h = c.getHeight();
|
w = c.getWidth();
|
||||||
effectiveWidth = Math.max(0, w - leftBorder - RIGHT_BORDER);
|
h = c.getHeight();
|
||||||
effectiveHeight = Math.max(0, h - topBorder - bottomBorder);
|
effectiveWidth = Math.max(0, w - leftBorder - RIGHT_BORDER);
|
||||||
setUpPath();
|
effectiveHeight = Math.max(0, h - topBorder - bottomBorder);
|
||||||
}
|
setUpPath();
|
||||||
c.save();
|
|
||||||
c.drawColor(Color.WHITE);
|
|
||||||
if (data.size() < 1) {
|
|
||||||
drawXAxis(c);
|
|
||||||
drawYAxis(c);
|
|
||||||
c.restore();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
c.save();
|
|
||||||
c.clipRect(leftBorder + 1 + getScrollX(), topBorder + 1,
|
|
||||||
w - RIGHT_BORDER + getScrollX() - 1, h - bottomBorder - 1);
|
|
||||||
|
|
||||||
drawGrid(c);
|
|
||||||
|
|
||||||
// Draw the data series.
|
|
||||||
for (ChartValueSeries cvs : series) {
|
|
||||||
if (cvs.isEnabled() && cvs.hasData()) {
|
|
||||||
cvs.drawPath(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the waypoints.
|
|
||||||
for (int i = 1; i < waypoints.size(); i++) {
|
|
||||||
final Waypoint waypoint = waypoints.get(i);
|
|
||||||
if (waypoint.getLocation() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
c.save();
|
c.save();
|
||||||
|
c.drawColor(Color.WHITE);
|
||||||
|
if (data.size() < 1) {
|
||||||
|
drawXAxis(c);
|
||||||
|
drawYAxis(c);
|
||||||
|
c.restore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final float x = getWaypointX(waypoint);
|
c.save();
|
||||||
c.drawLine(x, h - bottomBorder, x, topBorder, gridPaint);
|
c.clipRect(leftBorder + 1 + getScrollX(), topBorder + 1,
|
||||||
c.translate(x - markerWidth / 2, markerHeight);
|
w - RIGHT_BORDER + getScrollX() - 1, h - bottomBorder - 1);
|
||||||
if (waypoints.get(i).getType() == Waypoint.TYPE_STATISTICS) {
|
|
||||||
statsMarker.draw(c);
|
drawGrid(c);
|
||||||
} else {
|
|
||||||
waypointMarker.draw(c);
|
// Draw the data series.
|
||||||
|
for (ChartValueSeries cvs : series) {
|
||||||
|
if (cvs.isEnabled() && cvs.hasData()) {
|
||||||
|
cvs.drawPath(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the waypoints.
|
||||||
|
for (int i = 1; i < waypoints.size(); i++) {
|
||||||
|
final Waypoint waypoint = waypoints.get(i);
|
||||||
|
if (waypoint.getLocation() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c.save();
|
||||||
|
|
||||||
|
final float x = getWaypointX(waypoint);
|
||||||
|
c.drawLine(x, h - bottomBorder, x, topBorder, gridPaint);
|
||||||
|
c.translate(x - markerWidth / 2, markerHeight);
|
||||||
|
if (waypoints.get(i).getType() == Waypoint.TYPE_STATISTICS) {
|
||||||
|
statsMarker.draw(c);
|
||||||
|
} else {
|
||||||
|
waypointMarker.draw(c);
|
||||||
|
}
|
||||||
|
c.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
c.restore();
|
||||||
|
|
||||||
|
// Draw the axis and labels.
|
||||||
|
drawXLabels(c);
|
||||||
|
drawXAxis(c);
|
||||||
|
drawSeriesTitles(c);
|
||||||
|
|
||||||
|
c.translate(getScrollX(), 0);
|
||||||
|
drawYAxis(c);
|
||||||
|
float density = getContext().getResources().getDisplayMetrics().density;
|
||||||
|
final int spacer = (int) (5 * density);
|
||||||
|
int x = leftBorder - spacer;
|
||||||
|
for (ChartValueSeries cvs : series) {
|
||||||
|
if (cvs.isEnabled() && cvs.hasData()) {
|
||||||
|
x -= drawYLabels(cvs, c, x) + spacer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.restore();
|
c.restore();
|
||||||
}
|
if (showPointer && !data.isEmpty()) {
|
||||||
|
c.translate(getX(maxX) - pointer.getIntrinsicWidth() / 2,
|
||||||
c.restore();
|
getY(series[0], data.get(data.size() - 1)[1])
|
||||||
|
- pointer.getIntrinsicHeight() / 2 - 12);
|
||||||
// Draw the axis and labels.
|
pointer.draw(c);
|
||||||
drawXLabels(c);
|
|
||||||
drawXAxis(c);
|
|
||||||
drawSeriesTitles(c);
|
|
||||||
|
|
||||||
c.translate(getScrollX(), 0);
|
|
||||||
drawYAxis(c);
|
|
||||||
float density = getContext().getResources().getDisplayMetrics().density;
|
|
||||||
final int spacer = (int) (5 * density);
|
|
||||||
int x = leftBorder - spacer;
|
|
||||||
for (ChartValueSeries cvs : series) {
|
|
||||||
if (cvs.isEnabled() && cvs.hasData()) {
|
|
||||||
x -= drawYLabels(cvs, c, x) + spacer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.restore();
|
|
||||||
if (showPointer && !data.isEmpty()) {
|
|
||||||
c.translate(getX(maxX) - pointer.getIntrinsicWidth() / 2,
|
|
||||||
getY(series[0], data.get(data.size() - 1)[1])
|
|
||||||
- pointer.getIntrinsicHeight() / 2 - 12);
|
|
||||||
pointer.draw(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawSeriesTitles(Canvas c) {
|
private void drawSeriesTitles(Canvas c) {
|
||||||
@@ -647,52 +606,54 @@ public class ChartView extends View {
|
|||||||
* Sets up the path that is used to draw the histogram in onDraw(). The path
|
* 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.
|
* needs to be updated any time after the data or histogram dimensions change.
|
||||||
*/
|
*/
|
||||||
private synchronized void setUpPath() {
|
private void setUpPath() {
|
||||||
for (ChartValueSeries cvs : series) {
|
synchronized (data) {
|
||||||
cvs.getPath().reset();
|
for (ChartValueSeries cvs : series) {
|
||||||
}
|
cvs.getPath().reset();
|
||||||
if (data.isEmpty()) {
|
}
|
||||||
return;
|
if (data.isEmpty()) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// All of the data points to the respective series.
|
// All of the data points to the respective series.
|
||||||
// TODO: Come up with a better sampling than Math.max(1, (maxZoomLevel - zoomLevel + 1) / 2);
|
// TODO: Come up with a better sampling than Math.max(1, (maxZoomLevel - zoomLevel + 1) / 2);
|
||||||
int sampling = 1;
|
int sampling = 1;
|
||||||
for (int i = 0; i < data.size(); i += sampling) {
|
for (int i = 0; i < data.size(); i += sampling) {
|
||||||
double[] d = data.get(i);
|
double[] d = data.get(i);
|
||||||
int min = Math.min(series.length, d.length - 1);
|
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(x, y);
|
||||||
|
} else {
|
||||||
|
path.lineTo(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the path.
|
||||||
|
int yCorner = topBorder + effectiveHeight;
|
||||||
|
int xCorner = getX(data.get(0)[0]);
|
||||||
|
int min = series.length;
|
||||||
|
for (int j = 0; j < min; j++) {
|
||||||
ChartValueSeries cvs = series[j];
|
ChartValueSeries cvs = series[j];
|
||||||
Path path = cvs.getPath();
|
Path path = cvs.getPath();
|
||||||
int x = getX(d[0]);
|
int first = getFirstPointPopulatedIndex(j + 1);
|
||||||
int y = getY(cvs, d[j + 1]);
|
if (first != -1) {
|
||||||
if (i == 0) {
|
// Bottom right corner
|
||||||
path.moveTo(x, y);
|
path.lineTo(getX(data.get(data.size() - 1)[0]), yCorner);
|
||||||
} else {
|
// Bottom left corner
|
||||||
path.lineTo(x, y);
|
path.lineTo(xCorner, yCorner);
|
||||||
|
// Top right corner
|
||||||
|
path.lineTo(xCorner, getY(cvs, data.get(first)[j + 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the path.
|
|
||||||
int yCorner = topBorder + effectiveHeight;
|
|
||||||
int xCorner = getX(data.get(0)[0]);
|
|
||||||
int min = series.length;
|
|
||||||
for (int j = 0; j < min; j++) {
|
|
||||||
ChartValueSeries cvs = series[j];
|
|
||||||
Path path = cvs.getPath();
|
|
||||||
int first = getFirstPointPopulatedIndex(j + 1);
|
|
||||||
if (first != -1) {
|
|
||||||
// Bottom right corner
|
|
||||||
path.lineTo(getX(data.get(data.size() - 1)[0]), yCorner);
|
|
||||||
// Bottom left corner
|
|
||||||
path.lineTo(xCorner, yCorner);
|
|
||||||
// Top right corner
|
|
||||||
path.lineTo(xCorner, getY(cvs, data.get(first)[j + 1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the index of the first point which has a series populated.
|
* Find the index of the first point which has a series populated.
|
||||||
* @param seriesIndex The index of the value series to search for.
|
* @param seriesIndex The index of the value series to search for.
|
||||||
@@ -709,7 +670,7 @@ public class ChartView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the histogram dimensions.
|
* Update the chart dimensions.
|
||||||
*/
|
*/
|
||||||
private void updateDimensions() {
|
private void updateDimensions() {
|
||||||
maxX = xMonitor.getMax();
|
maxX = xMonitor.getMax();
|
||||||
@@ -785,7 +746,7 @@ public class ChartView extends View {
|
|||||||
}
|
}
|
||||||
String s =
|
String s =
|
||||||
(mode == Mode.BY_DISTANCE)
|
(mode == Mode.BY_DISTANCE)
|
||||||
? (shortFormat ? xShortFormat.format(x) : xFormat.format(x))
|
? (shortFormat ? X_SHORT_FORMAT.format(x) : X_FORMAT.format(x))
|
||||||
: StringUtils.formatTime((long) x);
|
: StringUtils.formatTime((long) x);
|
||||||
c.drawText(s,
|
c.drawText(s,
|
||||||
getX(x),
|
getX(x),
|
||||||
@@ -826,18 +787,18 @@ public class ChartView extends View {
|
|||||||
int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
|
int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
|
||||||
canvas.drawLine(leftBorder - 5, y, leftBorder, y, gridPaint);
|
canvas.drawLine(leftBorder - 5, y, leftBorder, y, gridPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context c = getContext();
|
Context c = getContext();
|
||||||
// TODO: This should really show units for all series.
|
// TODO: This should really show units for all series.
|
||||||
String s = metricUnits ? c.getString(R.string.meter) : c.getString(R.string.feet);
|
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);
|
canvas.drawText(s, leftBorder - UNIT_BORDER * .2f, UNIT_BORDER * .8f + topBorder, labelPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void drawGrid(Canvas c) {
|
private void drawGrid(Canvas c) {
|
||||||
if (data.isEmpty()) {
|
if (data.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rightEdge = getX(maxX);
|
float rightEdge = getX(maxX);
|
||||||
for (int i = 1; i < MAX_INTERVALS; ++i) {
|
for (int i = 1; i < MAX_INTERVALS; ++i) {
|
||||||
int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
|
int y = i * effectiveHeight / MAX_INTERVALS + topBorder;
|
||||||
|
|||||||
@@ -253,9 +253,14 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCurrentLocationChanged(Location loc) {
|
public void onCurrentLocationChanged(final Location loc) {
|
||||||
if (dataHub.isRecordingSelected()) {
|
if (dataHub.isRecordingSelected()) {
|
||||||
showLocation(loc);
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
showLocation(loc);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +274,12 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case DISABLED:
|
case DISABLED:
|
||||||
case NO_FIX:
|
case NO_FIX:
|
||||||
showUnknownLocation();
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
showUnknownLocation();
|
||||||
|
}
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user