package com.github.mikephil.charting.renderer; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Path; import com.github.mikephil.charting.components.LimitLine; import com.github.mikephil.charting.components.LimitLine.LimitLabelPosition; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis.AxisDependency; import com.github.mikephil.charting.components.YAxis.YAxisLabelPosition; import com.github.mikephil.charting.utils.PointD; import com.github.mikephil.charting.utils.Transformer; import com.github.mikephil.charting.utils.Utils; import com.github.mikephil.charting.utils.ViewPortHandler; import java.util.List; public class YAxisRenderer extends AxisRenderer { protected YAxis mYAxis; public YAxisRenderer(ViewPortHandler viewPortHandler, YAxis yAxis, Transformer trans) { super(viewPortHandler, trans); this.mYAxis = yAxis; mAxisLabelPaint.setColor(Color.BLACK); mAxisLabelPaint.setTextSize(Utils.convertDpToPixel(10f)); } /** * Computes the axis values. * * @param yMin - the minimum y-value in the data object for this axis * @param yMax - the maximum y-value in the data object for this axis */ public void computeAxis(float yMin, float yMax) { // calculate the starting and entry point of the y-labels (depending on // zoom / contentrect bounds) if (mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutY()) { PointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop()); PointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom()); if (!mYAxis.isInverted()) { yMin = (float) p2.y; yMax = (float) p1.y; } else { yMin = (float) p1.y; yMax = (float) p2.y; } } computeAxisValues(yMin, yMax); } /** * Sets up the y-axis labels. Computes the desired number of labels between * the two given extremes. Unlike the papareXLabels() method, this method * needs to be called upon every refresh of the view. * * @return */ protected void computeAxisValues(float min, float max) { float yMin = min; float yMax = max; int labelCount = mYAxis.getLabelCount(); double range = Math.abs(yMax - yMin); if (labelCount == 0 || range <= 0) { mYAxis.mEntries = new float[] {}; mYAxis.mEntryCount = 0; return; } double rawInterval = range / labelCount; double interval = Utils.roundToNextSignificant(rawInterval); double intervalMagnitude = Math.pow(10, (int) Math.log10(interval)); int intervalSigDigit = (int) (interval / intervalMagnitude); if (intervalSigDigit > 5) { // Use one order of magnitude higher, to avoid intervals like 0.9 or // 90 interval = Math.floor(10 * intervalMagnitude); } // if the labels should only show min and max if (mYAxis.isShowOnlyMinMaxEnabled()) { mYAxis.mEntryCount = 2; mYAxis.mEntries = new float[2]; mYAxis.mEntries[0] = yMin; mYAxis.mEntries[1] = yMax; } else { double first = Math.ceil(yMin / interval) * interval; double last = Utils.nextUp(Math.floor(yMax / interval) * interval); double f; int i; int n = 0; for (f = first; f <= last; f += interval) { ++n; } mYAxis.mEntryCount = n; if (mYAxis.mEntries.length < n) { // Ensure stops contains at least numStops elements. mYAxis.mEntries = new float[n]; } for (f = first, i = 0; i < n; f += interval, ++i) { mYAxis.mEntries[i] = (float) f; } } if (interval < 1) { mYAxis.mDecimals = (int) Math.ceil(-Math.log10(interval)); } else { mYAxis.mDecimals = 0; } } /** * draws the y-axis labels to the screen */ @Override public void renderAxisLabels(Canvas c) { if (!mYAxis.isEnabled() || !mYAxis.isDrawLabelsEnabled()) return; float[] positions = new float[mYAxis.mEntryCount * 2]; for (int i = 0; i < positions.length; i += 2) { // only fill y values, x values are not needed since the y-labels // are // static on the x-axis positions[i + 1] = mYAxis.mEntries[i / 2]; } mTrans.pointValuesToPixel(positions); mAxisLabelPaint.setTypeface(mYAxis.getTypeface()); mAxisLabelPaint.setTextSize(mYAxis.getTextSize()); mAxisLabelPaint.setColor(mYAxis.getTextColor()); float xoffset = mYAxis.getXOffset(); float yoffset = Utils.calcTextHeight(mAxisLabelPaint, "A") / 2.5f; AxisDependency dependency = mYAxis.getAxisDependency(); YAxisLabelPosition labelPosition = mYAxis.getLabelPosition(); float xPos = 0f; if (dependency == AxisDependency.LEFT) { if (labelPosition == YAxisLabelPosition.OUTSIDE_CHART) { mAxisLabelPaint.setTextAlign(Align.RIGHT); xPos = mViewPortHandler.offsetLeft() - xoffset; } else { mAxisLabelPaint.setTextAlign(Align.LEFT); xPos = mViewPortHandler.offsetLeft() + xoffset; } } else { if (labelPosition == YAxisLabelPosition.OUTSIDE_CHART) { mAxisLabelPaint.setTextAlign(Align.LEFT); xPos = mViewPortHandler.contentRight() + xoffset; } else { mAxisLabelPaint.setTextAlign(Align.RIGHT); xPos = mViewPortHandler.contentRight() - xoffset; } } drawYLabels(c, xPos, positions, yoffset); } @Override public void renderAxisLine(Canvas c) { if (!mYAxis.isEnabled() || !mYAxis.isDrawAxisLineEnabled()) return; mAxisLinePaint.setColor(mYAxis.getAxisLineColor()); mAxisLinePaint.setStrokeWidth(mYAxis.getAxisLineWidth()); if (mYAxis.getAxisDependency() == AxisDependency.LEFT) { c.drawLine(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom(), mAxisLinePaint); } else { c.drawLine(mViewPortHandler.contentRight(), mViewPortHandler.contentTop(), mViewPortHandler.contentRight(), mViewPortHandler.contentBottom(), mAxisLinePaint); } } /** * draws the y-labels on the specified x-position * * @param fixedPosition * @param positions */ protected void drawYLabels(Canvas c, float fixedPosition, float[] positions, float offset) { // draw for (int i = 0; i < mYAxis.mEntryCount; i++) { String text = mYAxis.getFormattedLabel(i); if (!mYAxis.isDrawTopYLabelEntryEnabled() && i >= mYAxis.mEntryCount - 1) return; c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset, mAxisLabelPaint); } } @Override public void renderGridLines(Canvas c) { if (!mYAxis.isDrawGridLinesEnabled() || !mYAxis.isEnabled()) return; // pre alloc float[] position = new float[2]; mGridPaint.setColor(mYAxis.getGridColor()); mGridPaint.setStrokeWidth(mYAxis.getGridLineWidth()); mGridPaint.setPathEffect(mYAxis.getGridDashPathEffect()); Path gridLinePath = new Path(); // draw the horizontal grid for (int i = 0; i < mYAxis.mEntryCount; i++) { position[1] = mYAxis.mEntries[i]; mTrans.pointValuesToPixel(position); gridLinePath.moveTo(mViewPortHandler.offsetLeft(), position[1]); gridLinePath.lineTo(mViewPortHandler.contentRight(), position[1]); c.drawPath(gridLinePath, mGridPaint); gridLinePath.reset(); } } /** * Draws the LimitLines associated with this axis to the screen. * * @param c */ @Override public void renderLimitLines(Canvas c) { List<LimitLine> limitLines = mYAxis.getLimitLines(); if (limitLines == null || limitLines.size() <= 0) return; float[] pts = new float[2]; Path limitLinePath = new Path(); for (int i = 0; i < limitLines.size(); i++) { LimitLine l = limitLines.get(i); mLimitLinePaint.setStyle(Paint.Style.STROKE); mLimitLinePaint.setColor(l.getLineColor()); mLimitLinePaint.setStrokeWidth(l.getLineWidth()); mLimitLinePaint.setPathEffect(l.getDashPathEffect()); pts[1] = l.getLimit(); mTrans.pointValuesToPixel(pts); limitLinePath.moveTo(mViewPortHandler.contentLeft(), pts[1]); limitLinePath.lineTo(mViewPortHandler.contentRight(), pts[1]); c.drawPath(limitLinePath, mLimitLinePaint); limitLinePath.reset(); // c.drawLines(pts, mLimitLinePaint); String label = l.getLabel(); // if drawing the limit-value label is enabled if (label != null && !label.equals("")) { float xOffset = Utils.convertDpToPixel(4f); float yOffset = l.getLineWidth() + Utils.calcTextHeight(mLimitLinePaint, label) / 2f; mLimitLinePaint.setStyle(l.getTextStyle()); mLimitLinePaint.setPathEffect(null); mLimitLinePaint.setColor(l.getTextColor()); mLimitLinePaint.setStrokeWidth(0.5f); mLimitLinePaint.setTextSize(l.getTextSize()); if (l.getLabelPosition() == LimitLabelPosition.POS_RIGHT) { mLimitLinePaint.setTextAlign(Align.RIGHT); c.drawText(label, mViewPortHandler.contentRight() - xOffset, pts[1] - yOffset, mLimitLinePaint); } else { mLimitLinePaint.setTextAlign(Align.LEFT); c.drawText(label, mViewPortHandler.offsetLeft() + xOffset, pts[1] - yOffset, mLimitLinePaint); } } } } }