导航菜单

页面标题

页面副标题

爱心e站 v1.0.0 - PieChartRenderer.java 源代码

正在查看: 爱心e站 v1.0.0 应用的 PieChartRenderer.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package lecho.lib.hellocharts.renderer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
import com.umeng.analytics.a;
import lecho.lib.hellocharts.formatter.PieChartValueFormatter;
import lecho.lib.hellocharts.model.ColumnChartData;
import lecho.lib.hellocharts.model.PieChartData;
import lecho.lib.hellocharts.model.SelectedValue;
import lecho.lib.hellocharts.model.SliceValue;
import lecho.lib.hellocharts.model.Viewport;
import lecho.lib.hellocharts.provider.PieChartDataProvider;
import lecho.lib.hellocharts.util.ChartUtils;
import lecho.lib.hellocharts.view.Chart;

public class PieChartRenderer extends AbstractChartRenderer {
    private static final float DEFAULT_LABEL_INSIDE_RADIUS_FACTOR = 0.7f;
    private static final float DEFAULT_LABEL_OUTSIDE_RADIUS_FACTOR = 1.0f;
    private static final int DEFAULT_START_ROTATION = 45;
    private static final int DEFAULT_TOUCH_ADDITIONAL_DP = 8;
    private static final float MAX_WIDTH_HEIGHT = 100.0f;
    private static final int MODE_DRAW = 0;
    private static final int MODE_HIGHLIGHT = 1;
    private Paint centerCirclePaint;
    private float centerCircleScale;
    private Paint.FontMetricsInt centerCircleText1FontMetrics;
    private Paint centerCircleText1Paint;
    private Paint.FontMetricsInt centerCircleText2FontMetrics;
    private Paint centerCircleText2Paint;
    private float circleFillRatio;
    private PieChartDataProvider dataProvider;
    private RectF drawCircleOval;
    private boolean hasCenterCircle;
    private boolean hasLabels;
    private boolean hasLabelsOnlyForSelected;
    private boolean hasLabelsOutside;
    private float maxSum;
    private RectF originCircleOval;
    private int rotation;
    private Paint separationLinesPaint;
    private Paint slicePaint;
    private PointF sliceVector;
    private Bitmap softwareBitmap;
    private Canvas softwareCanvas;
    private Viewport tempMaximumViewport;
    private int touchAdditional;
    private PieChartValueFormatter valueFormatter;

    public PieChartRenderer(Context context, Chart chart, PieChartDataProvider dataProvider) {
        super(context, chart);
        this.rotation = 45;
        this.slicePaint = new Paint();
        this.originCircleOval = new RectF();
        this.drawCircleOval = new RectF();
        this.sliceVector = new PointF();
        this.circleFillRatio = 1.0f;
        this.centerCirclePaint = new Paint();
        this.centerCircleText1Paint = new Paint();
        this.centerCircleText1FontMetrics = new Paint.FontMetricsInt();
        this.centerCircleText2Paint = new Paint();
        this.centerCircleText2FontMetrics = new Paint.FontMetricsInt();
        this.separationLinesPaint = new Paint();
        this.tempMaximumViewport = new Viewport();
        this.softwareCanvas = new Canvas();
        this.dataProvider = dataProvider;
        this.touchAdditional = ChartUtils.dp2px(this.density, 8);
        this.slicePaint.setAntiAlias(true);
        this.slicePaint.setStyle(Paint.Style.FILL);
        this.centerCirclePaint.setAntiAlias(true);
        this.centerCirclePaint.setStyle(Paint.Style.FILL);
        this.centerCirclePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        this.centerCircleText1Paint.setAntiAlias(true);
        this.centerCircleText1Paint.setTextAlign(Paint.Align.CENTER);
        this.centerCircleText2Paint.setAntiAlias(true);
        this.centerCircleText2Paint.setTextAlign(Paint.Align.CENTER);
        this.separationLinesPaint.setAntiAlias(true);
        this.separationLinesPaint.setStyle(Paint.Style.STROKE);
        this.separationLinesPaint.setStrokeCap(Paint.Cap.ROUND);
        this.separationLinesPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        this.separationLinesPaint.setColor(0);
    }

