1 package com.github.mikephil.charting.charts; 2 3 import android.content.Context; 4 import android.graphics.RectF; 5 import android.util.AttributeSet; 6 import android.util.Log; 7 8 import com.github.mikephil.charting.components.YAxis; 9 import com.github.mikephil.charting.data.BarData; 10 import com.github.mikephil.charting.data.BarEntry; 11 import com.github.mikephil.charting.highlight.BarHighlighter; 12 import com.github.mikephil.charting.highlight.Highlight; 13 import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider; 14 import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; 15 import com.github.mikephil.charting.renderer.BarChartRenderer; 16 17 /** 18 * Chart that draws bars. 19 * 20 * @author Philipp Jahoda 21 */ 22 public class BarChart extends BarLineChartBase<BarData> implements BarDataProvider { 23 24 /** 25 * flag that indicates whether the highlight should be full-bar oriented, or single-value? 26 */ 27 protected boolean mHighlightFullBarEnabled = false; 28 29 /** 30 * if set to true, all values are drawn above their bars, instead of below their top 31 */ 32 private boolean mDrawValueAboveBar = true; 33 34 /** 35 * if set to true, a grey area is drawn behind each bar that indicates the maximum value 36 */ 37 private boolean mDrawBarShadow = false; 38 39 private boolean mFitBars = false; 40 BarChart(Context context)41 public BarChart(Context context) { 42 super(context); 43 } 44 BarChart(Context context, AttributeSet attrs)45 public BarChart(Context context, AttributeSet attrs) { 46 super(context, attrs); 47 } 48 BarChart(Context context, AttributeSet attrs, int defStyle)49 public BarChart(Context context, AttributeSet attrs, int defStyle) { 50 super(context, attrs, defStyle); 51 } 52 53 @Override init()54 protected void init() { 55 super.init(); 56 57 mRenderer = new BarChartRenderer(this, mAnimator, mViewPortHandler); 58 59 setHighlighter(new BarHighlighter(this)); 60 61 getXAxis().setSpaceMin(0.5f); 62 getXAxis().setSpaceMax(0.5f); 63 } 64 65 @Override calcMinMax()66 protected void calcMinMax() { 67 68 if (mFitBars) { 69 mXAxis.calculate(mData.getXMin() - mData.getBarWidth() / 2f, mData.getXMax() + mData.getBarWidth() / 2f); 70 } else { 71 mXAxis.calculate(mData.getXMin(), mData.getXMax()); 72 } 73 74 // calculate axis range (min / max) according to provided data 75 mAxisLeft.calculate(mData.getYMin(YAxis.AxisDependency.LEFT), mData.getYMax(YAxis.AxisDependency.LEFT)); 76 mAxisRight.calculate(mData.getYMin(YAxis.AxisDependency.RIGHT), mData.getYMax(YAxis.AxisDependency 77 .RIGHT)); 78 } 79 80 /** 81 * Returns the Highlight object (contains x-index and DataSet index) of the selected value at the given touch 82 * point 83 * inside the BarChart. 84 * 85 * @param x 86 * @param y 87 * @return 88 */ 89 @Override getHighlightByTouchPoint(float x, float y)90 public Highlight getHighlightByTouchPoint(float x, float y) { 91 92 if (mData == null) { 93 Log.e(LOG_TAG, "Can't select by touch. No data set."); 94 return null; 95 } else { 96 Highlight h = getHighlighter().getHighlight(x, y); 97 if (h == null || !isHighlightFullBarEnabled()) return h; 98 99 // For isHighlightFullBarEnabled, remove stackIndex 100 return new Highlight(h.getX(), h.getY(), 101 h.getXPx(), h.getYPx(), 102 h.getDataSetIndex(), -1, h.getAxis()); 103 } 104 } 105 106 /** 107 * Returns the bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be 108 * found in the charts data. Performance-intensive code should use void getBarBounds(BarEntry, RectF) instead. 109 * 110 * @param e 111 * @return 112 */ getBarBounds(BarEntry e)113 public RectF getBarBounds(BarEntry e) { 114 115 RectF bounds = new RectF(); 116 getBarBounds(e, bounds); 117 118 return bounds; 119 } 120 121 /** 122 * The passed outputRect will be assigned the values of the bounding box of the specified Entry in the specified DataSet. 123 * The rect will be assigned Float.MIN_VALUE in all locations if the Entry could not be found in the charts data. 124 * 125 * @param e 126 * @return 127 */ getBarBounds(BarEntry e, RectF outputRect)128 public void getBarBounds(BarEntry e, RectF outputRect) { 129 130 RectF bounds = outputRect; 131 132 IBarDataSet set = mData.getDataSetForEntry(e); 133 134 if (set == null) { 135 bounds.set(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE); 136 return; 137 } 138 139 float y = e.getY(); 140 float x = e.getX(); 141 142 float barWidth = mData.getBarWidth(); 143 144 float left = x - barWidth / 2f; 145 float right = x + barWidth / 2f; 146 float top = y >= 0 ? y : 0; 147 float bottom = y <= 0 ? y : 0; 148 149 bounds.set(left, top, right, bottom); 150 151 getTransformer(set.getAxisDependency()).rectValueToPixel(outputRect); 152 } 153 154 /** 155 * If set to true, all values are drawn above their bars, instead of below their top. 156 * 157 * @param enabled 158 */ setDrawValueAboveBar(boolean enabled)159 public void setDrawValueAboveBar(boolean enabled) { 160 mDrawValueAboveBar = enabled; 161 } 162 163 /** 164 * returns true if drawing values above bars is enabled, false if not 165 * 166 * @return 167 */ isDrawValueAboveBarEnabled()168 public boolean isDrawValueAboveBarEnabled() { 169 return mDrawValueAboveBar; 170 } 171 172 /** 173 * If set to true, a grey area is drawn behind each bar that indicates the maximum value. Enabling his will reduce 174 * performance by about 50%. 175 * 176 * @param enabled 177 */ setDrawBarShadow(boolean enabled)178 public void setDrawBarShadow(boolean enabled) { 179 mDrawBarShadow = enabled; 180 } 181 182 /** 183 * returns true if drawing shadows (maxvalue) for each bar is enabled, false if not 184 * 185 * @return 186 */ isDrawBarShadowEnabled()187 public boolean isDrawBarShadowEnabled() { 188 return mDrawBarShadow; 189 } 190 191 /** 192 * Set this to true to make the highlight operation full-bar oriented, false to make it highlight single values (relevant 193 * only for stacked). If enabled, highlighting operations will highlight the whole bar, even if only a single stack entry 194 * was tapped. 195 * Default: false 196 * 197 * @param enabled 198 */ setHighlightFullBarEnabled(boolean enabled)199 public void setHighlightFullBarEnabled(boolean enabled) { 200 mHighlightFullBarEnabled = enabled; 201 } 202 203 /** 204 * @return true the highlight operation is be full-bar oriented, false if single-value 205 */ 206 @Override isHighlightFullBarEnabled()207 public boolean isHighlightFullBarEnabled() { 208 return mHighlightFullBarEnabled; 209 } 210 211 /** 212 * Highlights the value at the given x-value in the given DataSet. Provide 213 * -1 as the dataSetIndex to undo all highlighting. 214 * 215 * @param x 216 * @param dataSetIndex 217 * @param stackIndex the index inside the stack - only relevant for stacked entries 218 */ highlightValue(float x, int dataSetIndex, int stackIndex)219 public void highlightValue(float x, int dataSetIndex, int stackIndex) { 220 highlightValue(new Highlight(x, dataSetIndex, stackIndex), false); 221 } 222 223 @Override getBarData()224 public BarData getBarData() { 225 return mData; 226 } 227 228 /** 229 * 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 230 * fully displayed. 231 * Default: false 232 * 233 * @param enabled 234 */ setFitBars(boolean enabled)235 public void setFitBars(boolean enabled) { 236 mFitBars = enabled; 237 } 238 239 /** 240 * Groups all BarDataSet objects this data object holds together by modifying the x-value of their entries. 241 * Previously set x-values of entries will be overwritten. Leaves space between bars and groups as specified 242 * by the parameters. 243 * Calls notifyDataSetChanged() afterwards. 244 * 245 * @param fromX the starting point on the x-axis where the grouping should begin 246 * @param groupSpace the space between groups of bars in values (not pixels) e.g. 0.8f for bar width 1f 247 * @param barSpace the space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f 248 */ groupBars(float fromX, float groupSpace, float barSpace)249 public void groupBars(float fromX, float groupSpace, float barSpace) { 250 251 if (getBarData() == null) { 252 throw new RuntimeException("You need to set data for the chart before grouping bars."); 253 } else { 254 getBarData().groupBars(fromX, groupSpace, barSpace); 255 notifyDataSetChanged(); 256 } 257 } 258 } 259