1 2 package com.github.mikephil.charting.charts; 3 4 import android.content.Context; 5 import android.graphics.Canvas; 6 import android.util.AttributeSet; 7 import android.util.Log; 8 9 import com.github.mikephil.charting.data.BarData; 10 import com.github.mikephil.charting.data.BubbleData; 11 import com.github.mikephil.charting.data.CandleData; 12 import com.github.mikephil.charting.data.CombinedData; 13 import com.github.mikephil.charting.data.Entry; 14 import com.github.mikephil.charting.data.LineData; 15 import com.github.mikephil.charting.data.ScatterData; 16 import com.github.mikephil.charting.highlight.CombinedHighlighter; 17 import com.github.mikephil.charting.highlight.Highlight; 18 import com.github.mikephil.charting.interfaces.dataprovider.CombinedDataProvider; 19 import com.github.mikephil.charting.interfaces.datasets.IDataSet; 20 import com.github.mikephil.charting.renderer.CombinedChartRenderer; 21 22 /** 23 * This chart class allows the combination of lines, bars, scatter and candle 24 * data all displayed in one chart area. 25 * 26 * @author Philipp Jahoda 27 */ 28 public class CombinedChart extends BarLineChartBase<CombinedData> implements CombinedDataProvider { 29 30 /** 31 * if set to true, all values are drawn above their bars, instead of below 32 * their top 33 */ 34 private boolean mDrawValueAboveBar = true; 35 36 37 /** 38 * flag that indicates whether the highlight should be full-bar oriented, or single-value? 39 */ 40 protected boolean mHighlightFullBarEnabled = false; 41 42 /** 43 * if set to true, a grey area is drawn behind each bar that indicates the 44 * maximum value 45 */ 46 private boolean mDrawBarShadow = false; 47 48 protected DrawOrder[] mDrawOrder; 49 50 /** 51 * enum that allows to specify the order in which the different data objects 52 * for the combined-chart are drawn 53 */ 54 public enum DrawOrder { 55 BAR, BUBBLE, LINE, CANDLE, SCATTER 56 } 57 CombinedChart(Context context)58 public CombinedChart(Context context) { 59 super(context); 60 } 61 CombinedChart(Context context, AttributeSet attrs)62 public CombinedChart(Context context, AttributeSet attrs) { 63 super(context, attrs); 64 } 65 CombinedChart(Context context, AttributeSet attrs, int defStyle)66 public CombinedChart(Context context, AttributeSet attrs, int defStyle) { 67 super(context, attrs, defStyle); 68 } 69 70 @Override init()71 protected void init() { 72 super.init(); 73 74 // Default values are not ready here yet 75 mDrawOrder = new DrawOrder[]{ 76 DrawOrder.BAR, DrawOrder.BUBBLE, DrawOrder.LINE, DrawOrder.CANDLE, DrawOrder.SCATTER 77 }; 78 79 setHighlighter(new CombinedHighlighter(this, this)); 80 81 // Old default behaviour 82 setHighlightFullBarEnabled(true); 83 84 mRenderer = new CombinedChartRenderer(this, mAnimator, mViewPortHandler); 85 } 86 87 @Override getCombinedData()88 public CombinedData getCombinedData() { 89 return mData; 90 } 91 92 @Override setData(CombinedData data)93 public void setData(CombinedData data) { 94 super.setData(data); 95 setHighlighter(new CombinedHighlighter(this, this)); 96 ((CombinedChartRenderer)mRenderer).createRenderers(); 97 mRenderer.initBuffers(); 98 } 99 100 /** 101 * Returns the Highlight object (contains x-index and DataSet index) of the selected value at the given touch 102 * point 103 * inside the CombinedChart. 104 * 105 * @param x 106 * @param y 107 * @return 108 */ 109 @Override getHighlightByTouchPoint(float x, float y)110 public Highlight getHighlightByTouchPoint(float x, float y) { 111 112 if (mData == null) { 113 Log.e(LOG_TAG, "Can't select by touch. No data set."); 114 return null; 115 } else { 116 Highlight h = getHighlighter().getHighlight(x, y); 117 if (h == null || !isHighlightFullBarEnabled()) return h; 118 119 // For isHighlightFullBarEnabled, remove stackIndex 120 return new Highlight(h.getX(), h.getY(), 121 h.getXPx(), h.getYPx(), 122 h.getDataSetIndex(), -1, h.getAxis()); 123 } 124 } 125 126 @Override getLineData()127 public LineData getLineData() { 128 if (mData == null) 129 return null; 130 return mData.getLineData(); 131 } 132 133 @Override getBarData()134 public BarData getBarData() { 135 if (mData == null) 136 return null; 137 return mData.getBarData(); 138 } 139 140 @Override getScatterData()141 public ScatterData getScatterData() { 142 if (mData == null) 143 return null; 144 return mData.getScatterData(); 145 } 146 147 @Override getCandleData()148 public CandleData getCandleData() { 149 if (mData == null) 150 return null; 151 return mData.getCandleData(); 152 } 153 154 @Override getBubbleData()155 public BubbleData getBubbleData() { 156 if (mData == null) 157 return null; 158 return mData.getBubbleData(); 159 } 160 161 @Override isDrawBarShadowEnabled()162 public boolean isDrawBarShadowEnabled() { 163 return mDrawBarShadow; 164 } 165 166 @Override isDrawValueAboveBarEnabled()167 public boolean isDrawValueAboveBarEnabled() { 168 return mDrawValueAboveBar; 169 } 170 171 /** 172 * If set to true, all values are drawn above their bars, instead of below 173 * their top. 174 * 175 * @param enabled 176 */ setDrawValueAboveBar(boolean enabled)177 public void setDrawValueAboveBar(boolean enabled) { 178 mDrawValueAboveBar = enabled; 179 } 180 181 182 /** 183 * If set to true, a grey area is drawn behind each bar that indicates the 184 * maximum value. Enabling his will reduce performance by about 50%. 185 * 186 * @param enabled 187 */ setDrawBarShadow(boolean enabled)188 public void setDrawBarShadow(boolean enabled) { 189 mDrawBarShadow = enabled; 190 } 191 192 /** 193 * Set this to true to make the highlight operation full-bar oriented, 194 * false to make it highlight single values (relevant only for stacked). 195 * 196 * @param enabled 197 */ setHighlightFullBarEnabled(boolean enabled)198 public void setHighlightFullBarEnabled(boolean enabled) { 199 mHighlightFullBarEnabled = enabled; 200 } 201 202 /** 203 * @return true the highlight operation is be full-bar oriented, false if single-value 204 */ 205 @Override isHighlightFullBarEnabled()206 public boolean isHighlightFullBarEnabled() { 207 return mHighlightFullBarEnabled; 208 } 209 210 /** 211 * Returns the currently set draw order. 212 * 213 * @return 214 */ getDrawOrder()215 public DrawOrder[] getDrawOrder() { 216 return mDrawOrder; 217 } 218 219 /** 220 * Sets the order in which the provided data objects should be drawn. The 221 * earlier you place them in the provided array, the further they will be in 222 * the background. e.g. if you provide new DrawOrer[] { DrawOrder.BAR, 223 * DrawOrder.LINE }, the bars will be drawn behind the lines. 224 * 225 * @param order 226 */ setDrawOrder(DrawOrder[] order)227 public void setDrawOrder(DrawOrder[] order) { 228 if (order == null || order.length <= 0) 229 return; 230 mDrawOrder = order; 231 } 232 233 /** 234 * draws all MarkerViews on the highlighted positions 235 */ drawMarkers(Canvas canvas)236 protected void drawMarkers(Canvas canvas) { 237 238 // if there is no marker view or drawing marker is disabled 239 if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight()) 240 return; 241 242 for (int i = 0; i < mIndicesToHighlight.length; i++) { 243 244 Highlight highlight = mIndicesToHighlight[i]; 245 246 IDataSet set = mData.getDataSetByHighlight(highlight); 247 248 Entry e = mData.getEntryForHighlight(highlight); 249 if (e == null) 250 continue; 251 252 int entryIndex = set.getEntryIndex(e); 253 254 // make sure entry not null 255 if (entryIndex > set.getEntryCount() * mAnimator.getPhaseX()) 256 continue; 257 258 float[] pos = getMarkerPosition(highlight); 259 260 // check bounds 261 if (!mViewPortHandler.isInBounds(pos[0], pos[1])) 262 continue; 263 264 // callbacks to update the content 265 mMarker.refreshContent(e, highlight); 266 267 // draw the marker 268 mMarker.draw(canvas, pos[0], pos[1]); 269 } 270 } 271 272 } 273