    @Override
    public void onChartSizeChanged() {
        calculateCircleOval();
        if (this.computator.getChartWidth() > 0 && this.computator.getChartHeight() > 0) {
            this.softwareBitmap = Bitmap.createBitmap(this.computator.getChartWidth(), this.computator.getChartHeight(), Bitmap.Config.ARGB_8888);
            this.softwareCanvas.setBitmap(this.softwareBitmap);
        }
    }

    @Override
    public void onChartDataChanged() {
        super.onChartDataChanged();
        PieChartData data = this.dataProvider.getPieChartData();
        this.hasLabelsOutside = data.hasLabelsOutside();
        this.hasLabels = data.hasLabels();
        this.hasLabelsOnlyForSelected = data.hasLabelsOnlyForSelected();
        this.valueFormatter = data.getFormatter();
        this.hasCenterCircle = data.hasCenterCircle();
        this.centerCircleScale = data.getCenterCircleScale();
        this.centerCirclePaint.setColor(data.getCenterCircleColor());
        if (data.getCenterText1Typeface() != null) {
            this.centerCircleText1Paint.setTypeface(data.getCenterText1Typeface());
        }
        this.centerCircleText1Paint.setTextSize(ChartUtils.sp2px(this.scaledDensity, data.getCenterText1FontSize()));
        this.centerCircleText1Paint.setColor(data.getCenterText1Color());
        this.centerCircleText1Paint.getFontMetricsInt(this.centerCircleText1FontMetrics);
        if (data.getCenterText2Typeface() != null) {
            this.centerCircleText2Paint.setTypeface(data.getCenterText2Typeface());
        }
        this.centerCircleText2Paint.setTextSize(ChartUtils.sp2px(this.scaledDensity, data.getCenterText2FontSize()));
        this.centerCircleText2Paint.setColor(data.getCenterText2Color());
        this.centerCircleText2Paint.getFontMetricsInt(this.centerCircleText2FontMetrics);
        onChartViewportChanged();
    }

    @Override
    public void onChartViewportChanged() {
        if (this.isViewportCalculationEnabled) {
            calculateMaxViewport();
            this.computator.setMaxViewport(this.tempMaximumViewport);
            this.computator.setCurrentViewport(this.computator.getMaximumViewport());
        }
    }

    @Override
    public void draw(Canvas canvas) {
        Canvas drawCanvas;
        if (this.softwareBitmap != null) {
            drawCanvas = this.softwareCanvas;
            drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        } else {
            drawCanvas = canvas;
        }
        drawSlices(drawCanvas);
        drawSeparationLines(drawCanvas);
        if (this.hasCenterCircle) {
            drawCenterCircle(drawCanvas);
        }
        drawLabels(drawCanvas);
        if (this.softwareBitmap != null) {
            canvas.drawBitmap(this.softwareBitmap, ColumnChartData.DEFAULT_BASE_VALUE, ColumnChartData.DEFAULT_BASE_VALUE, (Paint) null);
        }
    }

    @Override
    public void drawUnclipped(Canvas canvas) {
    }

