HackPlan / AndroidCharts

An easy-to-use Android charts library with animation.
MIT License
1.33k stars 330 forks source link

Pie chart not showing title #32

Open adnanafzal565 opened 6 years ago

adnanafzal565 commented 6 years ago

What's the point of displaying pie charts without any label information ?

djethva89 commented 5 years ago

package im.dacer.androidcharts;

public class PieHelper {

    int velocity = 5;
    private float startDegree;
    private float endDegree;
    private float targetStartDegree;
    private float targetEndDegree;
    private String title;
    private int color;
    private float sweepDegree;

    /**
     * @param percent from 0 to 100
     */
    public PieHelper(float percent) {
        this(percent, null, 0);
    }

    public PieHelper(float percent, int color) {
        this(percent, null, color);
    }

    /**
     * @param percent from 0 to 100
     */
    public PieHelper(float percent, String title) {
        this(percent, title, 0);
    }

    /**
     * @param percent from 0 to 100
     */
    public PieHelper(float percent, String title, int color) {
        this.sweepDegree = percent * 360 / 100;
        this.title = title;
        this.color = color;
    }

    PieHelper(float startDegree, float endDegree, PieHelper targetPie) {
        this.startDegree = startDegree;
        this.endDegree = endDegree;
        targetStartDegree = targetPie.getStartDegree();
        targetEndDegree = targetPie.getEndDegree();
        this.sweepDegree = targetPie.getSweep();
        this.title = targetPie.getTitle();
        this.color = targetPie.getColor();
    }

    PieHelper setTarget(PieHelper targetPie) {
        this.targetStartDegree = targetPie.getStartDegree();
        this.targetEndDegree = targetPie.getEndDegree();
        this.title = targetPie.getTitle();
        this.color = targetPie.getColor();
        this.sweepDegree = targetPie.getSweep();
        return this;
    }

    void setDegree(float startDegree, float endDegree) {
        this.startDegree = startDegree;
        this.endDegree = endDegree;
    }

    boolean isColorSetted() {
        return color != 0;
    }

    boolean isAtRest() {
        return (startDegree == targetStartDegree) && (endDegree == targetEndDegree);
    }

    void update() {
        this.startDegree = updateSelf(startDegree, targetStartDegree, velocity);
        this.endDegree = updateSelf(endDegree, targetEndDegree, velocity);
        this.sweepDegree = endDegree - startDegree;
    }

    String getPercentStr() {
        float percent = sweepDegree / 360 * 100;
        return String.valueOf((int) percent) + "%";
    }

    public int getColor() {
        return color;
    }

    public String getTitle() {
        return title;
    }

    public float getSweep() {
        return sweepDegree;
    }

    public float getStartDegree() {
        return startDegree;
    }

    public float getEndDegree() {
        return endDegree;
    }

    private float updateSelf(float origin, float target, int velocity) {
        if (origin < target) {
            origin += velocity;
        } else if (origin > target) {
            origin -= velocity;
        }
        if (Math.abs(target - origin) < velocity) {
            origin = target;
        }
        return origin;
    }
}
package im.dacer.androidcharts;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

public class PieView extends View {

    public static final int NO_SELECTED_INDEX = -1;
    private final int[] DEFAULT_COLOR_LIST = {
            Color.parseColor("#33B5E5"), Color.parseColor("#AA66CC"), Color.parseColor("#99CC00"),
            Color.parseColor("#FFBB33"), Color.parseColor("#FF4444")
    };
    private Paint cirPaint;
    private Paint whiteLinePaint;
    private Point pieCenterPoint;
    private Paint textPaint;
    private RectF cirRect;
    private RectF cirSelectedRect;
    private int mViewWidth;
    private int mViewHeight;
    private int margin;
    private int pieRadius;
    private OnPieClickListener onPieClickListener;
    private ArrayList<PieHelper> pieHelperList;
    private int selectedIndex = NO_SELECTED_INDEX;
    private boolean showPercentLabel = true;
    private Runnable animator = new Runnable() {
        @Override
        public void run() {
            boolean needNewFrame = false;
            for (PieHelper pie : pieHelperList) {
                pie.update();
                if (!pie.isAtRest()) {
                    needNewFrame = true;
                }
            }
            if (needNewFrame) {
                postDelayed(this, 10);
            }
            invalidate();
        }
    };

    public PieView(Context context) {
        this(context, null);
    }

