Android Canvas练习(6)饼图(Pie Chart)百分比标注位置计算技巧

     今天终于解决了困扰整整一周的,一个令人抓狂的HPUX代码问题。可以在这半夜神清气爽的说下昨天晚上推导出来的一个小技巧,

如何在一张饼图(Pie Chart)上每个扇形的中心位置标记出百分比。 我之前写了一篇怎么自绘饼图的文章,但百分比都是另外在一个

地方显示的,不是不想显示在每个扇形图中,是当时还不会。昨晚花了点时间,终于找出了计算方法。

   先上张最终效果图:

     Android Canvas练习(6)饼图(Pie Chart)百分比标注位置计算技巧_第1张图片

   经历过的思路历程也很有意思,看看下面几张图,可以很清楚的显示说明计算经过是怎么样子的:


       Android Canvas练习(6)饼图(Pie Chart)百分比标注位置计算技巧_第2张图片 Android Canvas练习(6)饼图(Pie Chart)百分比标注位置计算技巧_第3张图片  Android Canvas练习(6)饼图(Pie Chart)百分比标注位置计算技巧_第4张图片

   靠左的这张图,说明了我需要解决的问题所在,即目前已知圆心坐标,半径,及角度,如何得到扇形的中心点这是个数学问题,而数学我基本都还给老师了,怀着

惭愧的心情baidu了一翻后,终于找到了依角度可求出图上坐标的计算公式,不知其所以然(继续惭愧中.....)的套了上去,得到了中间这张图。

   中间这张图可以很清楚的得到每个角度,最末边交叉点位置。 但这个位置并不是我们想要的,我们想的是中间这个点的坐标。如果是这样,而中点的坐标是多少呢,

好像没啥现成的公式,只好灵活变化一下,还是套用这公式,把角度减少一半不得就行了。这样就得到了最右边这张图。

   最右边这张图已经很接近最终效果了,实际上很多饼图得到这个坐标就够了,直接画一条线延伸出去,再标注百分比就可以了,这种情况适合于角度太小的情况。

但我举的例子中角度都偏大,可以直接标注百分比到图中,怎么做? 按前面取角度的思路想,事情就简单了,即然现在是在边上,那把半径缩小一圈按这个方法计算不就行了,哈哈。 终于得到了想要的效果。

    

  附上主程序代码:     

package com.xcl.canvas05;

/**
 * Canvas练习 
 * 	  给饼图标上百分比,能计算出饼图标注的位置
 *  
 * author:xiongchuanliang
 * date:2014-4-10
 */

import java.text.DecimalFormat;

import com.xcl.chart.XChartCalc;

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.View;

@SuppressLint("NewApi")
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     //   setContentView(R.layout.activity_main);
        this.setTitle("给饼图标上百分比");
        setContentView(new PanelPieChartLabel(this));
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    

   
     class PanelPieChartLabel extends View {
    	
    	private int ScrWidth,ScrHeight;
		private float rx, ry;
		

		public PanelPieChartLabel(Context context) {
			super(context);
			// TODO Auto-generated constructor stub
			
			//解决4.1版本 以下canvas.drawTextOnPath()不显示问题			
			this.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
			
			//屏幕信息
			DisplayMetrics dm = getResources().getDisplayMetrics();
			ScrHeight = dm.heightPixels;
			ScrWidth = dm.widthPixels;
		}
		
		public void onDraw(Canvas canvas){
			//画布背景
			canvas.drawColor(Color.WHITE);
			
			//画笔初始化
			Paint PaintArc = new Paint();
			PaintArc.setColor(Color.RED);		
						
			Paint PaintGree = new Paint();
			PaintGree.setColor(Color.GREEN);
			PaintGree.setStyle(Style.FILL);
			
			Paint PaintBlue = new Paint();
			PaintBlue.setColor(Color.BLUE);
			PaintBlue.setStyle(Style.STROKE);
			
			Paint PaintYellow = new Paint();
			PaintYellow.setColor(Color.YELLOW);
			PaintYellow.setStyle(Style.FILL);
			
			//抗锯齿
			PaintArc.setAntiAlias(true);
			PaintYellow.setAntiAlias(true);
			PaintGree.setAntiAlias(true);
					
			PaintBlue.setTextSize(12);
						
			float cirX = ScrWidth / 2;
			float cirY = ScrHeight / 3 ;
			float radius = ScrHeight / 5 ;
			//先画个圆确定下显示位置
			canvas.drawCircle(cirX,cirY,radius,PaintGree);
									
			float arcLeft = cirX - radius;
			float arcTop  = cirY - radius ;
			float arcRight = cirX + radius ;
			float arcBottom = cirY + radius ;
			RectF arcRF0 = new RectF(arcLeft ,arcTop,arcRight,arcBottom);	
			
			
			//饼图标题
			canvas.drawText("author:xiongchuanliang",60,ScrHeight - 270, PaintBlue);	
			
			//位置计算类  
            XChartCalc xcalc = new XChartCalc();					
            
            //实际用于计算的半径
            float calcRadius = radius/2;
			
			//初始角度 				
			float pAngle1 = 130f; 
			float pAngle2 = 40f; 
			float pAngle3 = 360f - pAngle1 - pAngle2; 
			
			//填充扇形
			canvas.drawArc(arcRF0, 0,pAngle1, true,PaintArc); 
			
			//计算并在扇形中心标注上百分比    130%
            xcalc.CalcArcEndPointXY(cirX, cirY, calcRadius, pAngle1/2); 
            canvas.drawText(Float.toString(pAngle1)+"%", xcalc.getPosX(),xcalc.getPosY(), PaintBlue);  
            //
            
                         
            //填充扇形
            canvas.drawArc(arcRF0, pAngle1,pAngle2, true,PaintYellow);            
            //计算并在扇形中心标注上百分比   40%
            xcalc.CalcArcEndPointXY(cirX, cirY, calcRadius, pAngle1 + pAngle2/2);	            
            canvas.drawText(Float.toString(pAngle2)+"%", xcalc.getPosX(),xcalc.getPosY(), PaintBlue);  
            
              
            //计算并在扇形中心标注上百分比  190%
            xcalc.CalcArcEndPointXY(cirX, cirY, calcRadius, pAngle1 + pAngle2 + pAngle3/2);	            
            canvas.drawText(Float.toString(pAngle3)+"%", xcalc.getPosX(),xcalc.getPosY(), PaintBlue);  
             								
	 }
		
	
    }
    
}

   附上计算位置的代码类:     

