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