Improved the code. Added highlight function for Linechart. TODO: Highlight on touch.

This commit is contained in:
Philipp Jahoda 2014-04-30 14:25:55 +02:00
parent 4c0e3ddeb0
commit 1fbfd0db37
9 changed files with 269 additions and 154 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/actionToggleValues" android:title="Toggle Values"></item>
<item android:id="@+id/actionToggleValues" android:title="Toggle Y-Values"></item>
<item android:id="@+id/actionToggleXVals" android:title="Toggle X-Values"></item>
<item android:id="@+id/actionTogglePercent" android:title="Toggle Percent"></item>
<item android:id="@+id/actionToggleHole" android:title="Toggle Hole"></item>

View file

@ -42,11 +42,13 @@ public class LineChartActivity extends Activity implements OnSeekBarChangeListen
// mChart.setRoundedYLegend(false);
// mChart.setStartAtZero(true);
mChart.setDrawYValues(false);
mChart.setLineWidth(5f);
mChart.setCircleSize(5f);
mChart.setLineWidth(4f);
mChart.setCircleSize(4f);
// mChart.setSpacePercent(20, 10);
mChart.setYLegendCount(6);
mChart.setTouchEnabled(true);
mChart.setHighlightEnabled(true);
// mChart.highlightValues(new int[] {2, 6});
mSeekBarX.setProgress(45);
mSeekBarY.setProgress(100);

View file

@ -102,6 +102,19 @@ public class BarChart extends BarLineChartBase {
// increase deltax by 1 because the bars have a width of 1
mDeltaX++;
}
@Override
protected void drawHighlights() {
// if there are values to highlight and highlighnting is enabled, do it
if(mHighlightEnabled && valuesToHighlight()) {
for(int i = 0; i < mIndicesToHightlight.length; i++) {
}
}
}
private RectF mBarRect = new RectF();
@ -224,11 +237,6 @@ public class BarChart extends BarLineChartBase {
}
}
@Override
public void highlightValues(int[] indices) {
super.highlightValues(indices);
}
/**
* sets the skew (default 0.3f), the skew indicates how much the 3D effect
* of the chart is turned to the right

View file

@ -145,6 +145,7 @@ public abstract class BarLineChartBase extends Chart {
drawHorizontalGrid();
drawVerticalGrid();
drawHighlights();
drawData();
drawAdditional();
drawValues();
@ -682,10 +683,26 @@ public abstract class BarLineChartBase extends Chart {
width = 3.0f;
mGridWidth = width;
}
@Override
protected void highlightValues(int[] indices) {
super.highlightValues(indices);
/**
* returns the index of the value at the given touch point
* @param x
* @param y
* @return
*/
public int getIndexByTouchPoint(float x, float y) {
return -1;
}
/**
* returns the value displayed at the touched position of the chart
* @param x
* @param y
* @return
*/
public float getValueByTouchPoint(float x, float y) {
return mYVals.get(getIndexByTouchPoint(x, y));
}
@Override

View file

@ -245,8 +245,6 @@ public class BarLineChartTouchListener extends SimpleOnGestureListener implement
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
PointF pointF = calcImagePosition(start);
mChart.highlightValues(new int[] {1});

View file

