Work on highlight rendering and markerview

This commit is contained in:
Philipp Jahoda 2016-06-13 20:13:30 +02:00
parent e853a80f78
commit 8a37bbda38
12 changed files with 218 additions and 213 deletions

View file

@ -760,7 +760,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
* @return
*/
protected float[] getMarkerPosition(Highlight high) {
return new float[]{high.getXPx(), high.getYPx()};
return new float[]{high.getDrawX(), high.getDrawY()};
}
/**

View file

@ -1,7 +1,6 @@
package com.github.mikephil.charting.charts;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
@ -126,9 +125,14 @@ public class HorizontalBarChart extends BarChart {
@Override
protected void prepareValuePxMatrix() {
mRightAxisTransformer.prepareMatrixValuePx(mAxisRight.mAxisMinimum, mAxisRight.mAxisRange, mXAxis.mAxisRange,
mXAxis.mAxisMinimum);
mXAxis.mAxisMinimum);
mLeftAxisTransformer.prepareMatrixValuePx(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisRange, mXAxis.mAxisRange,
mXAxis.mAxisMinimum);
mXAxis.mAxisMinimum);
}
@Override
protected float[] getMarkerPosition(Highlight high) {
return new float[]{high.getDrawY(), high.getDrawX()};
}
@Override
@ -181,7 +185,7 @@ public class HorizontalBarChart extends BarChart {
public Highlight getHighlightByTouchPoint(float x, float y) {
if (mData == null) {
if(mLogEnabled)
if (mLogEnabled)
Log.e(LOG_TAG, "Can't select by touch. No data set.");
return null;
} else
@ -191,14 +195,14 @@ public class HorizontalBarChart extends BarChart {
@Override
public float getLowestVisibleX() {
PointD pos = getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(),
mViewPortHandler.contentBottom());
mViewPortHandler.contentBottom());
return (float) Math.max(mXAxis.mAxisMinimum, pos.y);
}
@Override
public float getHighestVisibleX() {
PointD pos = getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(),
mViewPortHandler.contentTop());
mViewPortHandler.contentTop());
return (float) Math.min(mXAxis.mAxisMaximum, pos.y);
}
}

View file

@ -55,6 +55,16 @@ public class Highlight {
*/
private YAxis.AxisDependency axis;
/**
* the x-position (pixels) on which this highlight object was last drawn
*/
private float mDrawX;
/**
* the y-position (pixels) on which this highlight object was last drawn
*/
private float mDrawY;
public Highlight(float x, int dataSetIndex) {
this.mX = x;
this.mDataSetIndex = dataSetIndex;
@ -179,6 +189,35 @@ public class Highlight {
return axis;
}
/**
* Sets the x- and y-position (pixels) where this highlight was last drawn.
*
* @param x
* @param y
*/
public void setDraw(float x, float y) {
this.mDrawX = x;
this.mDrawY = y;
}
/**
* Returns the x-position in pixels where this highlight object was last drawn.
*
* @return
*/
public float getDrawX() {
return mDrawX;
}
/**
* Returns the y-position in pixels where this highlight object was last drawn.
*
* @return
*/
public float getDrawY() {
return mDrawY;
}
/**
* Returns true if this highlight object is equal to the other (compares
* xIndex and dataSetIndex)

View file

@ -77,7 +77,7 @@ public class RadarHighlighter extends PieRadarHighlighter<RadarChart> {
y * factor * phaseY,
sliceangle * index * phaseX + mChart.getRotationAngle());
vals.add(new Highlight(entry.getX(), entry.getY(), p.x, p.y, i, dataSet.getAxisDependency()));
vals.add(new Highlight(index, entry.getY(), p.x, p.y, i, dataSet.getAxisDependency()));
}
return vals;

View file

@ -19,7 +19,7 @@ import com.github.mikephil.charting.utils.ViewPortHandler;
import java.util.List;
public class BarChartRenderer extends DataRenderer {
public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
protected BarDataProvider mChart;
@ -328,82 +328,48 @@ public class BarChartRenderer extends DataRenderer {
for (Highlight high : indices) {
final int minDataSetIndex = high.getDataSetIndex() == -1
? 0
: high.getDataSetIndex();
final int maxDataSetIndex = high.getDataSetIndex() == -1
? barData.getDataSetCount()
: (high.getDataSetIndex() + 1);
if (maxDataSetIndex - minDataSetIndex < 1) continue;
IBarDataSet set = barData.getDataSetByIndex(high.getDataSetIndex());
for (int dataSetIndex = minDataSetIndex;
dataSetIndex < maxDataSetIndex;
dataSetIndex++) {
if (set == null || !set.isHighlightEnabled())
continue;
IBarDataSet set = barData.getDataSetByIndex(dataSetIndex);
BarEntry e = set.getEntryForXPos(high.getX());
if (set == null || !set.isHighlightEnabled())
continue;
if (!isInBoundsX(e, set))
continue;
Transformer trans = mChart.getTransformer(set.getAxisDependency());
Transformer trans = mChart.getTransformer(set.getAxisDependency());
mHighlightPaint.setColor(set.getHighLightColor());
mHighlightPaint.setAlpha(set.getHighLightAlpha());
mHighlightPaint.setColor(set.getHighLightColor());
mHighlightPaint.setAlpha(set.getHighLightAlpha());
float x = high.getX();
boolean isStack = high.getStackIndex() < 0 ? false : true;
BarEntry e = set.getEntryForXPos(x);
float entryIndex = set.getEntryIndex(e);
final float y1;
final float y2;
if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
continue;
boolean isStack = high.getStackIndex() < 0 ? false : true;
final float y1;
final float y2;
if (isStack) {
y1 = high.getRange().from;
y2 = high.getRange().to;
} else {
y1 = e.getY();
y2 = 0.f;
}
prepareBarHighlight(e.getX(), y1, y2, barData.getBarWidth() / 2f, trans);
c.drawRect(mBarRect, mHighlightPaint);
// if (mChart.isDrawHighlightArrowEnabled()) {
//
// mHighlightPaint.setAlpha(255);
//
// // distance between highlight arrow and bar
// float offsetY = mAnimator.getPhaseY() * 0.07f;
//
// float[] values = new float[9];
// trans.getPixelToValueMatrix().getValues(values);
// final float xToYRel = Math.abs(
// values[Matrix.MSCALE_Y] / values[Matrix.MSCALE_X]);
//
// final float arrowWidth = barData.getBarWidth();
// final float arrowWidthHalf = arrowWidth / 2f;
// final float arrowHeight = arrowWidth * xToYRel;
//
// final float yArrow = (y1 > -y2 ? y1 : y1) * mAnimator.getPhaseY();
//
// Path arrow = new Path();
// arrow.moveTo(e.getX() - arrowWidthHalf, yArrow + offsetY + arrowHeight);
// arrow.lineTo(e.getX(), yArrow + offsetY);
// arrow.lineTo(e.getX() + arrowWidthHalf, yArrow + offsetY + arrowHeight);
//
// trans.pathValueToPixel(arrow);
// c.drawPath(arrow, mHighlightPaint);
// }
if (isStack) {
y1 = high.getRange().from;
y2 = high.getRange().to;
} else {
y1 = e.getY();
y2 = 0.f;
}
}
prepareBarHighlight(e.getX(), y1, y2, barData.getBarWidth() / 2f, trans);
setHighlightDrawPos(high, mBarRect);
c.drawRect(mBarRect, mHighlightPaint);
}
}
/**
* Sets the drawing position of the highlight object based on the riven bar-rect.
* @param high
*/
protected void setHighlightDrawPos(Highlight high, RectF bar) {
high.setDraw(bar.centerX(), bar.top);
}
@Override

View file

@ -1,6 +1,7 @@
package com.github.mikephil.charting.renderer;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.DataSet;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.interfaces.dataprovider.BarLineScatterCandleBubbleDataProvider;
@ -17,6 +18,27 @@ public abstract class BarLineScatterCandleBubbleRenderer extends DataRenderer {
super(animator, viewPortHandler);
}
/**
* Checks if the provided entry object is in bounds for drawing considering the current animation phase.
*
* @param e
* @param set
* @return
*/
protected boolean isInBoundsX(Entry e, IBarLineScatterCandleBubbleDataSet set) {
if (e == null)
return false;
float entryIndex = set.getEntryIndex(e);
if (e == null || entryIndex >= set.getEntryCount() * mAnimator.getPhaseX()) {
return false;
} else {
return true;
}
}
/**
* Calculates and returns the x-bounds for the given DataSet in terms of index in their values array. This
* includes minimum and maximum visible x, as well as range.

View file

@ -184,76 +184,62 @@ public class BubbleChartRenderer extends BarLineScatterCandleBubbleRenderer {
for (Highlight high : indices) {
final int minDataSetIndex = high.getDataSetIndex() == -1
? 0
: high.getDataSetIndex();
final int maxDataSetIndex = high.getDataSetIndex() == -1
? bubbleData.getDataSetCount()
: (high.getDataSetIndex() + 1);
if (maxDataSetIndex - minDataSetIndex < 1) continue;
IBubbleDataSet set = bubbleData.getDataSetByIndex(high.getDataSetIndex());
for (int dataSetIndex = minDataSetIndex; dataSetIndex < maxDataSetIndex; dataSetIndex++) {
if (set == null || !set.isHighlightEnabled())
continue;
IBubbleDataSet dataSet = bubbleData.getDataSetByIndex(dataSetIndex);
final BubbleEntry entry = set.getEntryForXPos(high.getX());
if (dataSet == null || !dataSet.isHighlightEnabled())
continue;
if (!isInBoundsX(entry, set))
continue;
final BubbleEntry entry = dataSet.getEntryForXPos(high.getX());
Transformer trans = mChart.getTransformer(set.getAxisDependency());
if (entry == null)
continue;
sizeBuffer[0] = 0f;
sizeBuffer[2] = 1f;
XBounds bounds = getXBounds(mChart, dataSet);
trans.pointValuesToPixel(sizeBuffer);
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
boolean normalizeSize = set.isNormalizeSizeEnabled();
sizeBuffer[0] = 0f;
sizeBuffer[2] = 1f;
// calcualte the full width of 1 step on the x-axis
final float maxBubbleWidth = Math.abs(sizeBuffer[2] - sizeBuffer[0]);
final float maxBubbleHeight = Math.abs(
mViewPortHandler.contentBottom() - mViewPortHandler.contentTop());
final float referenceSize = Math.min(maxBubbleHeight, maxBubbleWidth);
trans.pointValuesToPixel(sizeBuffer);
pointBuffer[0] = entry.getX();
pointBuffer[1] = (entry.getY()) * phaseY;
trans.pointValuesToPixel(pointBuffer);
boolean normalizeSize = dataSet.isNormalizeSizeEnabled();
high.setDraw(pointBuffer[0], pointBuffer[1]);
// calcualte the full width of 1 step on the x-axis
final float maxBubbleWidth = Math.abs(sizeBuffer[2] - sizeBuffer[0]);
final float maxBubbleHeight = Math.abs(
mViewPortHandler.contentBottom() - mViewPortHandler.contentTop());
final float referenceSize = Math.min(maxBubbleHeight, maxBubbleWidth);
float shapeHalf = getShapeSize(entry.getSize(),
set.getMaxSize(),
referenceSize,
normalizeSize) / 2f;
pointBuffer[0] = entry.getX();
pointBuffer[1] = (entry.getY()) * phaseY;
trans.pointValuesToPixel(pointBuffer);
if (!mViewPortHandler.isInBoundsTop(pointBuffer[1] + shapeHalf)
|| !mViewPortHandler.isInBoundsBottom(pointBuffer[1] - shapeHalf))
continue;
float shapeHalf = getShapeSize(entry.getSize(),
dataSet.getMaxSize(),
referenceSize,
normalizeSize) / 2f;
if (!mViewPortHandler.isInBoundsLeft(pointBuffer[0] + shapeHalf))
continue;
if (!mViewPortHandler.isInBoundsTop(pointBuffer[1] + shapeHalf)
|| !mViewPortHandler.isInBoundsBottom(pointBuffer[1] - shapeHalf))
continue;
if (!mViewPortHandler.isInBoundsRight(pointBuffer[0] - shapeHalf))
break;
if (!mViewPortHandler.isInBoundsLeft(pointBuffer[0] + shapeHalf))
continue;
final int originalColor = set.getColor((int) entry.getX());
if (!mViewPortHandler.isInBoundsRight(pointBuffer[0] - shapeHalf))
break;
Color.RGBToHSV(Color.red(originalColor), Color.green(originalColor),
Color.blue(originalColor), _hsvBuffer);
_hsvBuffer[2] *= 0.5f;
final int color = Color.HSVToColor(Color.alpha(originalColor), _hsvBuffer);
if (high.getX() < bounds.min || high.getX() > bounds.max)
continue;
final int originalColor = dataSet.getColor((int) entry.getX());
Color.RGBToHSV(Color.red(originalColor), Color.green(originalColor),
Color.blue(originalColor), _hsvBuffer);
_hsvBuffer[2] *= 0.5f;
final int color = Color.HSVToColor(Color.alpha(originalColor), _hsvBuffer);
mHighlightPaint.setColor(color);
mHighlightPaint.setStrokeWidth(dataSet.getHighlightCircleWidth());
c.drawCircle(pointBuffer[0], pointBuffer[1], shapeHalf, mHighlightPaint);
}
mHighlightPaint.setColor(color);
mHighlightPaint.setStrokeWidth(set.getHighlightCircleWidth());
c.drawCircle(pointBuffer[0], pointBuffer[1], shapeHalf, mHighlightPaint);
}
}
}

View file

@ -308,40 +308,26 @@ public class CandleStickChartRenderer extends LineScatterCandleRadarRenderer {
for (Highlight high : indices) {
final int minDataSetIndex = high.getDataSetIndex() == -1
? 0
: high.getDataSetIndex();
final int maxDataSetIndex = high.getDataSetIndex() == -1
? candleData.getDataSetCount()
: (high.getDataSetIndex() + 1);
if (maxDataSetIndex - minDataSetIndex < 1) continue;
ICandleDataSet set = candleData.getDataSetByIndex(high.getDataSetIndex());
for (int dataSetIndex = minDataSetIndex;
dataSetIndex < maxDataSetIndex;
dataSetIndex++) {
if (set == null || !set.isHighlightEnabled())
continue;
float x = high.getX(); // get the
// x-position
CandleEntry e = set.getEntryForXPos(high.getX());
ICandleDataSet set = mChart.getCandleData().getDataSetByIndex(dataSetIndex);
if (!isInBoundsX(e, set))
continue;
if (set == null || !set.isHighlightEnabled())
continue;
float lowValue = e.getLow() * mAnimator.getPhaseY();
float highValue = e.getHigh() * mAnimator.getPhaseY();
float y = (lowValue + highValue) / 2f;
CandleEntry e = set.getEntryForXPos(x);
PointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(e.getX(), y);
if (e == null)
continue;
high.setDraw((float) pix.x, (float) pix.y);
float lowValue = e.getLow() * mAnimator.getPhaseY();
float highValue = e.getHigh() * mAnimator.getPhaseY();
float y = (lowValue + highValue) / 2f;
PointD px = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(x, y);
// draw the lines
drawHighlightLines(c, (float) px.x, (float) px.y, set);
}
// draw the lines
drawHighlightLines(c, (float) pix.x, (float) pix.y, set);
}
}
}

View file

@ -3,6 +3,7 @@ package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
import android.graphics.Paint.Align;
import android.graphics.RectF;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
@ -10,6 +11,7 @@ import com.github.mikephil.charting.buffer.HorizontalBarBuffer;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.dataprovider.ChartInterface;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
@ -291,6 +293,11 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
trans.rectToPixelPhaseHorizontal(mBarRect, mAnimator.getPhaseY());
}
@Override
protected void setHighlightDrawPos(Highlight high, RectF bar) {
high.setDraw(bar.centerY(), bar.right);
}
@Override
protected boolean isDrawingValuesAllowed(ChartInterface chart) {
return chart.getData().getEntryCount() < chart.getMaxVisibleCount()

View file

@ -622,34 +622,23 @@ public class LineChartRenderer extends LineRadarRenderer {
for (Highlight high : indices) {
final int minDataSetIndex = high.getDataSetIndex() == -1
? 0
: high.getDataSetIndex();
final int maxDataSetIndex = high.getDataSetIndex() == -1
? lineData.getDataSetCount()
: (high.getDataSetIndex() + 1);
if (maxDataSetIndex - minDataSetIndex < 1) continue;
ILineDataSet set = lineData.getDataSetByIndex(high.getDataSetIndex());
for (int dataSetIndex = minDataSetIndex;
dataSetIndex < maxDataSetIndex;
dataSetIndex++) {
if (set == null || !set.isHighlightEnabled())
continue;
ILineDataSet set = lineData.getDataSetByIndex(dataSetIndex);
Entry e = set.getEntryForXPos(high.getX());
if (set == null || !set.isHighlightEnabled())
continue;
if (!isInBoundsX(e, set))
continue;
float x = high.getX();
float y = high.getY() * mAnimator.getPhaseY();
PointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(e.getX(), e.getY() * mAnimator
.getPhaseY());
if (x > mChart.getXChartMax() * mAnimator.getPhaseX())
continue;
high.setDraw((float) pix.x, (float) pix.y);
PointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(x, y);
// draw the lines
drawHighlightLines(c, (float) pix.x, (float) pix.y, set);
}
// draw the lines
drawHighlightLines(c, (float) pix.x, (float) pix.y, set);
}
}

View file

@ -121,7 +121,7 @@ public class RadarChartRenderer extends LineRadarRenderer {
surface.close();
if(dataSet.isDrawFilledEnabled()) {
if (dataSet.isDrawFilledEnabled()) {
final Drawable drawable = dataSet.getFillDrawable();
if (drawable != null) {
@ -176,7 +176,8 @@ public class RadarChartRenderer extends LineRadarRenderer {
(entry.getY() - mChart.getYChartMin()) * factor * phaseY,
sliceangle * j * phaseX + mChart.getRotationAngle());
drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, p.x, p.y - yoffset, dataSet.getValueTextColor(j));
drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, p.x, p.y - yoffset, dataSet.getValueTextColor
(j));
}
}
}
@ -239,17 +240,33 @@ public class RadarChartRenderer extends LineRadarRenderer {
@Override
public void drawHighlighted(Canvas c, Highlight[] indices) {
for (int i = 0; i < indices.length; i++) {
float sliceangle = mChart.getSliceAngle();
IRadarDataSet set = mChart.getData()
.getDataSetByIndex(indices[i]
.getDataSetIndex());
// calculate the factor that is needed for transforming the value to
// pixels
float factor = mChart.getFactor();
PointF center = mChart.getCenterOffsets();
RadarData radarData = mChart.getData();
for (Highlight high : indices) {
IRadarDataSet set = radarData.getDataSetByIndex(high.getDataSetIndex());
if (set == null || !set.isHighlightEnabled())
continue;
Highlight high = indices[i];
PointF p = new PointF(high.getXPx(), high.getYPx());
Entry e = set.getEntryForXPos(high.getX());
if (!isInBoundsX(e, set))
continue;
PointF p = Utils.getPosition(center,
(e.getY() - mChart.getYChartMin()) * factor * mAnimator.getPhaseY(),
sliceangle * high.getX() * mAnimator.getPhaseX() + mChart.getRotationAngle());
high.setDraw(p.x, p.y);
// draw the lines
drawHighlightLines(c, p.x, p.y, set);
@ -280,12 +297,12 @@ public class RadarChartRenderer extends LineRadarRenderer {
}
public void drawHighlightCircle(Canvas c,
PointF point,
float innerRadius,
float outerRadius,
int fillColor,
int strokeColor,
float strokeWidth) {
PointF point,
float innerRadius,
float outerRadius,
int fillColor,
int strokeColor,
float strokeWidth) {
c.save();
outerRadius = Utils.convertDpToPixel(outerRadius);

View file

@ -355,34 +355,23 @@ public class ScatterChartRenderer extends LineScatterCandleRadarRenderer {
for (Highlight high : indices) {
final int minDataSetIndex = high.getDataSetIndex() == -1
? 0
: high.getDataSetIndex();
final int maxDataSetIndex = high.getDataSetIndex() == -1
? scatterData.getDataSetCount()
: (high.getDataSetIndex() + 1);
if (maxDataSetIndex - minDataSetIndex < 1) continue;
IScatterDataSet set = scatterData.getDataSetByIndex(high.getDataSetIndex());
for (int dataSetIndex = minDataSetIndex;
dataSetIndex < maxDataSetIndex;
dataSetIndex++) {
if (set == null || !set.isHighlightEnabled())
continue;
IScatterDataSet set = scatterData.getDataSetByIndex(dataSetIndex);
Entry e = set.getEntryForXPos(high.getX());
if (set == null || !set.isHighlightEnabled())
continue;
if (!isInBoundsX(e, set))
continue;
float x = high.getX();
float y = high.getY() * mAnimator.getPhaseY();
PointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(e.getX(), e.getY() * mAnimator
.getPhaseY());
if (x > mChart.getXChartMax() * mAnimator.getPhaseX())
continue;
high.setDraw((float) pix.x, (float) pix.y);
PointD px = mChart.getTransformer(set.getAxisDependency()).getPixelsForValues(x, y);
// draw the lines
drawHighlightLines(c, (float) px.x, (float) px.y, set);
}
// draw the lines
drawHighlightLines(c, (float) pix.x, (float) pix.y, set);
}
}
}