点击饼图上的事件 - mpandroid

时间:2017-01-31 21:08:07

标签: android mpandroidchart

我正在使用mpandroid图表库。我修改了PieChartRenderer 并且能够得到这样的图表。

enter image description here

PieChartRenderer

public class ImagePieChartRenderer extends PieChartRenderer {

    private ArrayList<Bitmap> bitMaps;
    private Paint mEntryLabelsPaint;
    public ImagePieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Bitmap> bitMaps) {
        super(chart, animator, viewPortHandler);
        this.bitMaps = bitMaps;
        mEntryLabelsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mEntryLabelsPaint.setColor(Color.BLACK);
        mEntryLabelsPaint.setTextAlign(Paint.Align.CENTER);
        mEntryLabelsPaint.setTextSize(Utils.convertDpToPixel(13f));
    }

    @Override
    protected void drawDataSet(Canvas c, IPieDataSet dataSet) {
        drawImages(c);
        super.drawDataSet(c, dataSet);
    }

    private void drawImages(Canvas c) {

        MPPointF center = mChart.getCenterCircleBox();

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

        float phaseX = mAnimator.getPhaseX();
        float phaseY = mAnimator.getPhaseY();

        final float holeRadiusPercent = mChart.getHoleRadius() / 100.f;
        float labelRadiusOffset = radius / 10f * 3.6f;


        labelRadiusOffset = (radius - (radius * holeRadiusPercent)) / 2f;


        final float labelRadius = radius - labelRadiusOffset;

        PieData data = mChart.getData();
        List<IPieDataSet> dataSets = data.getDataSets();

        float yValueSum = data.getYValueSum();

        float angle;
        int xIndex = 0;

        c.save();

        float offset = Utils.convertDpToPixel(5.f);

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


            IPieDataSet dataSet = dataSets.get(i);

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

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

            IValueFormatter formatter = dataSet.getValueFormatter();

            int entryCount = dataSet.getEntryCount();

            mValueLinePaint.setColor(dataSet.getValueLineColor());
            mValueLinePaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getValueLineWidth()));

            final float sliceSpace = getSliceSpace(dataSet);

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

                PieEntry entry = dataSet.getEntryForIndex(j);

                if (xIndex == 0)
                    angle = 0.f;
                else
                    angle = absoluteAngles[xIndex - 1] * phaseX;

                final float sliceAngle = drawAngles[xIndex];
                final float sliceSpaceMiddleAngle = sliceSpace / (Utils.FDEG2RAD * labelRadius);

                // offset needed to center the drawn text in the slice
                final float angleOffset = (sliceAngle - sliceSpaceMiddleAngle / 2.f) / 2.f;

                angle = angle + angleOffset;

                final float transformedAngle = rotationAngle + angle * phaseY;

                float value = mChart.isUsePercentValuesEnabled() ? entry.getY()
                        / yValueSum * 100f : entry.getY();

                final float sliceXBase = (float) Math.cos(transformedAngle * Utils.FDEG2RAD);
                final float sliceYBase = (float) Math.sin(transformedAngle * Utils.FDEG2RAD);

                final float valueLineLength1 = dataSet.getValueLinePart1Length();
                final float valueLineLength2 = dataSet.getValueLinePart2Length();
                final float valueLinePart1OffsetPercentage = dataSet.getValueLinePart1OffsetPercentage() / 100.f;

                float pt2x, pt2y;
                float labelPtx, labelPty;
                float percentX, percentY;

                float line1Radius;

                line1Radius = (radius - (radius * holeRadiusPercent))
                        * valueLinePart1OffsetPercentage
                        + (radius * holeRadiusPercent);

                final float polyline2Width = dataSet.isValueLineVariableLength()
                        ? labelRadius * valueLineLength2 * (float) Math.abs(Math.sin(
                        transformedAngle * Utils.FDEG2RAD))
                        : labelRadius * valueLineLength2;

                final float pt0x = line1Radius * sliceXBase + center.x;
                final float pt0y = line1Radius * sliceYBase + center.y;

                final float pt1x = labelRadius * (1 + valueLineLength1) * sliceXBase + center.x;
                final float pt1y = labelRadius * (1 + valueLineLength1) * sliceYBase + center.y;

                if (transformedAngle % 360.0 >= 40.0 && transformedAngle % 360.0 <= 130.0) {
                    pt2x = pt1x + polyline2Width;
                    pt2y = pt1y;

                    Log.d(entry.getLabel(), "TWO "+ transformedAngle % 360.0);

                    mValuePaint.setTextAlign(Paint.Align.LEFT);

                    mEntryLabelsPaint.setTextAlign(Paint.Align.LEFT);

                    labelPtx = pt2x;
                    labelPty = pt2y;

                    percentX = labelPtx - 1.5f*offset ;
                    percentY = labelPty + bitMaps.get(j).getHeight() + 2.2f*offset;
                } else {
                    pt2x = pt1x - polyline2Width;
                    pt2y = pt1y;

                    Log.d(entry.getLabel(), "ONE "+ transformedAngle % 360.0);

                    mValuePaint.setTextAlign(Paint.Align.RIGHT);

                    mEntryLabelsPaint.setTextAlign(Paint.Align.RIGHT);


                    labelPtx = pt2x;
                    labelPty = pt2y;

                    percentX = labelPtx + 1.5f*offset;
                    percentY = labelPty - bitMaps.get(j).getHeight() - 0.5f*offset;
                }



                mValueLinePaint.setColor(dataSet.getColor(j));

                c.drawLine(pt0x, pt0y, pt1x, pt1y, mValueLinePaint);
                c.drawLine(pt1x, pt1y, pt2x, pt2y, mValueLinePaint);


                // draw everything, depending on settings



                drawValue(c,
                        formatter,
                        value,
                        entry,
                        0,
                        percentX,
                        percentY,
                        dataSet.getValueTextColor(j));

                Paint paint = new Paint();
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(dataSet.getColor(j));
                c.drawCircle(labelPtx, labelPty, bitMaps.get(j).getWidth(), paint);
                c.drawBitmap(bitMaps.get(j), labelPtx-bitMaps.get(j).getWidth()/2f, labelPty-bitMaps.get(j).getHeight()/2, null );

