blob: ad96567eba80b2dce20026231f75966f00895223 [file] [log] [blame]
package com.github.mikephil.charting.highlight;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.utils.PointD;
import com.github.mikephil.charting.utils.SelectionDetail;
/**
* Created by Philipp Jahoda on 22/07/15.
*/
public class BarHighlighter extends ChartHighlighter<BarDataProvider> {
public BarHighlighter(BarDataProvider chart) {
super(chart);
}
@Override
public Highlight getHighlight(float x, float y) {
BarData barData = mChart.getBarData();
final float xVal = getXForTouch(x);
final float baseNoSpace = getBase(x);
final int setCount = barData.getDataSetCount();
int dataSetIndex = ((int) baseNoSpace) % setCount;
if (dataSetIndex < 0) {
dataSetIndex = 0;
} else if (dataSetIndex >= setCount) {
dataSetIndex = setCount - 1;
}
SelectionDetail selectionDetail = getSelectionDetail(xVal, x, y, dataSetIndex);
if (selectionDetail == null)
return null;
IBarDataSet set = barData.getDataSetByIndex(dataSetIndex);
if (set.isStacked()) {
float[] pts = new float[2];
pts[1] = y;
// take any transformer to determine the xPx-axis yValue
mChart.getTransformer(set.getAxisDependency()).pixelsToValue(pts);
return getStackedHighlight(selectionDetail,
set,
xVal,
pts[1]);
}
return new Highlight(
selectionDetail.xValue,
selectionDetail.yValue,
selectionDetail.dataIndex,
selectionDetail.dataSetIndex,
-1);
}
@Override
protected float getXForTouch(float x) {
if (!mChart.getBarData().isGrouped()) {
return super.getXForTouch(x);
} else {
return getBase(x);
//
// float baseNoSpace = getBase(x);
//
// int setCount = mChart.getBarData().getDataSetCount();
// int xIndex = (int) baseNoSpace / setCount;
//
// int valCount = mChart.getData().getXValCount();
//
// if (xIndex < 0)
// xIndex = 0;
// else if (xIndex >= valCount)
// xIndex = valCount - 1;
//
// return xIndex;
}
}
@Override
protected SelectionDetail getSelectionDetail(float xVal, float x, float y, int dataSetIndex) {
dataSetIndex = Math.max(dataSetIndex, 0);
BarData barData = mChart.getBarData();
IDataSet dataSet = barData.getDataSetCount() > dataSetIndex
? barData.getDataSetByIndex(dataSetIndex)
: null;
if (dataSet == null)
return null;
final Entry entry = dataSet.getEntryForXPos(xVal);
return new SelectionDetail(entry.getX(),
entry.getY(),
dataSetIndex,
dataSet);
}
/**
* This method creates the Highlight object that also indicates which yValue of a stacked BarEntry has been
* selected.
*
* @param selectionDetail the selection detail to work with looking for stacked values
* @param set
* @param xVal
* @param yValue
* @return
*/
protected Highlight getStackedHighlight(
SelectionDetail selectionDetail,
IBarDataSet set,
float xVal,
double yValue) {
BarEntry entry = set.getEntryForXPos(xVal);
if (entry == null)
return null;
// not stacked
if (entry.getYVals() == null) {
return new Highlight(entry.getX(),
entry.getY(),
selectionDetail.dataIndex,
selectionDetail.dataSetIndex);
} else {
Range[] ranges = getRanges(entry);
if (ranges.length > 0) {
int stackIndex = getClosestStackIndex(ranges, (float) yValue);
return new Highlight(
entry.getX(),
entry.getPositiveSum() - entry.getNegativeSum(),
selectionDetail.dataIndex,
selectionDetail.dataSetIndex,
stackIndex,
ranges[stackIndex]
);
}
}
return null;
}
/**
* Returns the index of the closest yValue inside the values array / ranges (stacked barchart) to the yValue
* given as
* a parameter.
*
* @param ranges
* @param value
* @return
*/
protected int getClosestStackIndex(Range[] ranges, float value) {
if (ranges == null || ranges.length == 0)
return 0;
int stackIndex = 0;
for (Range range : ranges) {
if (range.contains(value))
return stackIndex;
else
stackIndex++;
}
int length = Math.max(ranges.length - 1, 0);
return (value > ranges[length].to) ? length : 0;
}
/**
* Returns the base xPx-yValue to the given xPx-touch value in pixels.
*
* @param x
* @return
*/
protected float getBase(float x) {
// take any transformer to determine the x-axis value
PointD val = mChart.getTransformer(YAxis.AxisDependency.LEFT).getValuesByTouchPoint(x, 0f);
int setCount = mChart.getBarData().getDataSetCount();
return (float) val.x;
//
//
//
// // calculate how often the group-space appears
// int steps = (int) ((float) xVal / ((float) setCount + mChart.getBarData().getGroupSpace()));
//
// float groupSpaceSum = mChart.getBarData().getGroupSpace() * (float) steps;
//
// float baseNoSpace = (float) xVal - groupSpaceSum;
// return baseNoSpace;
}
/**
* Splits up the stack-values of the given bar-entry into Range objects.
*
* @param entry
* @return
*/
protected Range[] getRanges(BarEntry entry) {
float[] values = entry.getYVals();
if (values == null || values.length == 0)
return new Range[0];
Range[] ranges = new Range[values.length];
float negRemain = -entry.getNegativeSum();
float posRemain = 0f;
for (int i = 0; i < ranges.length; i++) {
float value = values[i];
if (value < 0) {
ranges[i] = new Range(negRemain, negRemain + Math.abs(value));
negRemain += Math.abs(value);
} else {
ranges[i] = new Range(posRemain, posRemain + value);
posRemain += value;
}
}
return ranges;
}
}