@ -118,6 +118,9 @@ public abstract class Chart extends View {
/** if true, y-values are drawn on the chart */
protected boolean mDrawYValues = true;
/** if true, value highlightning is enabled */
protected boolean mHighlightEnabled = true;
/** this rectangle defines the area in which graph values can be drawn */
protected Rect mContentRect;
@ -240,7 +243,7 @@ public abstract class Chart extends View {
// calc delta
mDeltaY = mYMax - mYChartMin;
mYChartMax = mYChartMin + mDeltaY;
mYChartMax = mYChartMin + mYMax;
mDeltaX = mXVals.size() - 1;
@ -420,28 +423,6 @@ public abstract class Chart extends View {
mMatrixOffset.mapPoints(pts);
}
/** the x-position the marker appears on */
protected int mMarkerPosX = 100;
/** the y-postion the marker appears on */
protected int mMarkerPosY = 100;
/** the view that represents the marker */
protected RelativeLayout mMarkerView;
/**
* draws the view that is displayed when the chart is clicked
*/
protected void drawMarkerView() {
if (mMarkerView == null)
return;
mDrawCanvas.translate(mMarkerPosX, mMarkerPosY);
mMarkerView.draw(mDrawCanvas);
mDrawCanvas.translate(-mMarkerPosX, -mMarkerPosY);
}
/**
* draws the description text in the bottom right corner of the chart
*/
@ -479,30 +460,11 @@ public abstract class Chart extends View {
* draws additional stuff, whatever that might be
*/
protected abstract void drawAdditional();
/**
* highlights the value at the given index of the values list
*
* @param indices
* draws the values of the chart that need highlightning
*/
protected void highlightValues(int[] indices) {
if (mSelectionListener != null) {
if (indices[0] == -1)
mSelectionListener.onNothingSelected();
else {
float[] values = new float[indices.length];
for (int i = 0; i < values.length; i++)
values[i] = getYValue(indices[i]);
// notify the listener
mSelectionListener.onValuesSelected(values, indices);
}
}
}
protected abstract void drawHighlights();
/**
* ################ ################ ################ ################
@ -578,6 +540,102 @@ public abstract class Chart extends View {
matrix.setValues(vals);
}
/**
* ################ ################ ################ ################
*/
/** BELOW THIS CODE FOR HIGHLIGHTING */
/**
* array of integers that reference the highlighted slices in the pie chart
*/
protected int[] mIndicesToHightlight = new int[0];
/**
* checks if the given index is set for highlighting or not
*
* @param index
* @return
*/
public boolean needsHighlight(int index) {
// no highlight
if(!valuesToHighlight()) return false;
for (int i = 0; i < mIndicesToHightlight.length; i++)
if (mIndicesToHightlight[i] == index)
return true;
return false;
}
/**
* returns true if there are values to highlight, false if there are not
* @return
*/
public boolean valuesToHighlight() {
return mIndicesToHightlight == null || mIndicesToHightlight.length == 0 ? false : true;
}
/**
* highlights the value at the given index of the values list
*
* @param indices
*/
public void highlightValues(int[] indices) {
// set the indices to highlight
mIndicesToHightlight = indices;
// redraw the chart
invalidate();
if (mSelectionListener != null) {
if(indices == null) return;
if (indices[0] == -1)
mSelectionListener.onNothingSelected();
else {
float[] values = new float[indices.length];
for (int i = 0; i < values.length; i++)
values[i] = getYValue(indices[i]);
// notify the listener
mSelectionListener.onValuesSelected(values, indices);
}
}
}
/**
* ################ ################ ################ ################
*/
/** BELOW CODE IS FOR THE MARKER VIEW */
/** the x-position the marker appears on */
protected int mMarkerPosX = 100;
/** the y-postion the marker appears on */
protected int mMarkerPosY = 100;
/** the view that represents the marker */
protected RelativeLayout mMarkerView;
/**
* draws the view that is displayed when the chart is clicked
*/
protected void drawMarkerView() {
if (mMarkerView == null)
return;
mDrawCanvas.translate(mMarkerPosX, mMarkerPosY);
mMarkerView.draw(mDrawCanvas);
mDrawCanvas.translate(-mMarkerPosX, -mMarkerPosY);
}
/**
* ################ ################ ################ ################
@ -593,6 +651,21 @@ public abstract class Chart extends View {
public void setOnTouchListener(OnTouchListener l) {
this.mListener = l;
}
/**
* if set to true, value highlightning is enabled
* @param enabled
*/
public void setHighlightEnabled(boolean enabled) {
mHighlightEnabled = enabled;
}
/**
* returns true if highlightning of values is enabled, false if not
* @return
*/
public boolean isHighlightEnabled() {
return mHighlightEnabled;
}
/**
* returns the total value (sum) of all y-values
@ -748,28 +821,6 @@ public abstract class Chart extends View {
this.mDrawYValues = enabled;
}
// /**
// * set this to true to make the x-legend exactly fill the whole chart with
// * all values being exacly correct, if the x-legend fits, it means that
// all
// * values use exactly the whole chart width, this can however lead to an
// * increased or decreased number of x-legend grid lines -> e.g. if the
// * number of x-values is a prime number only the first and last x-legend
// * grid line will be created. Nevertheless, the chart will always try to
// get
// * as close as possible to the actually specified number of x-legend grid
// * lines. if set to false, the chart will use exactly the specified number
// * of x-legend grid lines. This can however lead to small incorrectness of
// * the gridlines if the number of x-entries cannot be divided through the
// * number of X-legend entries. default: enabled true
// *
// * @param enabled
// */
// public void setFitXLegend(boolean enabled) {
// this.mFitXLegend = enabled;
// prepare();
// }
/**
* sets the y- starting and ending value
*
@ -815,6 +866,24 @@ public abstract class Chart extends View {
return mMarkerView;
}
/**
* returns the x-position of the marker view
*
* @return
*/
public int getMarkerPosX() {
return mMarkerPosX;
}
/**
* returns the y-position of the marker view
*
* @return
*/
public int getMarkerPosY() {
return mMarkerPosY;
}
/** paint for the lines of the linechart */
public static final int PAINT_LINE = 1;
@ -859,6 +928,9 @@ public abstract class Chart extends View {
/** paint for the text in the middle of the pie chart */
public static final int PAINT_CENTER_TEXT = 14;
/** paint for highlightning the values of a linechart */
public static final int PAINT_HIGHLIGHT_LINE = 15;
/**
* set a new paint object for the specified parameter in the chart e.g.
@ -882,18 +954,6 @@ public abstract class Chart extends View {
}
}
//
// /**
// * returns true if fitting x legend is enabled, false if not if the
// x-legend
// * fits, it means that all values use exactly the whole chart width
// *
// * @return
// */
// public boolean isFitXLegendEnabled() {
// return mFitXLegend;
// }
/**
* returns true if y-value drawing is enabled, false if not
*

View file

@ -6,6 +6,7 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
public class LineChart extends BarLineChartBase {
@ -16,6 +17,9 @@ public class LineChart extends BarLineChartBase {
/** the width of the drawn data lines */
protected float mLineWidth = 1f;
/** the width of the highlighning rectangle */
protected float mHighlightWidth = 0.6f;
/** if true, the data will also be drawn filled */
protected boolean mDrawFilled = false;
@ -34,6 +38,9 @@ public class LineChart extends BarLineChartBase {
/** paint for the inner circle of the value indicators */
protected Paint mCirclePaintInner;
/** paint used for highlighting values */
protected Paint mHighlightPaint;
public LineChart(Context context) {
super(context);
}
@ -71,6 +78,10 @@ public class LineChart extends BarLineChartBase {
mCirclePaintInner = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaintInner.setStyle(Paint.Style.FILL);
mCirclePaintInner.setColor(Color.WHITE);
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mHighlightPaint.setStyle(Paint.Style.FILL);
mHighlightPaint.setColor(Color.rgb(255, 187, 115));
}
@Override
@ -89,6 +100,22 @@ public class LineChart extends BarLineChartBase {
}
}
@Override
protected void drawHighlights() {
// if there are values to highlight and highlighnting is enabled, do it
if (mHighlightEnabled && valuesToHighlight()) {
for (int i = 0; i < mIndicesToHightlight.length; i++) {
RectF highlight = new RectF(mIndicesToHightlight[i] - mHighlightWidth / 2,
mYChartMax, mIndicesToHightlight[i] + mHighlightWidth / 2, mYChartMin);
transformRect(highlight);
mDrawCanvas.drawRect(highlight, mHighlightPaint);
}
}
}
/**
* draws the given y values to the screen
*/
@ -129,7 +156,7 @@ public class LineChart extends BarLineChartBase {
mDrawCanvas.drawPath(filled, mFilledPaint);
}
}
@Override
protected void drawValues() {
@ -180,11 +207,6 @@ public class LineChart extends BarLineChartBase {
}
}
@Override
public void highlightValues(int[] indices) {
super.highlightValues(indices);
}
/**
* set this to true to enable the drawing of circle indicators
*
@ -268,6 +290,26 @@ public class LineChart extends BarLineChartBase {
return mLineWidth;
}
/**
* set the width of the highlightning rectangle 1.0f == 100% width of the
* cell, 0f = 0%, default 0.6f
*
* @param width
*/
public void setHighlightRectWidth(float width) {
mHighlightWidth = width;
}
/**
* returns the width of the highlightning rectanlge, 1f == 100%, 0f = 0% of
* the highlighted cell
*
* @return
*/
public float getHighlightRectWidth() {
return mHighlightWidth;
}
@Override
public void setPaint(Paint p, int which) {
super.setPaint(p, which);
@ -285,6 +327,9 @@ public class LineChart extends BarLineChartBase {
case PAINT_CIRCLES_OUTER:
mCirclePaintOuter = p;
break;
case PAINT_HIGHLIGHT_LINE:
mHighlightPaint = p;
break;
}
}
}

View file

@ -63,11 +63,6 @@ public class PieChart extends Chart {
*/
private boolean mUsePercentValues = false;
/**
* array of integers that reference the highlighted slices in the pie chart
*/
private int[] mIndicesToHightlight = new int[0];
/**
* paint for the hole in the center of the pie chart
*/
@ -130,6 +125,8 @@ public class PieChart extends Chart {
long starttime = System.currentTimeMillis();
drawHighlights();
drawData();
drawAdditional();
@ -293,16 +290,26 @@ public class PieChart extends Chart {
}
@Override
protected void drawData() {
protected void drawHighlights() {
float angle = mChartAngle;
// if there are values to highlight and highlighnting is enabled, do it
if (mHighlightEnabled && valuesToHighlight()) {
for (int i = 0; i < mYVals.size(); i++) {
float angle = 0f;
float newanlge = mDrawAngles[i];
for (int i = 0; i < mIndicesToHightlight.length; i++) {
if (needsHighlight(i)) { // if true, highlight the slice
float shiftangle = (float) Math.toRadians(angle + newanlge / 2f);
// get the index to highlight
int index = mIndicesToHightlight[i];
if (index == 0)
angle = mChartAngle;
else
angle = mChartAngle + mAbsoluteAngles[index - 1];
float sliceDegrees = mDrawAngles[index];
float shiftangle = (float) Math.toRadians(angle + sliceDegrees / 2f);
float xShift = mShift * (float) Math.cos(shiftangle);
float yShift = mShift * (float) Math.sin(shiftangle);
@ -312,15 +319,28 @@ public class PieChart extends Chart {
// redefine the rect that contains the arc so that the
// highlighted pie is not cut off
mDrawCanvas.drawArc(highlighted, angle, newanlge, true, mDrawPaints[i
% mDrawPaints.length]);
} else {
mDrawCanvas.drawArc(mCircleBox, angle, newanlge, true, mDrawPaints[i
mDrawCanvas.drawArc(highlighted, angle, sliceDegrees, true, mDrawPaints[index
% mDrawPaints.length]);
}
angle += newanlge;
}
}
@Override
protected void drawData() {
float angle = mChartAngle;
for (int i = 0; i < mYVals.size(); i++) {
float newangle = mDrawAngles[i];
if (!needsHighlight(i)) {
mDrawCanvas.drawArc(mCircleBox, angle, newangle, true, mDrawPaints[i
% mDrawPaints.length]);
}
angle += newangle;
}
}
@ -432,21 +452,6 @@ public class PieChart extends Chart {
drawHole();
}
/**
* checks if the given index is set for highlighting or not
*
* @param index
* @return
*/
private boolean needsHighlight(int index) {
for (int i = 0; i < mIndicesToHightlight.length; i++)
if (mIndicesToHightlight[i] == index)
return true;
return false;
}
/**
* calculates the needed angle for a given value
*
@ -457,14 +462,6 @@ public class PieChart extends Chart {
return value / mYValueSum * 360f;
}
@Override
public void highlightValues(int[] indices) {
super.highlightValues(indices);
mIndicesToHightlight = indices;
invalidate();
}
/**
* returns the pie index for the pie at the given angle
*

View file

@ -121,27 +121,15 @@ public class PieChartTouchListener extends SimpleOnGestureListener implements On
@Override
public boolean onSingleTapUp(MotionEvent e) {
PointF chartCenter = mChart.getCenter();
PointF touchPoint = new PointF(e.getX(), e.getY());
PointF v = new PointF(touchPoint.x - chartCenter.x, touchPoint.y - chartCenter.y);
Vector3 vector = new Vector3(v.x, v.y, 0f);
vector.normalize();
Vector3 one = new Vector3(1, 0, 0);
float distance = mChart.distanceToCenter(e.getX(), e.getY());
// check if a slice was touched
if(distance < mChart.getRadius() / 2 || distance > mChart.getRadius()) {
// if no slice was touched, highlight nothing
mChart.highlightValues(new int[] {-1});
mChart.highlightValues(null);
} else {
float f = one.dot(vector);
int index = mChart.getIndexForAngle(mChart.getAngleForPoint(e.getX(), e.getY()));
mChart.highlightValues(new int[] {index});