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.XAxis.XAxisPosition; import com.github.mikephil.charting.components.YAxis.AxisDependency; import com.github.mikephil.charting.data.BarEntry; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.highlight.Highlight; import com.github.mikephil.charting.highlight.HorizontalBarHighlighter; import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer; import com.github.mikephil.charting.renderer.XAxisRendererHorizontalBarChart; import com.github.mikephil.charting.renderer.YAxisRendererHorizontalBarChart; import com.github.mikephil.charting.utils.HorizontalViewPortHandler; import com.github.mikephil.charting.utils.MPPointF; import com.github.mikephil.charting.utils.TransformerHorizontalBarChart; import com.github.mikephil.charting.utils.Utils; /** * BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched, meaning the YAxis class * represents the horizontal values and the XAxis class represents the vertical values. * * @author Philipp Jahoda */ public class HorizontalBarChart extends BarChart { public HorizontalBarChart(Context context) { super(context); } public HorizontalBarChart(Context context, AttributeSet attrs) { super(context, attrs); } public HorizontalBarChart(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void init() { mViewPortHandler = new HorizontalViewPortHandler(); super.init(); mLeftAxisTransformer = new TransformerHorizontalBarChart(mViewPortHandler); mRightAxisTransformer = new TransformerHorizontalBarChart(mViewPortHandler); mRenderer = new HorizontalBarChartRenderer(this, mAnimator, mViewPortHandler); setHighlighter(new HorizontalBarHighlighter(this)); mAxisRendererLeft = new YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisLeft, mLeftAxisTransformer); mAxisRendererRight = new YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisRight, mRightAxisTransformer); mXAxisRenderer = new XAxisRendererHorizontalBarChart(mViewPortHandler, mXAxis, mLeftAxisTransformer, this); } private RectF mOffsetsBuffer = new RectF(); @Override public void calculateOffsets() { float offsetLeft = 0f, offsetRight = 0f, offsetTop = 0f, offsetBottom = 0f; calculateLegendOffsets(mOffsetsBuffer); offsetLeft += mOffsetsBuffer.left; offsetTop += mOffsetsBuffer.top; offsetRight += mOffsetsBuffer.right; offsetBottom += mOffsetsBuffer.bottom; // offsets for y-labels if (mAxisLeft.needsOffset()) { offsetTop += mAxisLeft.getRequiredHeightSpace(mAxisRendererLeft.getPaintAxisLabels()); } if (mAxisRight.needsOffset()) { offsetBottom += mAxisRight.getRequiredHeightSpace(mAxisRendererRight.getPaintAxisLabels()); } float xlabelwidth = mXAxis.mLabelRotatedWidth; if (mXAxis.isEnabled()) { // offsets for x-labels if (mXAxis.getPosition() == XAxisPosition.BOTTOM) { offsetLeft += xlabelwidth; } else if (mXAxis.getPosition() == XAxisPosition.TOP) { offsetRight += xlabelwidth; } else if (mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { offsetLeft += xlabelwidth; offsetRight += xlabelwidth; } } offsetTop += getExtraTopOffset(); offsetRight += getExtraRightOffset(); offsetBottom += getExtraBottomOffset(); offsetLeft += getExtraLeftOffset(); float minOffset = Utils.convertDpToPixel(mMinOffset); mViewPortHandler.restrainViewPort( Math.max(minOffset, offsetLeft), Math.max(minOffset, offsetTop), Math.max(minOffset, offsetRight), Math.max(minOffset, offsetBottom)); if (mLogEnabled) { Log.i(LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); Log.i(LOG_TAG, "Content: " + mViewPortHandler.getContentRect().toString()); } prepareOffsetMatrix(); prepareValuePxMatrix(); } @Override protected void prepareValuePxMatrix() { mRightAxisTransformer.prepareMatrixValuePx(mAxisRight.mAxisMinimum, mAxisRight.mAxisRange, mXAxis.mAxisRange, mXAxis.mAxisMinimum); mLeftAxisTransformer.prepareMatrixValuePx(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisRange, mXAxis.mAxisRange, mXAxis.mAxisMinimum); } @Override protected float[] getMarkerPosition(Highlight high) { return new float[]{high.getDrawY(), high.getDrawX()}; } @Override public void getBarBounds(BarEntry e, RectF outputRect) { RectF bounds = outputRect; IBarDataSet set = mData.getDataSetForEntry(e); if (set == null) { outputRect.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 top = x - barWidth / 2f; float bottom = x + barWidth / 2f; float left = y >= 0 ? y : 0; float right = y <= 0 ? y : 0; bounds.set(left, top, right, bottom); getTransformer(set.getAxisDependency()).rectValueToPixel(bounds); } protected float[] mGetPositionBuffer = new float[2]; /** * Returns a recyclable MPPointF instance. * * @param e * @param axis * @return */ @Override public MPPointF getPosition(Entry e, AxisDependency axis) { if (e == null) return null; float[] vals = mGetPositionBuffer; vals[0] = e.getY(); vals[1] = e.getX(); getTransformer(axis).pointValuesToPixel(vals); return MPPointF.getInstance(vals[0], vals[1]); } /** * 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) { if (mLogEnabled) Log.e(LOG_TAG, "Can't select by touch. No data set."); return null; } else return getHighlighter().getHighlight(y, x); // switch x and y } @Override public float getLowestVisibleX() { getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom(), posForGetLowestVisibleX); float result = (float) Math.max(mXAxis.mAxisMinimum, posForGetLowestVisibleX.y); return result; } @Override public float getHighestVisibleX() { getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), posForGetHighestVisibleX); float result = (float) Math.min(mXAxis.mAxisMaximum, posForGetHighestVisibleX.y); return result; } /** * ###### VIEWPORT METHODS BELOW THIS ###### */ @Override public void setVisibleXRangeMaximum(float maxXRange) { float xScale = mXAxis.mAxisRange / (maxXRange); mViewPortHandler.setMinimumScaleY(xScale); } @Override public void setVisibleXRangeMinimum(float minXRange) { float xScale = mXAxis.mAxisRange / (minXRange); mViewPortHandler.setMaximumScaleY(xScale); } @Override public void setVisibleXRange(float minXRange, float maxXRange) { float minScale = mXAxis.mAxisRange / minXRange; float maxScale = mXAxis.mAxisRange / maxXRange; mViewPortHandler.setMinMaxScaleY(minScale, maxScale); } @Override public void setVisibleYRangeMaximum(float maxYRange, AxisDependency axis) { float yScale = getAxisRange(axis) / maxYRange; mViewPortHandler.setMinimumScaleX(yScale); } @Override public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) { float yScale = getAxisRange(axis) / minYRange; mViewPortHandler.setMaximumScaleX(yScale); } @Override public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis) { float minScale = getAxisRange(axis) / minYRange; float maxScale = getAxisRange(axis) / maxYRange; mViewPortHandler.setMinMaxScaleX(minScale, maxScale); } }