Breaking down chart drawing methods as suggested by Sandor.

This commit is contained in:
Rodrigo Damazio
2011-04-30 19:16:13 -03:00
parent c33c2de18b
commit ea47f93bc1
@@ -510,78 +510,102 @@ public class ChartView extends View {
@Override @Override
protected void onDraw(Canvas c) { protected void onDraw(Canvas c) {
synchronized (data) { synchronized (data) {
if (w != c.getWidth() || h != c.getHeight()) { updateEffectiveDimensionsIfChanged(c);
// Dimensions have changed (for example due to orientation change).
w = c.getWidth(); // Keep original state.
h = c.getHeight();
effectiveWidth = Math.max(0, w - leftBorder - RIGHT_BORDER);
effectiveHeight = Math.max(0, h - topBorder - bottomBorder);
setUpPath();
}
c.save(); c.save();
c.drawColor(Color.WHITE); c.drawColor(Color.WHITE);
if (data.size() < 1) {
if (data.isEmpty()) {
// No data, draw only axes
drawXAxis(c); drawXAxis(c);
drawYAxis(c); drawYAxis(c);
c.restore(); c.restore();
return; return;
} }
// Clip to graph drawing space
c.save(); c.save();
c.clipRect(leftBorder + 1 + getScrollX(), topBorder + 1, clipToGraphSpace(c);
w - RIGHT_BORDER + getScrollX() - 1, h - bottomBorder - 1);
// Draw the grid and the data on it.
drawGrid(c); drawGrid(c);
drawDataSeries(c);
drawWaypoints(c);
// Draw the data series. // Go back to full canvas drawing.
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(); c.restore();
// Draw the axis and labels. // Draw the axes and their labels.
drawXLabels(c); drawAxesAndLabels(c);
drawXAxis(c);
drawSeriesTitles(c);
c.translate(getScrollX(), 0); // Go back to original state.
drawYAxis(c); c.restore();
float density = getContext().getResources().getDisplayMetrics().density;
final int spacer = (int) (5 * density); // Draw the pointer
int x = leftBorder - spacer; if (showPointer) {
for (ChartValueSeries cvs : series) { drawPointer(c);
if (cvs.isEnabled() && cvs.hasData()) { }
x -= drawYLabels(cvs, c, x) + spacer; }
} }
private void clipToGraphSpace(Canvas c) {
c.clipRect(leftBorder + 1 + getScrollX(), topBorder + 1,
w - RIGHT_BORDER + getScrollX() - 1, h - bottomBorder - 1);
}
private void drawAxesAndLabels(Canvas c) {
// 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;
}
}
}
private void drawPointer(Canvas c) {
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 drawWaypoints(Canvas 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();
if (showPointer && !data.isEmpty()) { }
c.translate(getX(maxX) - pointer.getIntrinsicWidth() / 2, }
getY(series[0], data.get(data.size() - 1)[1])
- pointer.getIntrinsicHeight() / 2 - 12); private void drawDataSeries(Canvas c) {
pointer.draw(c); // Draw the data series.
for (ChartValueSeries cvs : series) {
if (cvs.isEnabled() && cvs.hasData()) {
cvs.drawPath(c);
} }
} }
} }
@@ -603,7 +627,7 @@ 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 chart 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 void setUpPath() { private void setUpPath() {
@@ -611,49 +635,57 @@ public class ChartView extends View {
for (ChartValueSeries cvs : series) { for (ChartValueSeries cvs : series) {
cvs.getPath().reset(); cvs.getPath().reset();
} }
if (data.isEmpty()) {
return;
}
// All of the data points to the respective series. if (!data.isEmpty()) {
// TODO: Come up with a better sampling than Math.max(1, (maxZoomLevel - zoomLevel + 1) / 2); drawPath();
int sampling = 1; closePath();
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) {
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. /** Actually draws the data points as a path. */
int yCorner = topBorder + effectiveHeight; private void drawPath() {
int xCorner = getX(data.get(0)[0]); // All of the data points to the respective series.
int min = series.length; // TODO: Come up with a better sampling than Math.max(1, (maxZoomLevel - zoomLevel + 1) / 2);
for (int j = 0; j < min; j++) { 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) {
ChartValueSeries cvs = series[j]; ChartValueSeries cvs = series[j];
Path path = cvs.getPath(); Path path = cvs.getPath();
int first = getFirstPointPopulatedIndex(j + 1); int x = getX(d[0]);
if (first != -1) { int y = getY(cvs, d[j + 1]);
// Bottom right corner if (i == 0) {
path.lineTo(getX(data.get(data.size() - 1)[0]), yCorner); path.moveTo(x, y);
// Bottom left corner } else {
path.lineTo(xCorner, yCorner); path.lineTo(x, y);
// Top right corner
path.lineTo(xCorner, getY(cvs, data.get(first)[j + 1]));
} }
} }
} }
} }
/** Closes the drawn path so it looks like a solid graph. */
private void closePath() {
// 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.
@@ -691,10 +723,24 @@ public class ChartView extends View {
float density = getContext().getResources().getDisplayMetrics().density; float density = getContext().getResources().getDisplayMetrics().density;
maxLength = Math.max(maxLength, 1); maxLength = Math.max(maxLength, 1);
leftBorder = (int) (density * (4 + 8 * maxLength)); leftBorder = (int) (density * (4 + 8 * maxLength));
effectiveWidth = w - leftBorder - RIGHT_BORDER;
bottomBorder = (int) (density * BOTTOM_BORDER); bottomBorder = (int) (density * BOTTOM_BORDER);
topBorder = (int) (density * TOP_BORDER); topBorder = (int) (density * TOP_BORDER);
effectiveHeight = h - topBorder - bottomBorder; updateEffectiveDimensions();
}
private void updateEffectiveDimensions() {
effectiveWidth = Math.max(0, w - leftBorder - RIGHT_BORDER);
effectiveHeight = Math.max(0, h - topBorder - bottomBorder);
}
private void updateEffectiveDimensionsIfChanged(Canvas c) {
if (w != c.getWidth() || h != c.getHeight()) {
// Dimensions have changed (for example due to orientation change).
w = c.getWidth();
h = c.getHeight();
updateEffectiveDimensions();
setUpPath();
}
} }
private int getX(double distance) { private int getX(double distance) {
@@ -795,10 +841,6 @@ public class ChartView extends View {
} }
private void drawGrid(Canvas c) { private void drawGrid(Canvas c) {
if (data.isEmpty()) {
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;