2017-01-31 6 views
1

私はmpandroid charting libraryを使用しています。私はPieChartRenderer を修正し、このようなチャートを手に入れることができました。円グラフのイベントをクリック - mpandroid

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

まず最初に、人々はそれのようなレンダラーを自分自身で書くのが嬉しいです。すごくいいよ!

あなたの実際の質問については、あなたが望むクラスは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)); 

次に、リスニングしたいモーションイベントのメソッドをオーバーライドする必要があります。

@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); 
} 

をあなたがいることを確認するためにいくつかの方法が必要になります。チャート上のチャートはxValueとyValueにxyをタップ生から変換する方法を示していますあなたは、単一のタップのため 次のスニペットを聴きたいとしましょう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 }); 
} 
+0

ありがとう:次に、あなたはこのように、その内部のジェスチャー秋からかpoint.xpoint.yを確認することができます。私はそれを撃つとあなたに知らせるでしょう。 – amarok

+0

私は自分の答えを更新しました。あなたが求めていることは、私が思ったより少し難しいです。私はあなたがそれらの間でマップすることができるようにラベルのxとyの値をキャッシュするときに、スライスのxとyの値をキャッシュする必要があると思う –

+0

ちょうどLabelPointCacheがカスタムオブジェクトであり、ライブラリ自体に属していないことを確認したい。また、このロジックは、円の全領域を探す代わりに、単一の点を検索しません。 – amarok

関連する問題