    @Override
    public boolean checkTouch(float touchX, float touchY) {
        this.selectedValue.clear();
        PieChartData data = this.dataProvider.getPieChartData();
        float centerX = this.originCircleOval.centerX();
        float centerY = this.originCircleOval.centerY();
        float circleRadius = this.originCircleOval.width() / 2.0f;
        this.sliceVector.set(touchX - centerX, touchY - centerY);
        if (this.sliceVector.length() > this.touchAdditional + circleRadius) {
            return false;
        }
        if (data.hasCenterCircle() && this.sliceVector.length() < data.getCenterCircleScale() * circleRadius) {
            return false;
        }
        float touchAngle = ((pointToAngle(touchX, touchY, centerX, centerY) - this.rotation) + 360.0f) % 360.0f;
        float sliceScale = 360.0f / this.maxSum;
        float lastAngle = ColumnChartData.DEFAULT_BASE_VALUE;
        int sliceIndex = 0;
        for (SliceValue sliceValue : data.getValues()) {
            float angle = Math.abs(sliceValue.getValue()) * sliceScale;
            if (touchAngle >= lastAngle) {
                this.selectedValue.set(sliceIndex, sliceIndex, SelectedValue.SelectedValueType.NONE);
            }
            lastAngle += angle;
            sliceIndex++;
        }
        return isTouched();
    }

    private void drawCenterCircle(Canvas canvas) {
        PieChartData data = this.dataProvider.getPieChartData();
        float circleRadius = this.originCircleOval.width() / 2.0f;
        float centerRadius = circleRadius * data.getCenterCircleScale();
        float centerX = this.originCircleOval.centerX();
        float centerY = this.originCircleOval.centerY();
        canvas.drawCircle(centerX, centerY, centerRadius, this.centerCirclePaint);
        if (!TextUtils.isEmpty(data.getCenterText1())) {
            int text1Height = Math.abs(this.centerCircleText1FontMetrics.ascent);
            if (!TextUtils.isEmpty(data.getCenterText2())) {
                int text2Height = Math.abs(this.centerCircleText2FontMetrics.ascent);
                canvas.drawText(data.getCenterText1(), centerX, centerY - (text1Height * 0.2f), this.centerCircleText1Paint);
                canvas.drawText(data.getCenterText2(), centerX, text2Height + centerY, this.centerCircleText2Paint);
                return;
            }
            canvas.drawText(data.getCenterText1(), centerX, (text1Height / 4) + centerY, this.centerCircleText1Paint);
        }
    }

    private void drawSlices(Canvas canvas) {
        PieChartData data = this.dataProvider.getPieChartData();
        float sliceScale = 360.0f / this.maxSum;
        float lastAngle = this.rotation;
        int sliceIndex = 0;
        for (SliceValue sliceValue : data.getValues()) {
            float angle = Math.abs(sliceValue.getValue()) * sliceScale;
            if (isTouched() && this.selectedValue.getFirstIndex() == sliceIndex) {
                drawSlice(canvas, sliceValue, lastAngle, angle, 1);
            } else {
                drawSlice(canvas, sliceValue, lastAngle, angle, 0);
            }
            lastAngle += angle;
            sliceIndex++;
        }
    }

    private void drawSeparationLines(Canvas canvas) {
        int sliceSpacing;
        PieChartData data = this.dataProvider.getPieChartData();
        if (data.getValues().size() >= 2 && (sliceSpacing = ChartUtils.dp2px(this.density, data.getSlicesSpacing())) >= 1) {
            float sliceScale = 360.0f / this.maxSum;
            float lastAngle = this.rotation;
            float circleRadius = this.originCircleOval.width() / 2.0f;
            this.separationLinesPaint.setStrokeWidth(sliceSpacing);
            for (SliceValue sliceValue : data.getValues()) {
                float angle = Math.abs(sliceValue.getValue()) * sliceScale;
                this.sliceVector.set((float) Math.cos(Math.toRadians(lastAngle)), (float) Math.sin(Math.toRadians(lastAngle)));
                normalizeVector(this.sliceVector);
                float x1 = (this.sliceVector.x * (this.touchAdditional + circleRadius)) + this.originCircleOval.centerX();
                float y1 = (this.sliceVector.y * (this.touchAdditional + circleRadius)) + this.originCircleOval.centerY();
                canvas.drawLine(this.originCircleOval.centerX(), this.originCircleOval.centerY(), x1, y1, this.separationLinesPaint);
                lastAngle += angle;
            }
        }
    }