//                if (j < data.getEntryCount() && entry.getLabel() != null) {
//                    drawEntryLabel(c, entry.getLabel(), labelPtx, labelPty + lineHeight);
//                }

                xIndex++;
            }
        }
        MPPointF.recycleInstance(center);
        c.restore();
    }
}

现在我需要点击图表周围的小圆圈。有人可以指出我需要修改的类和函数来实现这一目标。

基本上我想在触摸圆圈时调用onValueSelected(Entry e, Highlight h)

1 个答案:

答案 0 :(得分:1)

首先,很高兴看到人们自己编写这样的渲染器。看起来很棒!

对于您的实际问题,您想要的课程称为OnChartGestureListener。源代码为here

首先,您可能需要在渲染器中缓存圆圈和位图的位置。像这样:

public ImagePieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Bitmap> bitMaps, LabelPointCache labelPointCache) {
    super(chart, animator, viewPortHandler);
    this.bitMaps = bitMaps;
    this.labelPointCache = labelPointCache;
    mEntryLabelsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mEntryLabelsPaint.setColor(Color.BLACK);
    mEntryLabelsPaint.setTextAlign(Paint.Align.CENTER);
    mEntryLabelsPaint.setTextSize(Utils.convertDpToPixel(13f));
}

//snip, then:

    c.drawCircle(labelPtx, labelPty, bitMaps.get(j).getWidth(), paint);
    c.drawBitmap(bitMaps.get(j), labelPtx-bitMaps.get(j).getWidth()/2f, labelPty-bitMaps.get(j).getHeight()/2, null );
//then:
    float entryX = dataSet.getEntry().getX();
    float entryY = dataSet.getEntry().getY();
    labelPositionCache.add(entryX, entryY, labelPtx, labelPty);

现在创建一个实现该接口的类,比如MyOnChartGestureListener。现在将其设置为您的图表:

PieChartRenderer myRenderer = new ImagePieChartRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler(), bitmaps, labelPositionCache);
mChart.setOnChartGestureListener(new MyOnChartGestureListener(mChart, labelPointCache));

然后,您需要覆盖要监听的动作事件的方法。假设你想听单击 以下代码段显示了如何从原始抽头xy转换为图表上的图表xValue和yValue:

@Override
public void onChartSingleTapped(MotionEvent me) {
    float tappedX = me.getX();
    float tappedY = me.getY();
    MPPointD point = mChart.getTransformer(YAxis.AxisDependency.LEFT).getValuesByTouchPoint(tappedX, tappedY);
    Log.d(TAG, "tapped at: " + point.x + "," + point.y);
}

您需要某种方法来检查point.xpoint.y是否在您的圈子或位图中。然后,您可以检查手势中的point.xpoint.y是否属于其中,如下所示:

if (labelPositionCache.contains(point.x, point.y)) {
    float entryX = labelPositionCache.getEntryXForLabelX(point.x);
    float entryY = labelPositionCache.getEntryYForLabelY(point.y);
    Highlight highlight = mChart.getHighlightByTouchPoint(entryX, entryY);
    mChart.highlightValues(new Highlight [] { highlight });
}