package com.github.mikephil.charting.charts;
import android.content.Context;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
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.highlight.BarHighlighter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.renderer.BarChartRenderer;
/**
* Chart that draws bars.
*
* @author Philipp Jahoda
*/
public class BarChart extends BarLineChartBase<BarData> implements BarDataProvider {
/**
* flag that indicates whether the highlight should be full-bar oriented, or single-value?
*/
protected boolean mHighlightFullBarEnabled = false;
/**
* if set to true, all values are drawn above their bars, instead of below their top
*/
private boolean mDrawValueAboveBar = true;
/**
* if set to true, a grey area is drawn behind each bar that indicates the maximum value
*/
private boolean mDrawBarShadow = false;
private boolean mFitBars = false;
public BarChart(Context context) {
super(context);
}
public BarChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BarChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void init() {
super.init();
mRenderer = new BarChartRenderer(this, mAnimator, mViewPortHandler);
setHighlighter(new BarHighlighter(this));
getXAxis().setSpaceMin(0.5f);
getXAxis().setSpaceMax(0.5f);
}
@Override
protected void calcMinMax() {
if (mFitBars) {
mXAxis.calculate(mData.getXMin() - mData.getBarWidth() / 2f, mData.getXMax() + mData.getBarWidth() / 2f);
} else {
mXAxis.calculate(mData.getXMin(), mData.getXMax());
}
// calculate axis range (min / max) according to provided data
mAxisLeft.calculate(mData.getYMin(YAxis.AxisDependency.LEFT), mData.getYMax(YAxis.AxisDependency.LEFT));
mAxisRight.calculate(mData.getYMin(YAxis.AxisDependency.RIGHT), mData.getYMax(YAxis.AxisDependency
.RIGHT));
}
/**
* Returns the Highlight object (contains x-index and DataSet index) of the selected value at the given touch
* point
* inside the BarChart.
*
* @param x
* @param y
* @return
*/
@Override
public Highlight getHighlightByTouchPoint(float x, float y) {
if (mData == null) {
Log.e(LOG_TAG, "Can't select by touch. No data set.");
return null;
} else {
Highlight h = getHighlighter().getHighlight(x, y);
if (h == null || !isHighlightFullBarEnabled()) return h;
// For isHighlightFullBarEnabled, remove stackIndex
return new Highlight(h.getX(), h.getY(),
h.getXPx(), h.getYPx(),
h.getDataSetIndex(), -1, h.getAxis());
}
}
/**
* Returns the bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be
* found in the charts data. Performance-intensive code should use void getBarBounds(BarEntry, RectF) instead.
*
* @param e
* @return
*/
public RectF getBarBounds(BarEntry e) {
RectF bounds = new RectF();
getBarBounds(e, bounds);
return bounds;
}
/**
* The passed outputRect will be assigned the values of the bounding box of the specified Entry in the specified DataSet.
* The rect will be assigned Float.MIN_VALUE in all locations if the Entry could not be found in the charts data.
*
* @param e
* @return
*/
public void getBarBounds(BarEntry e, RectF outputRect) {
RectF bounds = outputRect;
IBarDataSet set = mData.getDataSetForEntry(e);
if (set == null) {
bounds.set(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
return;
}
float y = e.getY();
float x = e.getX();
float barWidth = mData.getBarWidth();
float left = x - barWidth / 2f;
float right = x + barWidth / 2f;
float top = y >= 0 ? y : 0;
float bottom = y <= 0 ? y : 0;
bounds.set(left, top, right, bottom);
getTransformer(set.getAxisDependency()).rectValueToPixel(outputRect);
}
/**
* If set to true, all values are drawn above their bars, instead of below their top.
*
* @param enabled
*/
public void setDrawValueAboveBar(boolean enabled) {
mDrawValueAboveBar = enabled;
}
/**
* returns true if drawing values above bars is enabled, false if not
*
* @return
*/
public boolean isDrawValueAboveBarEnabled() {
return mDrawValueAboveBar;
}
/**
* If set to true, a grey area is drawn behind each bar that indicates the maximum value. Enabling his will reduce
* performance by about 50%.
*
* @param enabled
*/
public void setDrawBarShadow(boolean enabled) {
mDrawBarShadow = enabled;
}
/**
* returns true if drawing shadows (maxvalue) for each bar is enabled, false if not
*
* @return
*/
public boolean isDrawBarShadowEnabled() {
return mDrawBarShadow;
}
/**
* Set this to true to make the highlight operation full-bar oriented, false to make it highlight single values (relevant
* only for stacked). If enabled, highlighting operations will highlight the whole bar, even if only a single stack entry
* was tapped.
* Default: false
*
* @param enabled
*/
public void setHighlightFullBarEnabled(boolean enabled) {
mHighlightFullBarEnabled = enabled;
}
/**
* @return true the highlight operation is be full-bar oriented, false if single-value
*/
@Override
public boolean isHighlightFullBarEnabled() {
return mHighlightFullBarEnabled;
}
/**
* Highlights the value at the given x-value in the given DataSet. Provide
* -1 as the dataSetIndex to undo all highlighting.
*
* @param x
* @param dataSetIndex
* @param stackIndex the index inside the stack - only relevant for stacked entries
*/
public void highlightValue(float x, int dataSetIndex, int stackIndex) {
highlightValue(new Highlight(x, dataSetIndex, stackIndex), false);
}
@Override
public BarData getBarData() {
return mData;
}
/**
* Adds half of the bar width to each side of the x-axis range in order to allow the bars of the barchart to be
* fully displayed.
* Default: false
*
* @param enabled
*/
public void setFitBars(boolean enabled) {
mFitBars = enabled;
}
/**
* Groups all BarDataSet objects this data object holds together by modifying the x-value of their entries.
* Previously set x-values of entries will be overwritten. Leaves space between bars and groups as specified
* by the parameters.
* Calls notifyDataSetChanged() afterwards.
*
* @param fromX the starting point on the x-axis where the grouping should begin
* @param groupSpace the space between groups of bars in values (not pixels) e.g. 0.8f for bar width 1f
* @param barSpace the space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f
*/
public void groupBars(float fromX, float groupSpace, float barSpace) {
if (getBarData() == null) {
throw new RuntimeException("You need to set data for the chart before grouping bars.");
} else {
getBarData().groupBars(fromX, groupSpace, barSpace);
notifyDataSetChanged();
}
}
}