    public void drawLabels(Canvas canvas) {
        PieChartData data = this.dataProvider.getPieChartData();
        float sliceScale = 360.0f / this.maxSum;
        float lastAngle = this.rotation;
        int sliceIndex = 0;
        for (SliceValue sliceValue : data.getValues()) {
            float angle = Math.abs(sliceValue.getValue()) * sliceScale;
            if (isTouched()) {
                if (this.hasLabels) {
                    drawLabel(canvas, sliceValue, lastAngle, angle);
                } else if (this.hasLabelsOnlyForSelected && this.selectedValue.getFirstIndex() == sliceIndex) {
                    drawLabel(canvas, sliceValue, lastAngle, angle);
                }
            } else if (this.hasLabels) {
                drawLabel(canvas, sliceValue, lastAngle, angle);
            }
            lastAngle += angle;
            sliceIndex++;
        }
    }

    private void drawSlice(Canvas canvas, SliceValue sliceValue, float lastAngle, float angle, int mode) {
        this.sliceVector.set((float) Math.cos(Math.toRadians((angle / 2.0f) + lastAngle)), (float) Math.sin(Math.toRadians((angle / 2.0f) + lastAngle)));
        normalizeVector(this.sliceVector);
        this.drawCircleOval.set(this.originCircleOval);
        if (1 == mode) {
            this.drawCircleOval.inset(-this.touchAdditional, -this.touchAdditional);
            this.slicePaint.setColor(sliceValue.getDarkenColor());
            canvas.drawArc(this.drawCircleOval, lastAngle, angle, true, this.slicePaint);
        } else {
            this.slicePaint.setColor(sliceValue.getColor());
            canvas.drawArc(this.drawCircleOval, lastAngle, angle, true, this.slicePaint);
        }
    }

    private void drawLabel(Canvas canvas, SliceValue sliceValue, float lastAngle, float angle) {
        float labelRadius;
        float left;
        float right;
        float top;
        float bottom;
        this.sliceVector.set((float) Math.cos(Math.toRadians((angle / 2.0f) + lastAngle)), (float) Math.sin(Math.toRadians((angle / 2.0f) + lastAngle)));
        normalizeVector(this.sliceVector);
        int numChars = this.valueFormatter.formatChartValue(this.labelBuffer, sliceValue);
        if (numChars != 0) {
            float labelWidth = this.labelPaint.measureText(this.labelBuffer, this.labelBuffer.length - numChars, numChars);
            int labelHeight = Math.abs(this.fontMetrics.ascent);
            float centerX = this.originCircleOval.centerX();
            float centerY = this.originCircleOval.centerY();
            float circleRadius = this.originCircleOval.width() / 2.0f;
            if (this.hasLabelsOutside) {
                labelRadius = circleRadius * 1.0f;
            } else if (this.hasCenterCircle) {
                labelRadius = circleRadius - ((circleRadius - (this.centerCircleScale * circleRadius)) / 2.0f);
            } else {
                labelRadius = circleRadius * DEFAULT_LABEL_INSIDE_RADIUS_FACTOR;
            }
            float rawX = (this.sliceVector.x * labelRadius) + centerX;
            float rawY = (this.sliceVector.y * labelRadius) + centerY;
            if (this.hasLabelsOutside) {
                if (rawX > centerX) {
                    left = rawX + this.labelMargin;
                    right = rawX + labelWidth + (this.labelMargin * 3);
                } else {
                    left = (rawX - labelWidth) - (this.labelMargin * 3);
                    right = rawX - this.labelMargin;
                }
                if (rawY > centerY) {
                    top = rawY + this.labelMargin;
                    bottom = labelHeight + rawY + (this.labelMargin * 3);
                } else {
                    top = (rawY - labelHeight) - (this.labelMargin * 3);
                    bottom = rawY - this.labelMargin;
                }
            } else {
                left = (rawX - (labelWidth / 2.0f)) - this.labelMargin;
                right = (labelWidth / 2.0f) + rawX + this.labelMargin;
                top = (rawY - (labelHeight / 2)) - this.labelMargin;
                bottom = (labelHeight / 2) + rawY + this.labelMargin;
            }
            this.labelBackgroundRect.set(left, top, right, bottom);
            drawLabelTextAndBackground(canvas, this.labelBuffer, this.labelBuffer.length - numChars, numChars, sliceValue.getDarkenColor());
        }
    }