    public PieView(Context context, AttributeSet attrs) {
        super(context, attrs);

        pieHelperList = new ArrayList<PieHelper>();
        cirPaint = new Paint();
        cirPaint.setAntiAlias(true);
        cirPaint.setColor(Color.GRAY);
        whiteLinePaint = new Paint(cirPaint);
        whiteLinePaint.setColor(Color.WHITE);
        whiteLinePaint.setStrokeWidth(2f);
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(MyUtils.sp2px(getContext(), 13));
        textPaint.setStrokeWidth(5);
        textPaint.setTextAlign(Paint.Align.CENTER);
        pieCenterPoint = new Point();
        cirRect = new RectF();
        cirSelectedRect = new RectF();
    }

    public void showPercentLabel(boolean show) {
        showPercentLabel = show;
        postInvalidate();
    }

    public void setOnPieClickListener(OnPieClickListener listener) {
        onPieClickListener = listener;
    }

    public void setDate(ArrayList<PieHelper> helperList) {
        initPies(helperList);
        pieHelperList.clear();
        removeSelectedPie();

        if (helperList != null && !helperList.isEmpty()) {
            for (PieHelper pieHelper : helperList) {
                pieHelperList.add(
                        new PieHelper(pieHelper.getStartDegree(), pieHelper.getStartDegree(),
                                pieHelper));
            }
        } else {
            pieHelperList.clear();
        }

        removeCallbacks(animator);
        post(animator);

        //        pieHelperList = helperList;
        //        postInvalidate();
    }

    /**
     * Set startDegree and endDegree for each PieHelper
     */
    private void initPies(ArrayList<PieHelper> helperList) {
        float totalAngel = 270;
        for (PieHelper pie : helperList) {
            pie.setDegree(totalAngel, totalAngel + pie.getSweep());
            totalAngel += pie.getSweep();
        }
    }

    public void selectedPie(int index) {
        selectedIndex = index;
        if (onPieClickListener != null) onPieClickListener.onPieClick(index);
        postInvalidate();
    }

    public void removeSelectedPie() {
        selectedIndex = NO_SELECTED_INDEX;
        if (onPieClickListener != null) onPieClickListener.onPieClick(NO_SELECTED_INDEX);
        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (pieHelperList.isEmpty()) {
            return;
        }

        int index = 0;
        for (PieHelper pieHelper : pieHelperList) {
            boolean selected = (selectedIndex == index);
            RectF rect = selected ? cirSelectedRect : cirRect;
            if (pieHelper.isColorSetted()) {
                cirPaint.setColor(pieHelper.getColor());
            } else {
                cirPaint.setColor(DEFAULT_COLOR_LIST[index % 5]);
            }
            canvas.drawArc(rect, pieHelper.getStartDegree(), pieHelper.getSweep(), true, cirPaint);
            drawPercentText(canvas, pieHelper);
            //drawText(canvas, pieHelper);

            drawLineBesideCir(canvas, pieHelper.getStartDegree(), selected);
            drawLineBesideCir(canvas, pieHelper.getEndDegree(), selected);
            index++;
        }
    }

    private void drawLineBesideCir(Canvas canvas, float angel, boolean selectedCir) {
        int sth2 = selectedCir ? mViewHeight / 2
                : pieRadius; // Sorry I'm really don't know how to name the variable..
        int sth = 1;                                       // And it's
        if (angel % 360 > 180 && angel % 360 < 360) {
            sth = -1;
        }
        float lineToX = (float) (mViewHeight / 2 + Math.cos(Math.toRadians(-angel)) * sth2);
        float lineToY =
                (float) (mViewHeight / 2 + sth * Math.abs(Math.sin(Math.toRadians(-angel))) * sth2);
        canvas.drawLine(pieCenterPoint.x, pieCenterPoint.y, lineToX, lineToY, whiteLinePaint);
    }

    private void drawPercentText(Canvas canvas, PieHelper pieHelper) {
        if (!showPercentLabel) return;
        float angel = (pieHelper.getStartDegree() + pieHelper.getEndDegree()) / 2;
        int sth = 1;
        if (angel % 360 > 180 && angel % 360 < 360) {
            sth = -1;
        }
        float x = (float) (mViewHeight / 2 + Math.cos(Math.toRadians(-angel)) * pieRadius / 2);
        float y = (float) (mViewHeight / 2
                + sth * Math.abs(Math.sin(Math.toRadians(-angel))) * pieRadius / 2);
        canvas.drawText(pieHelper.getPercentStr(), x, y, textPaint);
        canvas.drawText(pieHelper.getTitle(), x, y + 30, textPaint);
    }

