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(Paint.Style.FILL);

    mTransparentCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTransparentCirclePaint.setColor(Color.WHITE);
    mTransparentCirclePaint.setStyle(Paint.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(Paint.Align.CENTER);
  }
  @Override
  public void calculateOffsets() {

    float legendLeft = 0f, legendRight = 0f, legendBottom = 0f, legendTop = 0f;

    if (mLegend != null && mLegend.isEnabled()) {

      float fullLegendWidth =
          Math.min(
                  mLegend.mNeededWidth,
                  mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
              + mLegend.getFormSize()
              + mLegend.getFormToTextSpace();

      if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART_CENTER) {

        // this is the space between the legend and the chart
        float spacing = Utils.convertDpToPixel(13f);

        legendRight = fullLegendWidth + spacing;

      } else if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART) {

        // this is the space between the legend and the chart
        float spacing = Utils.convertDpToPixel(8f);

        float legendWidth = fullLegendWidth + spacing;

        float legendHeight = mLegend.mNeededHeight + mLegend.mTextHeightMax;

        PointF c = getCenter();

        PointF bottomRight = new PointF(getWidth() - legendWidth + 15, legendHeight + 15);
        float distLegend = distanceToCenter(bottomRight.x, bottomRight.y);

        PointF reference =
            getPosition(c, getRadius(), getAngleForPoint(bottomRight.x, bottomRight.y));

        float distReference = distanceToCenter(reference.x, reference.y);
        float min = Utils.convertDpToPixel(5f);

        if (distLegend < distReference) {

          float diff = distReference - distLegend;
          legendRight = min + diff;
        }

        if (bottomRight.y >= c.y && getHeight() - legendWidth > getWidth()) {
          legendRight = legendWidth;
        }

      } else if (mLegend.getPosition() == LegendPosition.LEFT_OF_CHART_CENTER) {

        // this is the space between the legend and the chart
        float spacing = Utils.convertDpToPixel(13f);

        legendLeft = fullLegendWidth + spacing;

      } else if (mLegend.getPosition() == LegendPosition.LEFT_OF_CHART) {

        // this is the space between the legend and the chart
        float spacing = Utils.convertDpToPixel(8f);

        float legendWidth = fullLegendWidth + spacing;

        float legendHeight = mLegend.mNeededHeight + mLegend.mTextHeightMax;

        PointF c = getCenter();

        PointF bottomLeft = new PointF(legendWidth - 15, legendHeight + 15);
        float distLegend = distanceToCenter(bottomLeft.x, bottomLeft.y);

        PointF reference =
            getPosition(c, getRadius(), getAngleForPoint(bottomLeft.x, bottomLeft.y));

        float distReference = distanceToCenter(reference.x, reference.y);
        float min = Utils.convertDpToPixel(5f);

        if (distLegend < distReference) {

          float diff = distReference - distLegend;
          legendLeft = min + diff;
        }

        if (bottomLeft.y >= c.y && getHeight() - legendWidth > getWidth()) {
          legendLeft = legendWidth;
        }

      } else if (mLegend.getPosition() == LegendPosition.BELOW_CHART_LEFT
          || mLegend.getPosition() == LegendPosition.BELOW_CHART_RIGHT
          || mLegend.getPosition() == LegendPosition.BELOW_CHART_CENTER) {

        // It's possible that we do not need this offset anymore as it
        //   is available through the extraOffsets, but changing it can mean
        //   changing default visibility for existing apps.
        float yOffset = getRequiredLegendOffset();

        legendBottom =
            Math.min(
                mLegend.mNeededHeight + yOffset,
                mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent());

      } else if (mLegend.getPosition() == LegendPosition.ABOVE_CHART_LEFT
          || mLegend.getPosition() == LegendPosition.ABOVE_CHART_RIGHT
          || mLegend.getPosition() == LegendPosition.ABOVE_CHART_CENTER) {

        // It's possible that we do not need this offset anymore as it
        //   is available through the extraOffsets, but changing it can mean
        //   changing default visibility for existing apps.
        float yOffset = getRequiredLegendOffset();

        legendTop =
            Math.min(
                mLegend.mNeededHeight + yOffset,
                mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent());
      }

      legendLeft += getRequiredBaseOffset();
      legendRight += getRequiredBaseOffset();
      legendTop += getRequiredBaseOffset();
    }

    float minOffset = Utils.convertDpToPixel(mMinOffset);

    if (this instanceof RadarChart) {
      XAxis x = ((RadarChart) this).getXAxis();

      if (x.isEnabled() && x.isDrawLabelsEnabled()) {
        minOffset = Math.max(minOffset, x.mLabelRotatedWidth);
      }
    }

    legendTop += getExtraTopOffset();
    legendRight += getExtraRightOffset();
    legendBottom += getExtraBottomOffset();
    legendLeft += getExtraLeftOffset();

    float offsetLeft = Math.max(minOffset, legendLeft);
    float offsetTop = Math.max(minOffset, legendTop);
    float offsetRight = Math.max(minOffset, legendRight);
    float offsetBottom = Math.max(minOffset, Math.max(getRequiredBaseOffset(), legendBottom));

    mViewPortHandler.restrainViewPort(offsetLeft, offsetTop, offsetRight, offsetBottom);

    if (mLogEnabled)
      Log.i(
          LOG_TAG,
          "offsetLeft: "
              + offsetLeft
              + ", offsetTop: "
              + offsetTop
              + ", offsetRight: "
              + offsetRight
              + ", offsetBottom: "
              + offsetBottom);
  }
  @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++;
      }
    }
  }