    private void normalizeVector(PointF point) {
        float abs = point.length();
        point.set(point.x / abs, point.y / abs);
    }

    private float pointToAngle(float x, float y, float centerX, float centerY) {
        double diffX = x - centerX;
        double diffY = y - centerY;
        double radian = Math.atan2(-diffX, diffY);
        float angle = (((float) Math.toDegrees(radian)) + 360.0f) % 360.0f;
        return angle + 90.0f;
    }

    private void calculateCircleOval() {
        Rect contentRect = this.computator.getContentRectMinusAllMargins();
        float circleRadius = Math.min(contentRect.width() / 2.0f, contentRect.height() / 2.0f);
        float centerX = contentRect.centerX();
        float centerY = contentRect.centerY();
        float left = (centerX - circleRadius) + this.touchAdditional;
        float top = (centerY - circleRadius) + this.touchAdditional;
        float right = (centerX + circleRadius) - this.touchAdditional;
        float bottom = (centerY + circleRadius) - this.touchAdditional;
        this.originCircleOval.set(left, top, right, bottom);
        float inest = 0.5f * this.originCircleOval.width() * (1.0f - this.circleFillRatio);
        this.originCircleOval.inset(inest, inest);
    }

    private void calculateMaxViewport() {
        this.tempMaximumViewport.set(ColumnChartData.DEFAULT_BASE_VALUE, MAX_WIDTH_HEIGHT, MAX_WIDTH_HEIGHT, ColumnChartData.DEFAULT_BASE_VALUE);
        this.maxSum = ColumnChartData.DEFAULT_BASE_VALUE;
        for (SliceValue sliceValue : this.dataProvider.getPieChartData().getValues()) {
            this.maxSum += Math.abs(sliceValue.getValue());
        }
    }

    public RectF getCircleOval() {
        return this.originCircleOval;
    }

    public void setCircleOval(RectF orginCircleOval) {
        this.originCircleOval = orginCircleOval;
    }

    public int getChartRotation() {
        return this.rotation;
    }

    public void setChartRotation(int rotation) {
        this.rotation = ((rotation % a.p) + a.p) % a.p;
    }

    public SliceValue getValueForAngle(int angle, SelectedValue selectedValue) {
        PieChartData data = this.dataProvider.getPieChartData();
        float touchAngle = ((angle - this.rotation) + 360.0f) % 360.0f;
        float sliceScale = 360.0f / this.maxSum;
        float lastAngle = ColumnChartData.DEFAULT_BASE_VALUE;
        int sliceIndex = 0;
        for (SliceValue sliceValue : data.getValues()) {
            float tempAngle = Math.abs(sliceValue.getValue()) * sliceScale;
            if (touchAngle >= lastAngle) {
                if (selectedValue != null) {
                    selectedValue.set(sliceIndex, sliceIndex, SelectedValue.SelectedValueType.NONE);
                    return sliceValue;
                }
                return sliceValue;
            }
            lastAngle += tempAngle;
            sliceIndex++;
        }
        return null;
    }

    public float getCircleFillRatio() {
        return this.circleFillRatio;
    }

    public void setCircleFillRatio(float fillRatio) {
        if (fillRatio < ColumnChartData.DEFAULT_BASE_VALUE) {
            fillRatio = ColumnChartData.DEFAULT_BASE_VALUE;
        } else if (fillRatio > 1.0f) {
            fillRatio = 1.0f;
        }
        this.circleFillRatio = fillRatio;
        calculateCircleOval();
    }
}