    private void drawText(Canvas canvas, PieHelper pieHelper) {
        if (pieHelper.getTitle() == null) return;
        float angel = (pieHelper.getStartDegree() + pieHelper.getEndDegree()) / 2;
        int sth = 1;
        if (angel % 360 > 180 && angel % 360 < 360) {
            sth = -1;
        }
        float x = (float) (mViewHeight / 2 + Math.cos(Math.toRadians(-angel)) * pieRadius / 2);
        float y = (float) (mViewHeight / 2
                + sth * Math.abs(Math.sin(Math.toRadians(-angel))) * pieRadius / 2);
        canvas.drawText(pieHelper.getTitle(), x, y, textPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            int clickedIndex = findPointAt((int) event.getX(), (int) event.getY());
            if (clickedIndex == selectedIndex) {
                selectedIndex = NO_SELECTED_INDEX;
            } else {
                selectedIndex = clickedIndex;
            }
            if (onPieClickListener != null) {
                onPieClickListener.onPieClick(selectedIndex);
            }
            postInvalidate();
        }

        return true;
    }

    /**
     * find pie index where point is
     */
    private int findPointAt(int x, int y) {
        double degree = Math.atan2(x - pieCenterPoint.x, y - pieCenterPoint.y) * 180 / Math.PI;
        degree = -(degree - 180) + 270;
        int index = 0;
        for (PieHelper pieHelper : pieHelperList) {
            if (degree >= pieHelper.getStartDegree() && degree <= pieHelper.getEndDegree()) {
                return index;
            }
            index++;
        }
        return NO_SELECTED_INDEX;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mViewWidth = measureWidth(widthMeasureSpec);
        mViewHeight = measureHeight(heightMeasureSpec);
        margin = mViewWidth / 16;
        pieRadius = (mViewWidth) / 2 - margin;
        pieCenterPoint.set(pieRadius + margin, pieRadius + margin);
        cirRect.set(pieCenterPoint.x - pieRadius, pieCenterPoint.y - pieRadius,
                pieCenterPoint.x + pieRadius, pieCenterPoint.y + pieRadius);
        cirSelectedRect.set(2, //minor margin for bigger circle
                2, mViewWidth - 2, mViewHeight - 2);
        setMeasuredDimension(mViewWidth, mViewHeight);
    }

    private int measureWidth(int measureSpec) {
        int preferred = 3;
        return getMeasurement(measureSpec, preferred);
    }

    private int measureHeight(int measureSpec) {
        int preferred = mViewWidth;
        return getMeasurement(measureSpec, preferred);
    }

    private int getMeasurement(int measureSpec, int preferred) {
        int specSize = View.MeasureSpec.getSize(measureSpec);
        int measurement;

        switch (View.MeasureSpec.getMode(measureSpec)) {
            case View.MeasureSpec.EXACTLY:
                measurement = specSize;
                break;
            case View.MeasureSpec.AT_MOST:
                measurement = Math.min(preferred, specSize);
                break;
            default:
                measurement = preferred;
                break;
        }
        return measurement;
    }

    public interface OnPieClickListener {
        void onPieClick(int index);
    }
}

How to Set Title (Kotlin Code) : var pieHelperArrayList = ArrayList() pieHelperArrayList.add(PieHelper(15f, "Red")) pieHelperArrayList.add(PieHelper(20f, "Green")) pieHelperArrayList.add(PieHelper(35f, "White")) pieHelperArrayList.add(PieHelper(30f, "Black")) pie_view.setDate(pieHelperArrayList)

djmyclasscampus commented 5 years ago

Please try to remove below line and check; canvas.drawText(pieHelper.getPercentStr(), x, y, textPaint); canvas.drawText(pieHelper.getTitle(), x, y + 30, textPaint);

On Tue, 6 Aug 2019 at 21:20, feifeikuaifeiba notifications@github.com wrote:

What's the point of displaying pie charts without any label information ?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/HackPlan/AndroidCharts/issues/32?email_source=notifications&email_token=ALX4IM4VO7BGR5TYHDTCUWTQDGMTBA5CNFSM4FAH67D2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3VS6GQ#issuecomment-518729498, or mute the thread https://github.com/notifications/unsubscribe-auth/ALX4IM2QLFSPDS7MX3ZHYMTQDGMTBANCNFSM4FAH67DQ .