package com.xcl.chart;

/**
 * Canvas练习 
 * 	  图形相关的计算类
 *   
 * author:xiongchuanliang
 * date:2014-4-9
 */

public class XChartCalc {
	

	//Position位置
	private float posX = 0.0f;
	private float posY = 0.0f;
	
	public XChartCalc()
	{
		
	}
			
	
	//依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标
	public void CalcArcEndPointXY(float cirX, float cirY, float radius, float cirAngle){

		//将角度转换为弧度		
        float arcAngle = (float) (Math.PI * cirAngle / 180.0);
        if (cirAngle < 90)
        {
            posX = cirX + (float)(Math.cos(arcAngle)) * radius;
            posY = cirY + (float)(Math.sin(arcAngle)) * radius;
        }
        else if (cirAngle == 90)
        {
            posX = cirX;
            posY = cirY + radius;
        }
        else if (cirAngle > 90 && cirAngle < 180)
        {
        	arcAngle = (float) (Math.PI * (180 - cirAngle) / 180.0);
            posX = cirX - (float)(Math.cos(arcAngle)) * radius;
            posY = cirY + (float)(Math.sin(arcAngle)) * radius;
        }
        else if (cirAngle == 180)
        {
            posX = cirX - radius;
            posY = cirY;
        }
        else if (cirAngle > 180 && cirAngle < 270)
        {
        	arcAngle = (float) (Math.PI * (cirAngle - 180) / 180.0);
            posX = cirX - (float)(Math.cos(arcAngle)) * radius;
            posY = cirY - (float)(Math.sin(arcAngle)) * radius;
        }
        else if (cirAngle == 270)
        {
            posX = cirX;
            posY = cirY - radius;
        }
        else
        {
        	arcAngle = (float) (Math.PI * (360 - cirAngle) / 180.0);
            posX = cirX + (float)(Math.cos(arcAngle)) * radius;
            posY = cirY - (float)(Math.sin(arcAngle)) * radius;
        }
				
	}


    //
	public float getPosX() {
		return posX;
	}


	public float getPosY() {
		return posY;
	}	
    //
}
   至此,我最近遇到的两个技术问题(一个被工作逼的,一个感兴趣的)都基本解决了,爽!

   

附其它链接:

   Android Canvas练习(1)画一张报表来玩   

   Android Canvas练习(2)自已绘饼图

   Android Canvas练习(3)自已绘柱形图

   Android Canvas练习(4)自已绘折线图

     Android Canvas练习(5)自已绘面积图(Area Chart)


MAIL: [email protected]

BLOG: http://blog.csdn.net/xcl168


你可能感兴趣的:(Android)