• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.XAxis.XAxisPosition;
9 import com.github.mikephil.charting.components.YAxis.AxisDependency;
10 import com.github.mikephil.charting.data.BarEntry;
11 import com.github.mikephil.charting.data.Entry;
12 import com.github.mikephil.charting.highlight.Highlight;
13 import com.github.mikephil.charting.highlight.HorizontalBarHighlighter;
14 import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
15 import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer;
16 import com.github.mikephil.charting.renderer.XAxisRendererHorizontalBarChart;
17 import com.github.mikephil.charting.renderer.YAxisRendererHorizontalBarChart;
18 import com.github.mikephil.charting.utils.HorizontalViewPortHandler;
19 import com.github.mikephil.charting.utils.MPPointF;
20 import com.github.mikephil.charting.utils.TransformerHorizontalBarChart;
21 import com.github.mikephil.charting.utils.Utils;
22 
23 /**
24  * BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched, meaning the YAxis class
25  * represents the horizontal values and the XAxis class represents the vertical values.
26  *
27  * @author Philipp Jahoda
28  */
29 public class HorizontalBarChart extends BarChart {
30 
HorizontalBarChart(Context context)31     public HorizontalBarChart(Context context) {
32         super(context);
33     }
34 
HorizontalBarChart(Context context, AttributeSet attrs)35     public HorizontalBarChart(Context context, AttributeSet attrs) {
36         super(context, attrs);
37     }
38 
HorizontalBarChart(Context context, AttributeSet attrs, int defStyle)39     public HorizontalBarChart(Context context, AttributeSet attrs, int defStyle) {
40         super(context, attrs, defStyle);
41     }
42 
43     @Override
init()44     protected void init() {
45 
46         mViewPortHandler = new HorizontalViewPortHandler();
47 
48         super.init();
49 
50         mLeftAxisTransformer = new TransformerHorizontalBarChart(mViewPortHandler);
51         mRightAxisTransformer = new TransformerHorizontalBarChart(mViewPortHandler);
52 
53         mRenderer = new HorizontalBarChartRenderer(this, mAnimator, mViewPortHandler);
54         setHighlighter(new HorizontalBarHighlighter(this));
55 
56         mAxisRendererLeft = new YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisLeft, mLeftAxisTransformer);
57         mAxisRendererRight = new YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisRight, mRightAxisTransformer);
58         mXAxisRenderer = new XAxisRendererHorizontalBarChart(mViewPortHandler, mXAxis, mLeftAxisTransformer, this);
59     }
60 
61     private RectF mOffsetsBuffer = new RectF();
62 
calculateLegendOffsets(RectF offsets)63     protected void calculateLegendOffsets(RectF offsets) {
64 
65         offsets.left = 0.f;
66         offsets.right = 0.f;
67         offsets.top = 0.f;
68         offsets.bottom = 0.f;
69 
70         if (mLegend == null || !mLegend.isEnabled() || mLegend.isDrawInsideEnabled())
71             return;
72 
73         switch (mLegend.getOrientation()) {
74             case VERTICAL:
75 
76                 switch (mLegend.getHorizontalAlignment()) {
77                     case LEFT:
78                         offsets.left += Math.min(mLegend.mNeededWidth,
79                                 mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
80                                 + mLegend.getXOffset();
81                         break;
82 
83                     case RIGHT:
84                         offsets.right += Math.min(mLegend.mNeededWidth,
85                                 mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
86                                 + mLegend.getXOffset();
87                         break;
88 
89                     case CENTER:
90 
91                         switch (mLegend.getVerticalAlignment()) {
92                             case TOP:
93                                 offsets.top += Math.min(mLegend.mNeededHeight,
94                                         mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
95                                         + mLegend.getYOffset();
96                                 break;
97 
98                             case BOTTOM:
99                                 offsets.bottom += Math.min(mLegend.mNeededHeight,
100                                         mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
101                                         + mLegend.getYOffset();
102                                 break;
103 
104                             default:
105                                 break;
106                         }
107                 }
108 
109                 break;
110 
111             case HORIZONTAL:
112 
113                 switch (mLegend.getVerticalAlignment()) {
114                     case TOP:
115                         offsets.top += Math.min(mLegend.mNeededHeight,
116                                 mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
117                                 + mLegend.getYOffset();
118 
119                         if (mAxisLeft.isEnabled() && mAxisLeft.isDrawLabelsEnabled())
120                             offsets.top += mAxisLeft.getRequiredHeightSpace(
121                                     mAxisRendererLeft.getPaintAxisLabels());
122                         break;
123 
124                     case BOTTOM:
125                         offsets.bottom += Math.min(mLegend.mNeededHeight,
126                                 mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
127                                 + mLegend.getYOffset();
128 
129                         if (mAxisRight.isEnabled() && mAxisRight.isDrawLabelsEnabled())
130                             offsets.bottom += mAxisRight.getRequiredHeightSpace(
131                                     mAxisRendererRight.getPaintAxisLabels());
132                         break;
133 
134                     default:
135                         break;
136                 }
137                 break;
138         }
139     }
140 
141     @Override
calculateOffsets()142     public void calculateOffsets() {
143 
144         float offsetLeft = 0f, offsetRight = 0f, offsetTop = 0f, offsetBottom = 0f;
145 
146         calculateLegendOffsets(mOffsetsBuffer);
147 
148         offsetLeft += mOffsetsBuffer.left;
149         offsetTop += mOffsetsBuffer.top;
150         offsetRight += mOffsetsBuffer.right;
151         offsetBottom += mOffsetsBuffer.bottom;
152 
153         // offsets for y-labels
154         if (mAxisLeft.needsOffset()) {
155             offsetTop += mAxisLeft.getRequiredHeightSpace(mAxisRendererLeft.getPaintAxisLabels());
156         }
157 
158         if (mAxisRight.needsOffset()) {
159             offsetBottom += mAxisRight.getRequiredHeightSpace(mAxisRendererRight.getPaintAxisLabels());
160         }
161 
162         float xlabelwidth = mXAxis.mLabelRotatedWidth;
163 
164         if (mXAxis.isEnabled()) {
165 
166             // offsets for x-labels
167             if (mXAxis.getPosition() == XAxisPosition.BOTTOM) {
168 
169                 offsetLeft += xlabelwidth;
170 
171             } else if (mXAxis.getPosition() == XAxisPosition.TOP) {
172 
173                 offsetRight += xlabelwidth;
174 
175             } else if (mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) {
176 
177                 offsetLeft += xlabelwidth;
178                 offsetRight += xlabelwidth;
179             }
180         }
181 
182         offsetTop += getExtraTopOffset();
183         offsetRight += getExtraRightOffset();
184         offsetBottom += getExtraBottomOffset();
185         offsetLeft += getExtraLeftOffset();
186 
187         float minOffset = Utils.convertDpToPixel(mMinOffset);
188 
189         mViewPortHandler.restrainViewPort(
190                 Math.max(minOffset, offsetLeft),
191                 Math.max(minOffset, offsetTop),
192                 Math.max(minOffset, offsetRight),
193                 Math.max(minOffset, offsetBottom));
194 
195         if (mLogEnabled) {
196             Log.i(LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " +
197                     offsetRight + ", offsetBottom: "
198                     + offsetBottom);
199             Log.i(LOG_TAG, "Content: " + mViewPortHandler.getContentRect().toString());
200         }
201 
202         prepareOffsetMatrix();
203         prepareValuePxMatrix();
204     }
205 
206     @Override
prepareValuePxMatrix()207     protected void prepareValuePxMatrix() {
208         mRightAxisTransformer.prepareMatrixValuePx(mAxisRight.mAxisMinimum, mAxisRight.mAxisRange, mXAxis.mAxisRange,
209                 mXAxis.mAxisMinimum);
210         mLeftAxisTransformer.prepareMatrixValuePx(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisRange, mXAxis.mAxisRange,
211                 mXAxis.mAxisMinimum);
212     }
213 
214     @Override
getMarkerPosition(Highlight high)215     protected float[] getMarkerPosition(Highlight high) {
216         return new float[]{high.getDrawY(), high.getDrawX()};
217     }
218 
219     @Override
getBarBounds(BarEntry e, RectF outputRect)220     public void getBarBounds(BarEntry e, RectF outputRect) {
221 
222         RectF bounds = outputRect;
223         IBarDataSet set = mData.getDataSetForEntry(e);
224 
225         if (set == null) {
226             outputRect.set(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
227             return;
228         }
229 
230         float y = e.getY();
231         float x = e.getX();
232 
233         float barWidth = mData.getBarWidth();
234 
235         float top = x - barWidth / 2f;
236         float bottom = x + barWidth / 2f;
237         float left = y >= 0 ? y : 0;
238         float right = y <= 0 ? y : 0;
239 
240         bounds.set(left, top, right, bottom);
241 
242         getTransformer(set.getAxisDependency()).rectValueToPixel(bounds);
243 
244     }
245 
246     protected float[] mGetPositionBuffer = new float[2];
247 
248     /**
249      * Returns a recyclable MPPointF instance.
250      *
251      * @param e
252      * @param axis
253      * @return
254      */
255     @Override
getPosition(Entry e, AxisDependency axis)256     public MPPointF getPosition(Entry e, AxisDependency axis) {
257 
258         if (e == null)
259             return null;
260 
261         float[] vals = mGetPositionBuffer;
262         vals[0] = e.getY();
263         vals[1] = e.getX();
264 
265         getTransformer(axis).pointValuesToPixel(vals);
266 
267         return MPPointF.getInstance(vals[0], vals[1]);
268     }
269 
270     /**
271      * Returns the Highlight object (contains x-index and DataSet index) of the selected value at the given touch point
272      * inside the BarChart.
273      *
274      * @param x
275      * @param y
276      * @return
277      */
278     @Override
getHighlightByTouchPoint(float x, float y)279     public Highlight getHighlightByTouchPoint(float x, float y) {
280 
281         if (mData == null) {
282             if (mLogEnabled)
283                 Log.e(LOG_TAG, "Can't select by touch. No data set.");
284             return null;
285         } else
286             return getHighlighter().getHighlight(y, x); // switch x and y
287     }
288 
289     @Override
getLowestVisibleX()290     public float getLowestVisibleX() {
291         getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(),
292                 mViewPortHandler.contentBottom(), posForGetLowestVisibleX);
293         float result = (float) Math.max(mXAxis.mAxisMinimum, posForGetLowestVisibleX.y);
294         return result;
295     }
296 
297     @Override
getHighestVisibleX()298     public float getHighestVisibleX() {
299         getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(),
300                 mViewPortHandler.contentTop(), posForGetHighestVisibleX);
301         float result = (float) Math.min(mXAxis.mAxisMaximum, posForGetHighestVisibleX.y);
302         return result;
303     }
304 
305     /**
306      * ###### VIEWPORT METHODS BELOW THIS ######
307      */
308 
309     @Override
setVisibleXRangeMaximum(float maxXRange)310     public void setVisibleXRangeMaximum(float maxXRange) {
311         float xScale = mXAxis.mAxisRange / (maxXRange);
312         mViewPortHandler.setMinimumScaleY(xScale);
313     }
314 
315     @Override
setVisibleXRangeMinimum(float minXRange)316     public void setVisibleXRangeMinimum(float minXRange) {
317         float xScale = mXAxis.mAxisRange / (minXRange);
318         mViewPortHandler.setMaximumScaleY(xScale);
319     }
320 
321     @Override
setVisibleXRange(float minXRange, float maxXRange)322     public void setVisibleXRange(float minXRange, float maxXRange) {
323         float minScale = mXAxis.mAxisRange / minXRange;
324         float maxScale = mXAxis.mAxisRange / maxXRange;
325         mViewPortHandler.setMinMaxScaleY(minScale, maxScale);
326     }
327 
328     @Override
setVisibleYRangeMaximum(float maxYRange, AxisDependency axis)329     public void setVisibleYRangeMaximum(float maxYRange, AxisDependency axis) {
330         float yScale = getAxisRange(axis) / maxYRange;
331         mViewPortHandler.setMinimumScaleX(yScale);
332     }
333 
334     @Override
setVisibleYRangeMinimum(float minYRange, AxisDependency axis)335     public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) {
336         float yScale = getAxisRange(axis) / minYRange;
337         mViewPortHandler.setMaximumScaleX(yScale);
338     }
339 
340     @Override
setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis)341     public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis) {
342         float minScale = getAxisRange(axis) / minYRange;
343         float maxScale = getAxisRange(axis) / maxYRange;
344         mViewPortHandler.setMinMaxScaleX(minScale, maxScale);
345     }
346 }
347