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 android.graphics.RectF; import com.github.mikephil.charting.components.LimitLine; 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.MPPointD; 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; protected Paint mZeroLinePaint; public YAxisRenderer(ViewPortHandler viewPortHandler, YAxis yAxis, Transformer trans) { super(viewPortHandler, trans, yAxis); this.mYAxis = yAxis; if(mViewPortHandler != null) { mAxisLabelPaint.setColor(Color.BLACK); mAxisLabelPaint.setTextSize(Utils.convertDpToPixel(10f)); mZeroLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mZeroLinePaint.setColor(Color.GRAY); mZeroLinePaint.setStrokeWidth(1f); mZeroLinePaint.setStyle(Paint.Style.STROKE); } } /** * draws the y-axis labels to the screen */ @Override public void renderAxisLabels(Canvas c) { if (!mYAxis.isEnabled() || !mYAxis.isDrawLabelsEnabled()) return; float[] positions = getTransformedPositions(); mAxisLabelPaint.setTypeface(mYAxis.getTypeface()); mAxisLabelPaint.setTextSize(mYAxis.getTextSize()); mAxisLabelPaint.setColor(mYAxis.getTextColor()); float xoffset = mYAxis.getXOffset(); float yoffset = Utils.calcTextHeight(mAxisLabelPaint, "A") / 2.5f + mYAxis.getYOffset(); 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) { final int from = mYAxis.isDrawBottomYLabelEntryEnabled() ? 0 : 1; final int to = mYAxis.isDrawTopYLabelEntryEnabled() ? mYAxis.mEntryCount : (mYAxis.mEntryCount - 1); // draw for (int i = from; i < to; i++) { String text = mYAxis.getFormattedLabel(i); c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset, mAxisLabelPaint); } } protected Path mRenderGridLinesPath = new Path(); @Override public void renderGridLines(Canvas c) { if (!mYAxis.isEnabled()) return; if (mYAxis.isDrawGridLinesEnabled()) { int clipRestoreCount = c.save(); c.clipRect(getGridClippingRect()); float[] positions = getTransformedPositions(); mGridPaint.setColor(mYAxis.getGridColor()); mGridPaint.setStrokeWidth(mYAxis.getGridLineWidth()); mGridPaint.setPathEffect(mYAxis.getGridDashPathEffect()); Path gridLinePath = mRenderGridLinesPath; gridLinePath.reset(); // draw the grid for (int i = 0; i < positions.length; i += 2) { // draw a path because lines don't support dashing on lower android versions c.drawPath(linePath(gridLinePath, i, positions), mGridPaint); gridLinePath.reset(); } c.restoreToCount(clipRestoreCount); } if (mYAxis.isDrawZeroLineEnabled()) { drawZeroLine(c); } } protected RectF mGridClippingRect = new RectF(); public RectF getGridClippingRect() { mGridClippingRect.set(mViewPortHandler.getContentRect()); mGridClippingRect.inset(0.f, -mAxis.getGridLineWidth()); return mGridClippingRect; } /** * Calculates the path for a grid line. * * @param p * @param i * @param positions * @return */ protected Path linePath(Path p, int i, float[] positions) { p.moveTo(mViewPortHandler.offsetLeft(), positions[i + 1]); p.lineTo(mViewPortHandler.contentRight(), positions[i + 1]); return p; } protected float[] mGetTransformedPositionsBuffer = new float[2]; /** * Transforms the values contained in the axis entries to screen pixels and returns them in form of a float array * of x- and y-coordinates. * * @return */ protected float[] getTransformedPositions() { if(mGetTransformedPositionsBuffer.length != mYAxis.mEntryCount * 2){ mGetTransformedPositionsBuffer = new float[mYAxis.mEntryCount * 2]; } float[] positions = mGetTransformedPositionsBuffer; for (int i = 0; i < positions.length; i += 2) { // only fill y values, x values are not needed for y-labels positions[i + 1] = mYAxis.mEntries[i / 2]; } mTrans.pointValuesToPixel(positions); return positions; } protected Path mDrawZeroLinePath = new Path(); protected RectF mZeroLineClippingRect = new RectF(); /** * Draws the zero line. */ protected void drawZeroLine(Canvas c) { int clipRestoreCount = c.save(); mZeroLineClippingRect.set(mViewPortHandler.getContentRect()); mZeroLineClippingRect.inset(0.f, -mYAxis.getZeroLineWidth()); c.clipRect(mZeroLineClippingRect); // draw zero line MPPointD pos = mTrans.getPixelForValues(0f, 0f); mZeroLinePaint.setColor(mYAxis.getZeroLineColor()); mZeroLinePaint.setStrokeWidth(mYAxis.getZeroLineWidth()); Path zeroLinePath = mDrawZeroLinePath; zeroLinePath.reset(); zeroLinePath.moveTo(mViewPortHandler.contentLeft(), (float) pos.y); zeroLinePath.lineTo(mViewPortHandler.contentRight(), (float) pos.y); // draw a path because lines don't support dashing on lower android versions c.drawPath(zeroLinePath, mZeroLinePaint); c.restoreToCount(clipRestoreCount); } protected Path mRenderLimitLines = new Path(); protected float[] mRenderLimitLinesBuffer = new float[2]; protected RectF mLimitLineClippingRect = new RectF(); /** * 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 = mRenderLimitLinesBuffer; pts[0] = 0; pts[1] = 0; Path limitLinePath = mRenderLimitLines; limitLinePath.reset(); for (int i = 0; i < limitLines.size(); i++) { LimitLine l = limitLines.get(i); if (!l.isEnabled()) continue; int clipRestoreCount = c.save(); mLimitLineClippingRect.set(mViewPortHandler.getContentRect()); mLimitLineClippingRect.inset(0.f, -l.getLineWidth()); c.clipRect(mLimitLineClippingRect); 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("")) { mLimitLinePaint.setStyle(l.getTextStyle()); mLimitLinePaint.setPathEffect(null); mLimitLinePaint.setColor(l.getTextColor()); mLimitLinePaint.setTypeface(l.getTypeface()); mLimitLinePaint.setStrokeWidth(0.5f); mLimitLinePaint.setTextSize(l.getTextSize()); final float labelLineHeight = Utils.calcTextHeight(mLimitLinePaint, label); float xOffset = Utils.convertDpToPixel(4f) + l.getXOffset(); float yOffset = l.getLineWidth() + labelLineHeight + l.getYOffset(); final LimitLine.LimitLabelPosition position = l.getLabelPosition(); if (position == LimitLine.LimitLabelPosition.RIGHT_TOP) { mLimitLinePaint.setTextAlign(Align.RIGHT); c.drawText(label, mViewPortHandler.contentRight() - xOffset, pts[1] - yOffset + labelLineHeight, mLimitLinePaint); } else if (position == LimitLine.LimitLabelPosition.RIGHT_BOTTOM) { mLimitLinePaint.setTextAlign(Align.RIGHT); c.drawText(label, mViewPortHandler.contentRight() - xOffset, pts[1] + yOffset, mLimitLinePaint); } else if (position == LimitLine.LimitLabelPosition.LEFT_TOP) { mLimitLinePaint.setTextAlign(Align.LEFT); c.drawText(label, mViewPortHandler.contentLeft() + xOffset, pts[1] - yOffset + labelLineHeight, mLimitLinePaint); } else { mLimitLinePaint.setTextAlign(Align.LEFT); c.drawText(label, mViewPortHandler.offsetLeft() + xOffset, pts[1] + yOffset, mLimitLinePaint); } } c.restoreToCount(clipRestoreCount); } } }