Tuesday, 24 September 2013

how to implement PieChart in android sample source code

This demo demonstrates the usage of Android Graphics API to create simple 2D Pie chart and handling of touch event on the Pie-chart. This demo draws the 2D Pie chart based on the given data inputs, colors. Data legends are shown at the bottom of the chart as shown in the below image. Also, it handles the touch events and identifies the particular pie slice whether touched or not to support drilled down features.

Pie Chart using Android Graphics API

Let me explain the application in more details, the steps to draw the Pie-Chart.

1. Create a simple view layout containing one Image View. (activity_main.xml)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<ImageView
    android:id="@+id/image_placeholder"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:adjustViewBounds="false"
    android:background="#000000"
    android:scaleType="center" />

</RelativeLayout>



2. Create a main activity which contains the above layout (MainActivity.java)



    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        //main layout
        setContentView(R.layout.activity_main);
        
        //pie chart parameters
        int data_values[] = { 20,10,25,5,15,25};
        int color_values[] = {Color.MAGENTA, Color.RED, Color.GREEN,Color.BLUE,Color.YELLOW,Color.CYAN};
        String itemnames[] = { "item 1""item 2""item 3""item 4""item 5","item 6"};
        
        //get the imageview
        ImageView imgView = (ImageView ) findViewById(R.id.image_placeholder);
         
        //create pie chart Drawable and set it to ImageView
        PieChart pieChart = new PieChart(this, imgView, itemnames, data_values, color_values);
        imgView.setImageDrawable(pieChart);

    }


Create  the required pie-chart parameters like data values, names, colors and create PieChart drawable Shape instance and assign to Image View.

3. PieChart Drawable Shape


Create a PieChart Class by extending Drawable Class and  implementation for OnTouchLister.

public class PieChart extends Drawable implements OnTouchListener {....}

Add the constructor with the required parameters for to draw the Pie Chart.


     public PieChart(Context c, View v, String[] data_names, int[] data_values, int[] color_values) {
         context = c;
         view = v;
         this.data_values = data_values;
         this.color_values = color_values;
         this.data_names = data_names;
         
         paint = new Paint();
         view.setOnTouchListener(this);
     }


And Now, Overwrite the draw() method with the below steps

  • Get the screen width & height
  • Calculate the chart area in Rectangle area
  • Calculate the start angle and Sweep angle for each data item
  •  And finally Draw the Arc, legend box, legend text with corresponding paint.




public void draw(Canvas canvas) {
// TODO Auto-generated method stub

//screen width & height
int view_w = view.getWidth();
        int view_h = view.getHeight();
        
     //chart area rectangle
      arc_bounds = new RectF(
                 left_edge,
                 top_edge,
                 right_edge,
                 bottom_edge
         );

        //sum of data values
        for (int datum : data_values)
                value_sum += datum;
        
        float startAngle = 0;
        int i = 0;
  
        for (int datum : data_values) {
                if (datum == 0) continue;
                
                //calculate start & end angle for each data value
                float endAngle = value_sum == 0 ? 0 : 360 * datum / (floatvalue_sum;
                float newStartAngle = startAngle + endAngle;
                
             
                int flickr_pink = color_values[i % color_values.length];
                paint.setColor(flickr_pink);
                paint.setAntiAlias(true);
                paint.setStyle(Paint.Style.FILL);
                paint.setStrokeWidth(0.5f);
                
                //gradient fill color
                LinearGradient linearGradient = new LinearGradient(arc_bounds.leftarc_bounds.toparc_bounds.right,arc_bounds.bottom, flickr_pink, Color.WHITE, Shader.TileMode.CLAMP);
                paint.setShader(linearGradient);
                
                //draw fill arc
                canvas.drawArc(arc_bounds, startAngle, endAngle, truepaint);
            
                Paint linePaint = new Paint();
                linePaint.setAntiAlias(true);
                linePaint.setStyle(Paint.Style.STROKE);
                linePaint.setStrokeJoin(Join.ROUND);
                linePaint.setStrokeCap(Cap.ROUND);
                linePaint.setStrokeWidth(0.5f);
                linePaint.setColor(Color.BLACK);

                //draw border arc
                canvas.drawArc(arc_bounds, startAngle, endAngle, true, linePaint);
                
                int barStartX = 50;
                int barWidth = 20;
                int barStartY = view_h-padding_bottom+(i-1)*2*barWidth;
               
                Rect barRect = new Rect(barStartX,barStartY,barStartX+barWidth,barStartY+barWidth);
                
                //draw legend box
                canvas.drawRect(barRect, paint);
                canvas.drawRect(barRect,linePaint);
                
                
                Paint textPaint = new Paint();
                textPaint.setAntiAlias(true);
                textPaint.setColor(Color.WHITE);
                textPaint.setTextSize(30);
                
                //draw legend text
                canvas.drawText(data_names[i], barStartX+2*barWidth, barStartY+barWidth, textPaint);
                
                startAngle = newStartAngle;
                i++;
        }
}


4.. Adding Touch Listener

Now, Implement the onTouchListener with below steps,
  • Get mouse down event
  • Calculate the click angle
  • Check the condition with the start angle and Sweep angle for each data item


public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
//mouse down event
if( event.getAction() == MotionEvent.ACTION_DOWN)
{

double clickAngle;
//relative x & y position
float xPos = event.getX() - arc_bounds.centerX();
float yPos = event.getY() - arc_bounds.centerY();
//calcuate the click angle
clickAngle = Math.atan2(yPos,xPos) * 180 / Math.PI;
if(clickAngle < 0)
clickAngle = 360 + clickAngle;
float startAngle = 0;
int itemIndex = 0;
for (int datum : data_values) {
if (datum == 0) continue;

float endAngle = value_sum == 0 ? 0 : 360 * datum / (floatvalue_sum;
float newStartAngle = startAngle + endAngle;
 
//check the condition of start angle & end angle of data item.
             if(arc_bounds.contains(event.getX(),event.getY())  && clickAngle > startAngle && clickAngle < newStartAngle)
             {
            
             Toast.makeText(contextdata_names[itemIndex] + "  is clicked!!", Toast.LENGTH_LONG).show();
             Log.d(TAG,"pie item is clicked-->" + data_names[itemIndex]);
             break;
             }
           
             itemIndex++;
startAngle = newStartAngle;

}
}

return false;
}


the below image shows the Toast message when the particular pie slice is touched. Based on this event, drilled down feature will be supported like starting activity or reloading the view with different data values.




PieChart with OnTouchLister Implementation



Conclusion:

The above sample demo application uses the Android Graphics API to draw simple 2D PieChart and supports the touch events. calculation used for detecting the Pie Slice is shown in the above sample. This sample will help to create interactive charts, decision like starting new activity, different view based on the pie slice selection.

2 comments:

  1. this code have error
    Are there is need to add any jar file if i working at android studio?

    ReplyDelete