package com.github.mikephil.charting.highlight; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; import com.github.mikephil.charting.interfaces.BarDataProvider; /** * 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) { Highlight h = super.getHighlight(x, y); if (h == null) return h; else { BarDataSet set = mChart.getBarData().getDataSetByIndex(h.getDataSetIndex()); if (set.isStacked()) { // create an array of the touch-point float[] pts = new float[2]; pts[1] = y; // take any transformer to determine the x-axis value mChart.getTransformer(set.getAxisDependency()).pixelsToValue(pts); return getStackedHighlight(h, set, h.getXIndex(), h.getDataSetIndex(), pts[1]); } else return h; } } @Override protected int getXIndex(float x) { if (!mChart.getBarData().isGrouped()) { return super.getXIndex(x); } else { 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 int getDataSetIndex(int xIndex, float x, float y) { if (!mChart.getBarData().isGrouped()) { return 0; } else { float baseNoSpace = getBase(x); int setCount = mChart.getBarData().getDataSetCount(); int dataSetIndex = (int) baseNoSpace % setCount; if (dataSetIndex < 0) dataSetIndex = 0; else if (dataSetIndex >= setCount) dataSetIndex = setCount - 1; return dataSetIndex; } } /** * This method creates the Highlight object that also indicates which value of a stacked BarEntry has been selected. * * @param old * the old highlight object before looking for stacked values * @param set * @param xIndex * @param dataSetIndex * @param yValue * @return */ protected Highlight getStackedHighlight(Highlight old, BarDataSet set, int xIndex, int dataSetIndex, double yValue) { BarEntry entry = set.getEntryForXIndex(xIndex); if (entry == null || entry.getVals() == null) return old; Range[] ranges = getRanges(entry); int stackIndex = getClosestStackIndex(ranges, (float) yValue); Highlight h = new Highlight(xIndex, dataSetIndex, stackIndex, ranges[stackIndex]); return h; } /** * Returns the index of the closest value inside the values array / ranges (stacked barchart) to the value given as * a parameter. * * @param ranges * @param value * @return */ protected int getClosestStackIndex(Range[] ranges, float value) { if (ranges == null) return 0; int stackIndex = 0; for (Range range : ranges) { if (range.contains(value)) return stackIndex; else stackIndex++; } int length = ranges.length - 1; return (value > ranges[length].to) ? length : 0; // // float[] vals = e.getVals(); // // if (vals == null) // return -1; // // int index = 0; // float remainder = e.getNegativeSum(); // // while (index < vals.length - 1 && value > vals[index] + remainder) { // remainder += vals[index]; // index++; // } // // return index; } /** * Returns the base x-value to the corresponding x-touch value in pixels. * * @param x * @return */ protected float getBase(float x) { // create an array of the touch-point float[] pts = new float[2]; pts[0] = x; // take any transformer to determine the x-axis value mChart.getTransformer(YAxis.AxisDependency.LEFT).pixelsToValue(pts); float xVal = pts[0]; int setCount = mChart.getBarData().getDataSetCount(); // 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.getVals(); if (values == null) return null; float negRemain = -entry.getNegativeSum(); float posRemain = 0f; Range[] ranges = new Range[values.length]; 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; } }