@Override
  public void renderAxisLabels(Canvas c) {

    if (!mYAxis.isEnabled() || !mYAxis.isDrawLabelsEnabled()) return;

    mAxisLabelPaint.setTypeface(mYAxis.getTypeface());
    mAxisLabelPaint.setTextSize(mYAxis.getTextSize());
    mAxisLabelPaint.setColor(mYAxis.getTextColor());

    PointF center = mChart.getCenterOffsets();
    float factor = mChart.getFactor();

    int labelCount = mYAxis.mEntryCount;

    for (int j = 0; j < labelCount; j++) {

      if (j == labelCount - 1 && mYAxis.isDrawTopYLabelEntryEnabled() == false) break;

      float r = (mYAxis.mEntries[j] - mYAxis.mAxisMinimum) * factor;

      PointF p = Utils.getPosition(center, r, mChart.getRotationAngle());

      String label = mYAxis.getFormattedLabel(j);

      c.drawText(label, p.x + 10, p.y, mAxisLabelPaint);
    }
  }
  public PieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
    super(animator, viewPortHandler);
    mChart = chart;

    mHolePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mHolePaint.setColor(Color.WHITE);
    mHolePaint.setStyle(Style.FILL);

    mTransparentCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTransparentCirclePaint.setColor(Color.WHITE);
    mTransparentCirclePaint.setStyle(Style.FILL);
    mTransparentCirclePaint.setAlpha(105);

    mCenterTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    mCenterTextPaint.setColor(Color.BLACK);
    mCenterTextPaint.setTextSize(Utils.convertDpToPixel(12f));
    // mCenterTextPaint.setTextAlign(Align.CENTER);

    mValuePaint.setTextSize(Utils.convertDpToPixel(13f));
    mValuePaint.setColor(Color.WHITE);
    mValuePaint.setTextAlign(Align.CENTER);
  }
  @Override
  public void renderLimitLines(Canvas c) {

    List<LimitLine> limitLines = mYAxis.getLimitLines();

    if (limitLines == null) return;

    float sliceangle = mChart.getSliceAngle();

    // calculate the factor that is needed for transforming the value to
    // pixels
    float factor = mChart.getFactor();

    PointF center = mChart.getCenterOffsets();

    for (int i = 0; i < limitLines.size(); i++) {

      LimitLine l = limitLines.get(i);

      if (!l.isEnabled()) continue;

      mLimitLinePaint.setColor(l.getLineColor());
      mLimitLinePaint.setPathEffect(l.getDashPathEffect());
      mLimitLinePaint.setStrokeWidth(l.getLineWidth());

      float r = (l.getLimit() - mChart.getYChartMin()) * factor;

      Path limitPath = new Path();

      for (int j = 0; j < mChart.getData().getXValCount(); j++) {

        PointF p = Utils.getPosition(center, r, sliceangle * j + mChart.getRotationAngle());

        if (j == 0) limitPath.moveTo(p.x, p.y);
        else limitPath.lineTo(p.x, p.y);
      }

      limitPath.close();

      c.drawPath(limitPath, mLimitLinePaint);
    }
  }
  @Override
  public void drawValues(Canvas c) {

    PointF center = mChart.getCenterCircleBox();

    // get whole the radius
    float r = mChart.getRadius();
    float rotationAngle = mChart.getRotationAngle();
    float[] drawAngles = mChart.getDrawAngles();
    float[] absoluteAngles = mChart.getAbsoluteAngles();

    float off = r / 10f * 3.6f;

    if (mChart.isDrawHoleEnabled()) {
      off = (r - (r / 100f * mChart.getHoleRadius())) / 2f;
    }

    r -= off; // offset to keep things inside the chart

    PieData data = mChart.getData();
    List<PieDataSet> dataSets = data.getDataSets();
    boolean drawXVals = mChart.isDrawSliceTextEnabled();

    int cnt = 0;

    for (int i = 0; i < dataSets.size(); i++) {

      PieDataSet dataSet = dataSets.get(i);

      if (!dataSet.isDrawValuesEnabled() && !drawXVals) continue;

      // apply the text-styling defined by the DataSet
      applyValueTextStyle(dataSet);

      float lineHeight = Utils.calcTextHeight(mValuePaint, "Q") + Utils.convertDpToPixel(4f);

      List<Entry> entries = dataSet.getYVals();

      for (int j = 0,
              maxEntry =
                  Math.min((int) Math.ceil(entries.size() * mAnimator.getPhaseX()), entries.size());
          j < maxEntry;
          j++) {

        Entry entry = entries.get(j);

        // offset needed to center the drawn text in the slice
        float offset = drawAngles[cnt] / 2;

        // calculate the text position
        float x =
            (float)
                (r
                        * Math.cos(
                            Math.toRadians(
                                (rotationAngle + absoluteAngles[cnt] - offset)
                                    * mAnimator.getPhaseY()))
                    + center.x);
        float y =
            (float)
                (r
                        * Math.sin(
                            Math.toRadians(
                                (rotationAngle + absoluteAngles[cnt] - offset)
                                    * mAnimator.getPhaseY()))
                    + center.y);

        float value =
            mChart.isUsePercentValuesEnabled()
                ? entry.getVal() / data.getYValueSum() * 100f
                : entry.getVal();

        ValueFormatter formatter = dataSet.getValueFormatter();

        boolean drawYVals = dataSet.isDrawValuesEnabled();

        // draw everything, depending on settings
        if (drawXVals && drawYVals) {

          drawValue(c, formatter, value, entry, 0, x, y);

          if (j < data.getXValCount())
            c.drawText(data.getXVals().get(j), x, y + lineHeight, mValuePaint);

        } else if (drawXVals && !drawYVals) {
          if (j < data.getXValCount())
            c.drawText(data.getXVals().get(j), x, y + lineHeight / 2f, mValuePaint);
        } else if (!drawXVals && drawYVals) {

          drawValue(c, formatter, value, entry, 0, x, y + lineHeight / 2f);
        }

        cnt++;
      }
    }
  }
  @Override
  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);
    }

    // force label count
    if (mYAxis.isForceLabelsEnabled()) {

      float step = (float) range / (float) (labelCount - 1);
      mYAxis.mEntryCount = labelCount;

      if (mYAxis.mEntries.length < labelCount) {
        // Ensure stops contains at least numStops elements.
        mYAxis.mEntries = new float[labelCount];
      }

      float v = min;

      for (int i = 0; i < labelCount; i++) {
        mYAxis.mEntries[i] = v;
        v += step;
      }

      // no forced count
    } else {

      // 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 {

        final double rawCount = yMin / interval;
        double first =
            rawCount < 0.0 ? Math.floor(rawCount) * interval : Math.ceil(rawCount) * interval;

        if (first < yMin && mYAxis.isStartAtZeroEnabled()) {
          // Force the first label to be at the 0 (or smallest negative value)
          first = yMin;
        }

        if (first == 0.0) // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
        first = 0.0;

        double last = Utils.nextUp(Math.floor(yMax / interval) * interval);

        double f;
        int i;
        int n = 0;
        for (f = first; f <= last; f += interval) {
          ++n;
        }

        if (Float.isNaN(mYAxis.getAxisMaxValue())) n += 1;

        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;
    }

    if (!mYAxis.isStartAtZeroEnabled() && mYAxis.mEntries[0] < yMin) {
      // If startAtZero is disabled, and the first label is lower that the axis minimum,
      // Then adjust the axis minimum
      mYAxis.mAxisMinimum = mYAxis.mEntries[0];
    }

    mYAxis.mAxisMaximum = mYAxis.mEntries[mYAxis.mEntryCount - 1];
    mYAxis.mAxisRange = Math.abs(mYAxis.mAxisMaximum - mYAxis.mAxisMinimum);
  }