public class MathHelper {

	private static MathHelper instance = null;
	
	//Position位置
	private float mPosX = 0.0f;
	private float mPosY = 0.0f;
	private PointF mPointF = new PointF();
	
	//除法运算精度
	private static final int DEFAULT_DIV_SCALE = 10;
	
	//
	private boolean mHighPrecision = true;

	public MathHelper()
	{	
	}
	
	public static synchronized MathHelper getInstance()
	{
		 if(instance == null)
		 {
			 instance = new MathHelper();
		 }
		 return instance;
	}
		
	private void resetEndPointXY()
	{
		mPosX = mPosY = 0.0f;
		mPointF.x = mPosX;
		mPointF.y = mPosY;
	}	
	
	//依圆心坐标，半径，扇形角度，计算出扇形终射线与圆弧交叉点的xy坐标	
	public PointF calcArcEndPointXY(float cirX, 
									float cirY, 
									float radius, 
									float cirAngle)
	{	
		resetEndPointXY();		
		if( Float.compare(cirAngle, 0.0f) == 0 || 
			Float.compare(radius, 0.0f) == 0   )
		{
			 return mPointF;		
		}
		
			
		//将角度转换为弧度		
	    float arcAngle = (float) (Math.PI *  div(cirAngle , 180.0f));
	    if( Float.compare(arcAngle,0.0f) == -1)mPosX = mPosY = 0.0f;	
	    
	    if (Float.compare(cirAngle , 90.0f) == -1)
	    {	    		    
	    	mPosX = add(cirX , (float)Math.cos(arcAngle) * radius);
	        mPosY = add(cirY , (float)Math.sin(arcAngle) * radius) ;
	    }
	    else if (Float.compare(cirAngle,90.0f) == 0)
	    {
	        mPosX = cirX;
	        mPosY = add(cirY , radius);
	    }
	    else if (Float.compare(cirAngle,90.0f) == 1 &&
	    		 Float.compare(cirAngle,180.0f) == -1)
	    {
	    	arcAngle = (float) (Math.PI * (sub(180f , cirAngle)) / 180.0f);	 	    		    		    		    
	        mPosX = sub(cirX , (float) (Math.cos(arcAngle) * radius));
	        mPosY = add(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    else if (Float.compare(cirAngle,180.0f) == 0)
	    {
	        mPosX = cirX - radius;
	        mPosY = cirY;
	    }
	    else if (Float.compare(cirAngle,180.0f) == 1 &&
	    		 Float.compare(cirAngle,270.0f) == -1) 
	    {
	    	arcAngle = (float) (Math.PI * ( sub(cirAngle , 180.0f)) / 180.0f);
	        mPosX = sub(cirX , (float) (Math.cos(arcAngle) * radius));
	        mPosY = sub(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    else if (Float.compare(cirAngle,270.0f) == 0)
	    {
	        mPosX = cirX;
	        mPosY = sub (cirY , radius);
	    }
	    else
	    {
	    	arcAngle = (float) (Math.PI * ( sub(360.0f , cirAngle )) / 180.0f);
	        mPosX = add(cirX , (float) (Math.cos(arcAngle) * radius)) ;
	        mPosY = sub(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    	    
	    mPointF.x = mPosX;
	    mPointF.y = mPosY;	    
	    return mPointF;				
	}
	
	public PointF getArcEndPointF()
	{		
		return mPointF;
	}
	
	public float getPosX() {
		return mPosX;
	}
		
	public float getPosY() {
		return mPosY;
	}	
	
	
	//两点间的角度
	public double getDegree(float sx, float sy, float tx, float ty) 
    {
        float nX = tx - sx;
        float nY = ty - sy;
        double angrad = 0d,angel = 0d,tpi = 0d;
        float tan = 0.0f;
        
        if (Float.compare(nX ,0.0f) != 0) {
            tan = Math.abs(nY / nX);
            angel  = Math.atan(tan);
            
            if ( Float.compare(nX,0.0f) == 1 )
            {
            	if( Float.compare(nY,0.0f) == 1 || Float.compare(nY,0.0f) ==  0)
            	{
            		 angrad = angel;
            	}else{
            		 angrad = 2 * Math.PI - angel;
            	}
            }else{
            	if( Float.compare(nY,0.0f) == 1 || Float.compare(nY,0.0f) ==  0)
            	{
            		angrad = Math.PI - angel;
            	}else{
            		angrad = Math.PI + angel;
            	}
            }                      

        } else {
        	tpi  = Math.PI / 2;        	
        	if( Float.compare(nY,0.0f) == 1)
        	{
        		angrad = tpi;
        	}else{
        		angrad = -1 * tpi;
        	}
        }        
        return  Math.toDegrees(angrad);
    }
		
    //两点间的距离
    public double getDistance(float sx,float sy,float tx,float ty)
    {	 
    	float nx = Math.abs(tx - sx);
        float ny = Math.abs(ty - sy);	       
          
      	return Math.hypot(nx, ny);
    }	
    
    
    /**
     * 将百分比转换为图心角角度
     * @param totalAngle	总角度(如:360度)
     * @param percentage	百分比
     * @return 圆心角度
     */
	public float getSliceAngle(float totalAngle,float percentage) 
	{			
		float Angle = 0.0f;
		try{
			
			float currentValue = percentage;
			if(currentValue >= 101f || currentValue < 0.0f)
			{
				//Log.e(TAG,"输入的百分比不合规范.须在0~100之间.");			
			}else{						
				Angle =  MathHelper.getInstance().round( 
								MathHelper.getInstance().mul(totalAngle,
									MathHelper.getInstance().div(currentValue,100f) ) ,2);												
			}
			
		}catch(Exception ex)
		{
			Angle = -1f;
		}finally{
			
		}
		return  Angle;
	}
	
	
	//函数来自LnChart，位置算法现在到处都是，可以考虑优化下。[各轴，定制线]
	public float getLnPlotXValPosition(float plotScreenWidth,float plotAreaLeft,
								   double xValue, double maxValue,double minValue) {
		// 对应的X坐标
		double maxminRange = sub(maxValue, minValue);
		double xScale = div(sub(xValue, minValue), maxminRange);
		return mul(plotScreenWidth, (float) xScale);
	}    
	
	public float getLnXValPosition(float plotScreenWidth,float plotAreaLeft,
			   double xValue, double maxValue,double minValue) {
		// 对应的X坐标
		return add(plotAreaLeft, 
				getLnXValPosition(plotScreenWidth,plotAreaLeft,xValue,maxValue,minValue) );
	}    		
        
    public void disableHighPrecision()
    {
    	mHighPrecision = false;
    }
    
    public void enabledHighPrecision()
    {
    	mHighPrecision = true;
    }
	 
	/**
	 * 加法运算
	 * @param v1
	 * @param v2
	 * @return
	 */
	 public float add(float v1, float v2) 
	 {
		 if(!mHighPrecision)
		 {
			 return (v1+v2);	 
		 }else{
			 // BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		
			 BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		 
		 	 BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
		 	 return bgNum1.add(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 减法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float sub(float v1, float v2) 
	 {
		 if(!mHighPrecision)
		 {
			 return (v1 - v2);	 
		 }else{
			 BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		 		 
			 BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			 return bgNum1.subtract(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 乘法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float mul(float v1, float v2) 
	 {		
		 if(!mHighPrecision)
		 {
			 return (v1 * v2);	 
		 }else{
			  BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			  return bgNum1.multiply(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 除法运算,当除不尽时，精确到小数点后10位
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float div(float v1, float v2)
	 {		
		return div(v1, v2, DEFAULT_DIV_SCALE);		 
	 }
		 
	 /**
	  * 除法运算,当除不尽时，精确到小数点后scale位
	  * @param v1
	  * @param v2
	  * @param scale
	  * @return 运算结果
	  */
	 public float div(float v1, float v2, int scale) 
	 {		 		 
		  if (scale < 0) 
		   throw new IllegalArgumentException("The scale must be a positive integer or zero");
		
		  if( Float.compare(v2, 0.0f) == 0)return 0.0f;
		  
		  if(!mHighPrecision)
		  {
			 return (v1 / v2);	 
		  }else{		  							
			  BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
		  }
	 }
		 
	 /**
	  * 四舍五入到小数点后scale位
	  * @param v
	  * @param scale
	  * @return 
	  */
	 public float round(float v, int scale) 
	 {
		  if (scale < 0) 
			  throw new IllegalArgumentException("The scale must be a positive integer or zero");
			
		  BigDecimal bgNum1 = new BigDecimal(Float.toString(v));
		  BigDecimal bgNum2 = new BigDecimal("1");
		  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).floatValue();		  
		 // return b.setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
	 }
	
	 public double add(double v1, double v2) 
	 {
		 if(!mHighPrecision)
		  {
			 return (v1 + v2);	 
		  }else{
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.add(bgNum2).doubleValue();
		  }
	 }
	 
	 public double sub(double v1, double v2) 
	 {		 
		 if(!mHighPrecision)
		  {
			 return (v1 - v2);	 
		  }else{
			 BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			 BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			 return bgNum1.subtract(bgNum2).doubleValue();
		  }
	 }
	 
	 
	 /**
	  * 除法计算,使用默认精度
	  * @param v1
	  * @param v2
	  * @return
	  */
	 public double div(double v1, double v2) 
	 {
		 return div(v1,v2,DEFAULT_DIV_SCALE);
	 }
	 
	 /**
	  * 除法计算
	  * @param v1
	  * @param v2
	  * @param scale	指定保留精度
	  * @return
	  */
	 public double div(double v1, double v2, int scale) 
	 {
		  if (scale < 0) 
		   throw new IllegalArgumentException("The scale must be a positive integer or zero");
		
		  if(Double.compare(v2, 0d) == 0) return 0d;
		  
		  if(!mHighPrecision)
		  {
			 return (v1 / v2);	 
		  }else{		  
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
		  }
	 }	 	 	
	 
	 /**
	  * 乘法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public double mul(double v1, double v2) 
	 {		
		 if(!mHighPrecision)
		 {
			 return (v1 * v2);	 
		 }else{
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.multiply(bgNum2).doubleValue();
		 }
	 }
	 
	 /**
	  * 四舍五入到小数点后scale位
	  * @param v
	  * @param scale
	  * @return 
	  */
	 public double round(double v, int scale) 
	 {
		  if (scale < 0) 
			  throw new IllegalArgumentException("The scale must be a positive integer or zero");
			
		  BigDecimal bgNum1 = new BigDecimal(Double.toString(v));
		  BigDecimal bgNum2 = new BigDecimal("1");
		  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();		  
		 // return b.setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
	 }
	 
} public class AnchorDataPoint {
	
	private int mDataSeriesID = -1; //
	private int mDataChildID = -1; //Points
	
	private XEnum.AnchorStyle mAnchorStyle = XEnum.AnchorStyle.RECT;
	private String mAnchor = "";
	private int mAnchorTextSize = 22;
	private int mAnchorTextColor = Color.BLUE;
	
	private int mBgColor = Color.BLACK;
	private int mAlpha = 100;
	private XEnum.DataAreaStyle mDataAreaStyle = XEnum.DataAreaStyle.STROKE;
	
	private float mRadius = 30.f;
	private float mRoundRaidus = 15.f;
	
	private int mLineWidth = -1;
	//private XEnum.LineStyle  mLineStyle = XEnum.LineStyle.SOLID;
	
	private float mCapRectW = 20.f;
	private float mCapRectH = 10.f;
	private float mCapRectHeight = 30.f;
	
	//线的风格(点或线之类)
	protected XEnum.LineStyle mLineStyle = XEnum.LineStyle.SOLID;
	
	
	public AnchorDataPoint()
	{
		
	}

	public AnchorDataPoint(int dataSeriesID,int dataChildID,XEnum.AnchorStyle anchorStyle)
	{
		mDataSeriesID = dataSeriesID;
		mDataChildID = dataChildID;
		mAnchorStyle = anchorStyle;
	}
	
	public AnchorDataPoint(int dataSeriesID,XEnum.AnchorStyle anchorStyle)
	{
		mDataSeriesID = dataSeriesID;
		mAnchorStyle = anchorStyle;
	}
	
	
	public XEnum.AnchorStyle getAnchorStyle() {
		return mAnchorStyle;
	}

	public void setAnchorStyle(XEnum.AnchorStyle style) {
		this.mAnchorStyle = style;
	}


	public int getDataSeriesID() {
		return mDataSeriesID;
	}



	public void setDataSeriesID(int mDataSeriesID) {
		this.mDataSeriesID = mDataSeriesID;
	}



	public int getDataChildID() {
		return mDataChildID;
	}



	public void setDataChildID(int mDataChildID) {
		this.mDataChildID = mDataChildID;
	}
	
	public void setAnchor(String anchor)
	{
		mAnchor = anchor;
	}
	
	public String getAnchor()
	{
		return mAnchor;
	}
	
	
	public void setRadius(float radius)
	{
		mRadius = radius;
	}
	
	public float getRadius()
	{
		return mRadius;
	}
	
	public void setTextSize(int size)
	{
		mAnchorTextSize = size;
	}
	
	public float getTextSize()
	{
		return mAnchorTextSize;
	}
	
	public void setTextColor(int color)
	{
		mAnchorTextColor = color;
	}
	
	public int getTextColor()
	{
		return mAnchorTextColor;
	}
	
	public void setLineWidth(int size)
	{
		mLineWidth = size;
	}
	
	public int getLineWidth()
	{
		return mLineWidth;
	}	
	
	//public XEnum.LineStyle getLineStyle()
	//{
	//	return mLineStyle;
	//}

	//public void setLineStyle(XEnum.LineStyle style)
	//{
	//	 mLineStyle = style;
	//}			
	
	public void setAlpha(int alpha)
	{
		mAlpha = alpha;
	}
	
	public int getAlpha()
	{
		return mAlpha;
	}
	
	public void setBgColor(int color)
	{
		mBgColor = color;
	}
	
	public int getBgColor()
	{
		return mBgColor;
	}
	
	public void setAreaStyle(XEnum.DataAreaStyle style)
	{
		mDataAreaStyle = style;
	}
	
	public XEnum.DataAreaStyle getAreaStyle()
	{
		return mDataAreaStyle;
	}
	
	/**
	 * 当风格为CAPRECT时，可用此函数来设置三角形的宽/高
	 * @param width  三角形的宽
	 * @param height 三角形的高
	 */
	public void setCapRectAngleWH(float capWidth,float capHeight)
	{		
		mCapRectW = capWidth;
		mCapRectH = capHeight;
	}
		
	/**
	 * 当风格为CAPRECT时，设置Rect的高度
	 * @param rectHeight
	 */
	public void setCapRectHeight(float rectHeight)
	{
		mCapRectHeight = rectHeight;
	}
	
	
	public float getCapRectW()
	{
		return mCapRectW;
	}
	
	public float getCapRectH()
	{
		return mCapRectH;
	}
	
	public float getCapRectHeight()
	{
		return mCapRectHeight;
	}
	
	
	/**
	 * 设置角圆弧半径
	 * @param radius 半径
	 */
	public void setRoundRadius(int radius)
	{
		mRoundRaidus = radius;
	}
	
	/**
	 * 返回角圆弧半径
	 * @return 半径
	 */
	public float getRoundRadius()
	{		
		return mRoundRaidus;		
	}
	
	
	/**
	 * 设置线的风格(点或线之类)
	 * @param style 线的风格
	 */
	public void setLineStyle(XEnum.LineStyle  style)
	{
		mLineStyle = style;
	}
	
	
	/**
	 * 返回线的风格
	 * @return 线的风格
	 */
	public XEnum.LineStyle getLineStyle()
	{
		return mLineStyle;		
	}

} public class AnchorRender {
	
	private static AnchorRender instance = null;
	
	private RectF mRect= null;
	
	private Paint mPaintText = null;
	private Paint mPaintBg = null;
	
	public AnchorRender()
	{

	}
	
	public static synchronized AnchorRender getInstance()
	{
		if(instance == null)
		{
			instance = new AnchorRender();
		}
		return instance;
	}
	
	
	public void renderAnchor(Canvas canvas,
					AnchorDataPoint pAnchor, float cx, float cy,float cradius,
					float left,float top,float right, float bottom) {
		
		if(null == pAnchor) return;		
		float radius = pAnchor.getRadius();	
		
		switch(pAnchor.getAreaStyle())
		{
		case FILL:
			getBgPaint().setStyle(Style.FILL);
			break;
		case STROKE:
			getBgPaint().setStyle(Style.STROKE);
			break;		
		}		
		getBgPaint().setColor(pAnchor.getBgColor());
		
		float width = getBgPaint().getStrokeWidth();
		if( pAnchor.getLineWidth() > -1 )
		{			
			getBgPaint().setStrokeWidth(pAnchor.getLineWidth());
		}		
		
		switch (pAnchor.getAnchorStyle()) {
		case CAPRECT:
		case CAPROUNDRECT:
		case ROUNDRECT:	
			renderRoundRect(canvas,pAnchor,cx, cy,radius);
			break;
		default:		
			switch (pAnchor.getAnchorStyle()) {
			case RECT:	
				renderRect(canvas,getBgPaint(),radius,cx, cy);
				break;	
			case CIRCLE:			
				canvas.drawCircle(cx, cy, radius, getBgPaint());
				
				break;			
			case VLINE:	
				//canvas.drawLine(cx, top,cx, bottom, getBgPaint());
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						cx, top,cx, bottom,
						canvas, getBgPaint());
				break;
			case HLINE:	
				//canvas.drawLine(left, cy,right, cy, getBgPaint());
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						left, cy,right, cy,
						canvas, getBgPaint());
				break;
			case TOBOTTOM:				
				//canvas.drawLine(cx, cy + cradius,cx,bottom, getBgPaint());				
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						cx, cy + cradius,cx,bottom,
						canvas, getBgPaint());				
				break;
			case TOTOP:		
				//canvas.drawLine(cx, cy - cradius,cx, top, getBgPaint());
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						cx, cy - cradius,cx, top,
						canvas, getBgPaint());	
				break;
			case TOLEFT:	
				//canvas.drawLine(cx - cradius, cy,left, cy, getBgPaint());
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						cx - cradius, cy,left, cy,
						canvas, getBgPaint());
				break;
			case TORIGHT:		
				//canvas.drawLine(cx + cradius, cy,right, cy, getBgPaint());
				DrawHelper.getInstance().drawLine(pAnchor.getLineStyle(), 
						cx + cradius, cy,right, cy,
						canvas, getBgPaint());
				break;
			default:
			}		
									
			if(pAnchor.getAnchor().trim() != "" )
			{
				getTextPaint().setColor(pAnchor.getTextColor());
				getTextPaint().setTextSize(pAnchor.getTextSize());
				canvas.drawText(pAnchor.getAnchor(), cx, cy, getTextPaint());
			}		
		}
		
		getBgPaint().setStrokeWidth(width);
	}
	
	private void renderRoundRect(Canvas canvas,
			AnchorDataPoint pAnchor,
			float cirX,float cirY,float radius){
		
		float angleW = pAnchor.getCapRectW() / 2;//20.f;
		float angleH = pAnchor.getCapRectH(); //10.f;
		
		float fontH =  pAnchor.getCapRectHeight(); // angleH ; // + 5.f;		
		float extW = angleW + radius;	
		
		if(Float.compare(radius, angleW) == -1 || Float.compare(radius, angleW) == 0)
		{
			extW = angleW + 30.f;
		}			
			
		String anchor = pAnchor.getAnchor().trim();					
		if(pAnchor.getAnchor() != "")
		{			
			float textHeight = DrawHelper.getInstance().getPaintFontHeight(getTextPaint()) + 30.f;			
			if(Float.compare(textHeight, fontH) == 1) fontH = textHeight;			
			float textWidth = DrawHelper.getInstance().getTextWidth(getTextPaint(), anchor);		
			if( Float.compare(textWidth, extW ) == 1 ) extW = textWidth;			
		}	
		
		switch (pAnchor.getAnchorStyle()) {
		case CAPRECT:
			renderCapRect(canvas,pAnchor,cirX, cirY, radius,angleW,angleH,fontH,extW);			
			break;
		case CAPROUNDRECT:
			renderCapRound(canvas,pAnchor,cirX,cirY,radius,angleW,angleH,fontH,extW);
			break;
		case ROUNDRECT:
			renderRound(canvas,pAnchor,cirX, cirY, radius,angleW,angleH,fontH,extW);
			break;
		default:
		}		
		
		if(pAnchor.getAnchor() != "")
		{
			getTextPaint().setColor(pAnchor.getTextColor());
			getTextPaint().setTextSize(pAnchor.getTextSize());
			canvas.drawText(anchor, cirX,  cirY - angleH - fontH/3, getTextPaint());			
		}
		mPaintText = null;
	}
	
	private void renderCapRound(Canvas canvas,AnchorDataPoint pAnchor,
			float cirX,float cirY,float radius,
			float angleW,float angleH,float fontH,float extW){
		//round Rect这种强制bgPaint为fill
		getBgPaint().setStyle(Style.FILL);			
		renderRound(canvas,pAnchor,cirX,cirY,radius,angleW,angleH,fontH,extW);		
		renderCap(canvas,pAnchor,cirX,cirY,radius,angleW,angleH,fontH,extW);
	}
	
	private void renderCapRect(Canvas canvas,AnchorDataPoint pAnchor,
			float cirX,float cirY,float radius,
			float angleW,float angleH,float fontH,float extW){
				
		Path path = new Path();
		path.moveTo(cirX, cirY);
		path.lineTo(cirX - angleW , cirY - angleH);
		path.lineTo(cirX - extW , cirY - angleH);		
		path.lineTo(cirX - extW, cirY - angleH - fontH);
		path.lineTo(cirX + extW,  cirY - angleH - fontH); 
		path.lineTo(cirX + extW,  cirY - angleH );
		path.lineTo(cirX + angleW,  cirY - angleH );
		path.lineTo(cirX, cirY);
		path.close();
		canvas.drawPath(path, getBgPaint());		
		path.reset();	
	}

	private void renderRound(Canvas canvas,AnchorDataPoint pAnchor,
			float cirX,float cirY,float radius,
			float angleW,float angleH,float fontH,float extW){
		
		if(null == mRect)mRect = new RectF();		
		mRect.left =  cirX - extW;
		mRect.top =   cirY - angleH - fontH; 
		mRect.right =  cirX + extW;
		mRect.bottom = cirY - angleH;
		
		getBgPaint().setStyle(Style.FILL);	
		
		canvas.drawRoundRect(mRect, pAnchor.getRoundRadius(), 
				pAnchor.getRoundRadius(), getBgPaint());	
		mRect.setEmpty();
	}
	
	private void renderCap(Canvas canvas,AnchorDataPoint pAnchor,
			float cirX,float cirY,float radius,
			float angleW,float angleH,float fontH,float extW){		
							
		Path path = new Path();
		path.moveTo(cirX, cirY);
		path.lineTo(cirX - angleW , cirY - angleH);
		path.lineTo(cirX + angleW,  cirY - angleH );
		path.close();
		canvas.drawPath(path, getBgPaint());		
		path.reset();					
	}

	private void renderRect(Canvas canvas,Paint paint,
							float radius,float cirX,float cirY )
	{		
		if(null == mRect)mRect = new RectF();
		
		mRect.left =  (cirX - radius);
		mRect.top =   (cirY - radius); 
		mRect.right =  (cirX + radius);
		mRect.bottom = (cirY + radius);
		canvas.drawRect(mRect,getBgPaint());		
		mRect.setEmpty();
	}
	
	private Paint getTextPaint()
	{
		if(null == mPaintText)
		{
			mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG);		
			mPaintText.setTextAlign(Align.CENTER);
		}
		return mPaintText;
	}
	
	private Paint getBgPaint()
	{
		if(null == mPaintBg) mPaintBg = new Paint(Paint.ANTI_ALIAS_FLAG);	
		mPaintBg.setStrokeWidth(2);
		return mPaintBg;
	}
	
	
	
} public class DyLine {
	
	private Paint mPaintLine = null;
	protected PointF mCenterXY = null;
	//设置交叉线显示风格
	private XEnum.DyLineStyle mDyLineStyle = XEnum.DyLineStyle.Cross;
	
	//线绘制为实线，虚实线 	等哪种风格
	private XEnum.LineStyle mLineDrawStyle = XEnum.LineStyle.SOLID;
	
	private float mOldX = 0.0f,mOldY =0.0f;
	
	public DyLine()
	{
		
	}
	
	/**
	 * 线的画笔
	 * @return
	 */
	public Paint getLinePaint()
	{
		if(null == mPaintLine)
		{
			mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
			//mPaintLine.setStyle(Style.STROKE);
			mPaintLine.setColor(Color.rgb(215, 10, 10)); //50, 165, 238));			
		}
		
		return mPaintLine;
	}

	/**
	 * 点击位置坐标
	 * @param x		x坐标
	 * @param y		y坐标
	 */
	public void setCurrentXY(float x,float y) //setCurrentXY
	{
		if(null == mCenterXY) mCenterXY = new PointF();
		mCenterXY.x = x;
		mCenterXY.y = y;
	}
	
	/**
	 * 是否需要重绘
	 * @return 是否允许重绘
	 */
	public boolean isInvalidate()
	{
		if(null == mCenterXY) return false;
		if(Float.compare(Math.abs(mCenterXY.x - mOldX ) , 5.f ) == 1 
        		|| Float.compare(Math.abs(mCenterXY.y - mOldY), 5.f) == 1)
        {        				          				       
        	mOldX = mCenterXY.x;
        	mOldY = mCenterXY.y;		
        	return true;
        }	
		return false;
	}
	
	
	/**
	 * 设置线的风格
	 * @param style 线的交叉风格
	 */
	public void setDyLineStyle(XEnum.DyLineStyle style)
	{
		mDyLineStyle = style;
	}
	
	/**
	 * 返回线的风格
	 * @return  线的交叉风格
	 */
	public XEnum.DyLineStyle getDyLineStyle()
	{
		return mDyLineStyle;
	}
	

	/**
	 * 设置线绘制为实线，虚实线 	等哪种风格
	 * @param style 线的类型
	 */
	public void setLineDrawStyle(XEnum.LineStyle style)
	{
		mLineDrawStyle = style;
	}
	
	/**
	 * 返回线的绘制类型(实线，虚实线等)
	 * @return 线的绘制类型
	 */
	public XEnum.LineStyle getLineDrawStyle()
	{
		return mLineDrawStyle;
	}
	
	
} public class DyLineRender extends DyLine{
	
	
	private float mLeft = 0.0f;
	private float mTop = 0.0f;
	private float mRight = 0.0f;
	private float mBottom = 0.0f;
	
	public DyLineRender()
	{
	}
		
	// Cross 指定交叉的水平线和垂直线。
	// BackwardDiagonal 从右上到左下的对角线的线条图案。
	// Vertical		垂直线
	// Horizontal 水平线
	private void drawCross(Canvas canvas)
	{	
		//竖线
		drawVertical(canvas);
		//横线
		drawHorizontal(canvas);
	}
	
	private void drawBackwardDiagonal(Canvas canvas)
	{		
		//竖线
		DrawHelper.getInstance().drawLine(getLineDrawStyle(), 
				mCenterXY.x, mCenterXY.y, mCenterXY.x, mBottom,canvas,getLinePaint());	
		//横线
		DrawHelper.getInstance().drawLine(getLineDrawStyle(), 
				mLeft, mCenterXY.y, mCenterXY.x, mCenterXY.y,canvas,getLinePaint());	
	}
	
	private void drawVertical(Canvas canvas) //竖线
	{			
		DrawHelper.getInstance().drawLine(getLineDrawStyle(), 
				mCenterXY.x, mTop, mCenterXY.x, mBottom,canvas,getLinePaint());	
	}
	
	private void drawHorizontal(Canvas canvas)
	{
		DrawHelper.getInstance().drawLine(getLineDrawStyle(), 
				mLeft, mCenterXY.y, mRight, mCenterXY.y,canvas,getLinePaint());	
	}

	public void renderLine(Canvas canvas,float left,float top,float right,float bottom) 
	{						
		if(null == mCenterXY) return;
						
		//if(Float.compare(left, 0.0f) == 0 && Float.compare(top, 0.0f) == 0 &&
		//	Float.compare(right, 0.0f) == 0 && Float.compare(bottom, 0.0f) == 0) return;
		
		if(Float.compare(mCenterXY.x, left) == 0 ||
		  Float.compare(mCenterXY.x, left) == -1 ||
		  Float.compare(mCenterXY.x, right) == 0 ||
		  Float.compare(mCenterXY.x, right) == 1 ||				  
		  Float.compare(mCenterXY.y, top) == 0 ||
		  Float.compare(mCenterXY.y, top) == -1 ||
		  Float.compare(mCenterXY.y, bottom) == 0 ||
		  Float.compare(mCenterXY.y, bottom) == 1 ) return;
		
		
		mLeft = left;
		mTop = top;
		mRight = right;
		mBottom = bottom;
		
		switch(getDyLineStyle())
		{
		case Cross:
			drawCross(canvas);
			break;
		case BackwardDiagonal:
			drawBackwardDiagonal(canvas);
			break;
		case Vertical:
			drawVertical(canvas);
			break;
		case Horizontal:
			drawHorizontal(canvas);
			break;
		}
	}

} public class Legend extends DyInfo{
	
	protected float mXPercentage = 0.0f;
	protected float mYPercentage = 0.0f;
	
	
	public Legend()
	{

	}
	
	/**
	 * 设置显示位置
	 * @param xPercentage	占绘图区的竖向百分比位置
	 * @param yPercentage	占绘图区的横向百分比位置
	 */
	public void setPosition(float xPercentage,float yPercentage)
	{
		mXPercentage = xPercentage;
		mYPercentage = yPercentage;
	}
	
	/**
	 * 增加动态图例
	 * @param text	文本
	 * @param paint	画笔
	 */
	public void addLegend(String text,Paint paint)
	{
		addInfo(text,paint);
	}
	
	/**
	 * 增加动态图例
	 * @param dotStyle		图案风格
	 * @param text			文本
	 * @param paint			画笔
	 */
	public void addLegend(PlotDot dotStyle,String text,Paint paint)
	{
		addInfo(dotStyle,text,paint);
	}
	

} public class LegendRender extends Legend{
	
	public LegendRender()
	{

	}
	
	public void setPlotWH(float width,float height)
	{				
		setCenterXY(width * mXPercentage,height * mYPercentage);
	}

	public void renderInfo(Canvas canvas) 
	{
		drawInfo(canvas);
	}
	
} public class Border {		

	//线的基类画笔	
	private Paint mPaintBorderLine = null;

	private XEnum.LineStyle mLineStyle = XEnum.LineStyle.SOLID;
	private XEnum.RectType mRectType = XEnum.RectType.ROUNDRECT;	
	private int mRaidus = 15;
	protected static final int mBorderSpadding = 5;
	
	//背景画笔
	protected Paint mPaintBackground = null;

	public Border()
	{							
									
	}
	
	
	/**
	 * 开放线的画笔
	 * @return 画笔
	 */
	public Paint getLinePaint()
	{
		if(null == mPaintBorderLine)
		{
			mPaintBorderLine = new Paint();
			mPaintBorderLine.setAntiAlias(true);
			mPaintBorderLine.setColor(Color.BLACK); //(int)Color.rgb(26, 59, 105));
			mPaintBorderLine.setStyle(Style.STROKE);  		
			mPaintBorderLine.setStrokeWidth(2);	
		}
		return mPaintBorderLine;
	}
		
	/**
	 * 设置线的颜色	
	 * @param color 线的颜色
	 */
	public void setBorderLineColor(int color) 
	{			
		getLinePaint().setColor(color );
	}
	
	/**
	 * 设置边框线类型
	 * @param style 线类型
	 */
	public void setBorderLineStyle(XEnum.LineStyle style) 
	{				
		mLineStyle = style;
	}	
	
	/**
	 * 设置边框类型
	 * @param type 框类型
	 */
	public void setBorderRectType(XEnum.RectType type) 
	{				
		mRectType = type;
	}
				
	/**
	 * 返回边框线类型
	 * @return 边框线类型
	 */
	public XEnum.LineStyle getBorderLineStyle()
	{
		return mLineStyle;		
	}
	
	/**
	 * 返回边框类型
	 * @return 边框类型
	 */
	public XEnum.RectType getBorderRectType()
	{
		return mRectType;
	}
	
	/**
	 * 设置角圆弧半径
	 * @param radius 半径
	 */
	public void setRoundRadius(int radius)
	{
		mRaidus = radius;
	}
	
	/**
	 * 返回角圆弧半径
	 * @return 半径
	 */
	public int getRoundRadius()
	{		
		return mRaidus;		
	}
	
	/**
	 * 返回边框所占宽度
	 * @return 边框所占宽度
	 */
	public int getBorderWidth()
	{
		int width = mBorderSpadding;		
		if(getBorderRectType() == XEnum.RectType.ROUNDRECT)
		{
			width += getRoundRadius();
		}		
		return width;
	}
	
	/**
	 * 开放背景画笔
	 * @return 画笔
	 */
	 public Paint getBackgroundPaint()
	{
		if(null == mPaintBackground)
		{
			mPaintBackground = new Paint();
			mPaintBackground.setAntiAlias(true);
			mPaintBackground.setStyle(Style.FILL);
			mPaintBackground.setColor(Color.WHITE);
			mPaintBackground.setAlpha(220);
		}
		return mPaintBackground;
	}
	
} public class BorderRender extends Border {
	
	private RectF mRect = new RectF();	
	private Path mPath = null;
	

	public BorderRender()
	{
	}
	
	/**
	 * 边框默认内边距
	 * @return 内边距
	 */
	public int getBorderSpadding()
	{
		return mBorderSpadding;
	}
	
	 private void setPaintLineStyle()
	 {
		 switch(getBorderLineStyle())
			{
			case SOLID:					
				break;
			case DOT:			
				getLinePaint().setPathEffect(DrawHelper.getInstance().getDotLineStyle());			
				break;
			case DASH:		
				//虚实线 	
				getLinePaint().setPathEffect(DrawHelper.getInstance().getDashLineStyle());
				break;
			}
	 }
	 
	 
	public void renderRect(Canvas canvas,RectF rect,
							boolean showBoxBorder,boolean showBackground)
	{			
		setPaintLineStyle();							
		switch(getBorderRectType())
		{
			case RECT:		
				if(showBackground)
					canvas.drawRect(rect, getBackgroundPaint());	
				
				if(showBoxBorder)
					canvas.drawRect(rect, getLinePaint());
				break;
			case ROUNDRECT:		
				if(showBackground)
						canvas.drawRoundRect(rect, getRoundRadius(), 
											 getRoundRadius(), getBackgroundPaint());	
				if(showBoxBorder)
					canvas.drawRoundRect(rect, getRoundRadius(), 
											getRoundRadius(), getLinePaint());					
			break;
		}			
	}
	

	public void renderCapRect(Canvas canvas,RectF rect,float capHeight,
			boolean showBoxBorder,boolean showBackground)
	{	
		
		setPaintLineStyle();	
		
		if(null == mPath) mPath = new Path();
				
		float centerX = rect.left + rect.width() * 0.5f;			
		float AngleH = capHeight; 						
		float AngleY = rect.bottom;
		
		mPath.moveTo(rect.left, rect.bottom);
		mPath.lineTo(rect.left, rect.top);
		mPath.lineTo(rect.right, rect.top);
		mPath.lineTo(rect.right, rect.bottom);
		mPath.lineTo( centerX + AngleH, AngleY);
		mPath.lineTo( centerX , AngleY + AngleH );
		mPath.lineTo( centerX - AngleH, AngleY);
		mPath.close();				
		if(showBackground)		
			canvas.drawPath(mPath, getBackgroundPaint());
		if(showBoxBorder)
			canvas.drawPath(mPath, getLinePaint());
		mPath.reset();		
	}
	
	
	public void renderCapRound(Canvas canvas,RectF rect,float capHeight,
			boolean showBoxBorder,boolean showBackground)
	{			
		
		
		if(!showBackground)	return;
		setPaintLineStyle();			
				
		float centerX = rect.left + rect.width() * 0.5f;			
		float AngleH = capHeight; 						
		float AngleY = rect.bottom;		
		
	
		if(null == mRect)mRect = new RectF();
		mRect.left = rect.left + mBorderSpadding;
		mRect.top = rect.top + mBorderSpadding;
		mRect.right = rect.right - mBorderSpadding;
		mRect.bottom = rect.bottom - mBorderSpadding;	
		
		getBackgroundPaint().setStyle(Style.FILL);
		//getLinePaint().setStyle(Style.STROKE);				
		canvas.drawRoundRect(mRect, this.getRoundRadius(), this.getRoundRadius(), getBackgroundPaint());

	  
		if(null == mPath) mPath = new Path();	
		
		float pHeight = DrawHelper.getInstance().getPaintFontHeight(getBackgroundPaint());
		mPath.moveTo( centerX + AngleH, AngleY - pHeight );
		mPath.lineTo( centerX , AngleY + AngleH );
		mPath.lineTo( centerX - AngleH, AngleY - pHeight);
		mPath.close();		
		canvas.drawPath(mPath, getBackgroundPaint());
		mPath.reset();
	
		
		
		/*
		if(showBoxBorder)
		{										
			mPath.moveTo(rect.left, rect.bottom);
			mPath.lineTo(rect.left, rect.top);
			mPath.lineTo(rect.right, rect.top);
			mPath.lineTo(rect.right, rect.bottom);
			mPath.lineTo( centerX + AngleH, AngleY);
			mPath.lineTo( centerX , AngleY + AngleH );
			mPath.lineTo( centerX - AngleH, AngleY);
			mPath.close();		
			canvas.drawPath(mPath, getLinePaint());
			mPath.reset();
		}
		*/
		
	}
	
	
	public void renderRound(Canvas canvas,RectF rect,float capHeight,
			boolean showBoxBorder,boolean showBackground)
	{	
		
		setPaintLineStyle();	
		
		if(null == mRect)mRect = new RectF();
		mRect.left = rect.left + mBorderSpadding;
		mRect.top = rect.top + mBorderSpadding;
		mRect.right = rect.right - mBorderSpadding;
		mRect.bottom = rect.bottom - mBorderSpadding;	
		
		if(showBackground)	
		  canvas.drawRoundRect(mRect, this.getRoundRadius(), this.getRoundRadius(), getBackgroundPaint());
		
		if(showBoxBorder)	
			  canvas.drawRoundRect(mRect, this.getRoundRadius(), this.getRoundRadius(), getLinePaint());
				
	}
	

	/**
	 * 绘制边
	 * @param canvas	画布
	 * @param left	左边距
	 * @param top	上边距
	 * @param right	右边距
	 * @param bottom	底边距
	 */
	public void renderBorder(String type ,Canvas canvas,
							 float left,float top,float right,float bottom)
	{
		
		mRect.left = left + mBorderSpadding;
		mRect.top = top + mBorderSpadding;
		mRect.right = right - mBorderSpadding;
		mRect.bottom = bottom - mBorderSpadding;		
			
		setPaintLineStyle();	
		
		switch(getBorderRectType())
		{
			case RECT:				
				if(type.equals("CHART"))
				{
					if(null != mPaintBackground) 
						canvas.drawRect(mRect, mPaintBackground);		
				}else{ //BORDER
					canvas.drawRect(mRect, getLinePaint());
				}
				break;
			case ROUNDRECT:		
				if(type.equals("CHART"))
				{
					if(null != mPaintBackground)
						canvas.drawRoundRect(mRect, getRoundRadius(), 
								getRoundRadius(), mPaintBackground);	
				}else{ //BORDER
					canvas.drawRoundRect(mRect, getRoundRadius(), 
								getRoundRadius(), getLinePaint());		
				}
			break;
		}
	}
	
	
} public class PlotArea {
	
	//主图表区范围
	protected float mLeft  = 0.0f;
	protected float mTop  = 0.0f;
	protected float mRight   = 0.0f;
	protected float mBottom  = 0.0f;
	
	private float mWidth = 0.0f;
	private float mHeight = 0.0f;
	
	//主图表区背景色,即画X轴与Y轴围成的区域
	private Paint mBackgroundPaint = null;	
	
	//是否画背景色
	private boolean mBackgroundColorVisible = false;
	
	//扩展宽度
	private float mExtWidth = 0.0f;
	
	//是否应用渲染模式
	private boolean mApplayGradient = false;
		
	private int mBeginColor = Color.WHITE;
    private int mEndColor = Color.WHITE;
	private Shader.TileMode mTileMode = Shader.TileMode.MIRROR;
	private XEnum.Direction mDirection = XEnum.Direction.VERTICAL;
		
	
	public PlotArea()
	{

	}
	
	private void initBackgroundPaint()
	{
		if(null == mBackgroundPaint)
		{
			mBackgroundPaint = new Paint();
			mBackgroundPaint.setStyle(Style.FILL);	
			mBackgroundPaint.setColor(Color.WHITE);
		}
	}
	
	
	/**
	 * 开放主图表区背景画笔，即画X轴与Y轴围成的区域的背景画笔。
	 * @return 画笔
	 */
	 public Paint getBackgroundPaint()
	 {
		 initBackgroundPaint();
		 return mBackgroundPaint;
	 }
	 
	 /**
	  * 设置是否显示背景色
	  * @param visible 是否显示背景色
	  */
	public void setBackgroundColorVisible(boolean visible)
	{
		mBackgroundColorVisible = visible;
	}
	
	/**
	 * 返回是否显示背景色
	 * @return 是否显示背景色
	 */
	public boolean getBackgroundColorVisible()
	{
		return mBackgroundColorVisible;
	}
	
	
	/**
	 * 设置是否显示背景色及其背景色的值
	 * @param visible 是否显示背景色
	 * @param color	      背景色
	 */
	public void setBackgroundColor(boolean visible,int color)
	{
		mBackgroundColorVisible = visible;
		getBackgroundPaint().setColor(color);
		
		setBeginColor(color);
		setEndColor(color);		
	}	
	

	/**
	 * 绘图区左边位置X坐标
	 * @return X坐标
	 */
	public float getLeft() {
		return mLeft;
	}
	
	public float getPlotLeft() {
		return mLeft;
	}

	/**
	 * 绘图区上方Y坐标
	 * @return Y坐标
	 */
	public float getTop() {
		return mTop ;
	}
	
	public float getPlotTop() {
		return mTop ;
	}
	
	/**
	 * 绘图区下方Y坐标
	 * @return Y坐标
	 */
	public float getBottom() {
		return mBottom ;
	}
	
	public float getPlotBottom() {
		return mBottom ;
	}
	
	/**
	 * 绘图区右边位置X坐标
	 * @return X坐标
	 */
	public float getRight() {
		return mRight;
	}
	
	public float getPlotRight() {
		return (mRight + mExtWidth);
	}
	
	/**
	 * 绘图区宽度
	 * @return 宽度
	 */
	public float getWidth() {		
		mWidth = Math.abs(mRight - mLeft);		
		return mWidth;
	}
	
	
	public float getPlotWidth() {		
		return Math.abs(mRight + mExtWidth - mLeft);		
	}
	

	/**
	 * 绘图区高度
	 * @return 高度
	 */
	public float getHeight() {		
		mHeight = Math.abs(getBottom() - getTop());
		return mHeight;
	}
	
	public float getPlotHeight() {		
		mHeight = Math.abs(getPlotBottom() - getPlotTop());
		return mHeight;
	}
		
	/*
	public void showRoundRect(Canvas canvas)
	{
		BorderRender border = new BorderRender();
		border.renderBorder(canvas, mLeft  , mTop  , mRight , mBottom  ); 
	}
	*/
	
	/**
	 * 扩展绘图区的实际宽度,用来处理需要很大显示范围的图表
	 * @param width 宽度
	 */
	public void extWidth(float width)
	{
		mExtWidth = width;
	}
	
	public float getExtWidth()
	{
		return mExtWidth;
	}
	
	/**
	 * 设置 是否应用渲染模式
	 */
	public void setApplayGradient(boolean status)
	{
		mApplayGradient = status;
	}
	
	/**
	 * 返回是否应用渲染模式
	 * @return 状态
	 */
	public boolean getApplayGradient()
	{
		return mApplayGradient;
	}
	
	/**
	 * 设置渐变渲染方向	
	 * @param direction 方向
	 */
	public void setGradientDirection(XEnum.Direction direction)
	{
		mDirection = direction;
	}
	
	/**
	 * 返回渐变渲染方向	
	 * @return 方向	
	 */
	public XEnum.Direction getGradientDirection()
	{
		return mDirection;
	}
	
	/**
	 * 设置渲染模式
	 * @param tm	渲染模式
	 */
	 public void setGradientMode(Shader.TileMode tm)
	 {
		 mTileMode = tm;
	 }
	 
	 /**
	  * 返回渲染模式
	  * @return 渲染模式
	  */
	 public Shader.TileMode getGradientMode()
	 {
		 return mTileMode;
	 }
	 
	 /**
	  * 设置起始颜色
	  * @param color	颜色
	  */
	 public void setBeginColor(int color)
	 {
		 mBeginColor = color;
	 }
	 
	 /**
	  * 设置结束颜色
	  * @param color	颜色
	  */
	 public void setEndColor(int color)
	 {
		 mEndColor = color;
	 }
	 
	 
	 /**
	  * 返回起始颜色
	  * @return	颜色
	  */
	 public int getBeginColor()
	 {
		 return mBeginColor;
	 }
	 
	 /**
	  * 返回结束颜色
	  * @return	颜色
	  */
	 public int getEndColor()
	 {
		 return mEndColor;
	 }
	
	
} public class PlotAreaRender extends PlotArea implements IRender{

	public PlotAreaRender()
	{

	}
		
	/**
	 * 绘制背景
	 */
	protected void drawPlotBackground(Canvas canvas)
	{
		if(null == canvas) return;
		if(getBackgroundColorVisible())
		{
			if(getApplayGradient())
			{			
				LinearGradient  linearGradient ;
				if(getGradientDirection() == XEnum.Direction.VERTICAL)
				{
					linearGradient = new LinearGradient(
							0, 0, 0, getBottom() - getTop(),							
							 getBeginColor(),getEndColor(), 				 
							 getGradientMode());
				}else{
					linearGradient = new LinearGradient(
							 getLeft(),getBottom(),getRight(),getTop(),
							 getBeginColor(),getEndColor(), 				 
							 getGradientMode());
				}
				getBackgroundPaint().setShader(linearGradient);    
			}else{
				getBackgroundPaint().setShader(null);
			}
			
			canvas.drawRect(mLeft,mTop,
					mRight,mBottom, getBackgroundPaint());
		}
	}		
	
	/**
	 * 得到中心点X坐标
	 * @return X坐标
	 */
	public float getCenterX() {			
		return Math.abs(mLeft + (mRight - mLeft)/2);
	}

	/**
	 * 得到中心点Y坐标
	 * @return Y坐标
	 */
	public float getCenterY() {				
		return (Math.abs(mBottom - (mBottom - mTop)/2));	
	}
	
	

	/**
	 * 设置绘图区的左边X坐标
	 * @param left	X坐标
	 */
	public void setLeft(float left) {
		this.mLeft = left;
	}
	
	/**
	 * 设置绘图区的上面Y坐标
	 * @param top	Y坐标
	 */
	public void setTop(float top) {
		this.mTop = top;
	}

	/**
	 * 设置绘图区的右边X坐标
	 * @param right	X坐标
	 */
	public void setRight(float right) {
		this.mRight = right;
	}
	
	/**
	 * 设置绘图区的底部Y坐标
	 * @param bottom	Y坐标
	 */
	public void setBottom(float bottom) {
		this.mBottom = bottom;
	}
	
	/**
	 * 返回实际绘图区最右边X值，包含了扩展绘图区范围
	 * @return 绘图区最右边X值
	 */
	@Override
	public float getPlotRight() {
		return mRight + getExtWidth();
	}
	
	
	//public float getPlotTop() {
	//	return mTop + getExtWidth();
	//}
	

	@Override
	public boolean render(Canvas canvas) throws Exception {
		// TODO Auto-generated method stub
		try{
			if(null == canvas) return false;
			drawPlotBackground(canvas);
		}catch( Exception e){
			 throw e;
		}
		return false;
	}

} public class PlotGrid {
	 //横向网格线
	 private Paint mPaintGridLineHorizontal = null;
	 //竖向网格线
	 private Paint mPaintGridLineVertical = null;
	 
	 //是否显示横向网格线
	 private boolean mGridLinesHorizontalVisible = false;
	 //是否显示竖向网格线
	 private boolean mGridLinesVerticalVisible = false;		

	 //是否显示奇数行填充色
	 private boolean mOddRowBgColorVisible = false;
	//是否显示偶数行填充色
	 private boolean mEvenRowBgColorVisible = false;
	 
	 //横向网格线
	 private Paint mPaintOddBgColor = null;
	 //竖向网格线
	 private Paint mPaintEvenBgColor = null;
	 
	 // Solid、Dot、Dash。
	 private XEnum.LineStyle mHorizontalLineStyle = XEnum.LineStyle.SOLID;
	 private XEnum.LineStyle mVerticalLineStyle = XEnum.LineStyle.SOLID;
	
	public PlotGrid()
	{		

	}
		
	private void initEvenBgColorPaint()
	{
		if(null == mPaintEvenBgColor)
		{
			mPaintEvenBgColor = new Paint();
			mPaintEvenBgColor.setStyle(Style.FILL);						
			mPaintEvenBgColor.setColor(Color.rgb(239, 239, 239)); 					
			mPaintEvenBgColor.setAntiAlias(true);
		}
	}
	
	private void initOddBgColorPaint()
	{
		if(null == mPaintOddBgColor)
		{
			mPaintOddBgColor = new Paint();
			mPaintOddBgColor.setStyle(Style.FILL);
			mPaintOddBgColor.setColor(Color.WHITE);
			mPaintOddBgColor.setAntiAlias(true);
		}
	}
	
	private void initHorizontalLinePaint()
	{
		if(null == mPaintGridLineHorizontal)
		{
			mPaintGridLineHorizontal = new Paint();
			mPaintGridLineHorizontal.setAntiAlias(true);
			mPaintGridLineHorizontal.setStrokeWidth(1);
			mPaintGridLineHorizontal.setColor(Color.rgb(180, 205, 230));
		}		
	}
	
	private void initVerticalLinePaint()
	{
		if(null == mPaintGridLineVertical)
		{
			mPaintGridLineVertical = new Paint();	
			mPaintGridLineVertical.setColor(Color.rgb(180, 205, 230));				
			mPaintGridLineVertical.setStrokeWidth(1);
			mPaintGridLineVertical.setAntiAlias(true);
		}
	}
		
	/**
	 * 设置奇数行填充色
	 * @param color 填充色
	 */
	public void setOddRowBackgroundColor(int color) 
	{
		mPaintOddBgColor.setColor(color);
	}
	/**
	 * 设置偶数行填充色
	 * @param color 填充色
	 */
	public void setEvenRowBackgroundColor(int color)
	{	
		mPaintOddBgColor.setColor(color);
	}
	
	/**
	 * 显示横向网格线
	 */
	public void showHorizontalLines()
	{
		mGridLinesHorizontalVisible = true;
	}
	
	/**
	 * 隐藏横向网格线
	 */
	public void hideHorizontalLines()
	{
		mGridLinesHorizontalVisible = false;
		if(null != mPaintGridLineHorizontal)mPaintGridLineHorizontal = null;
	}
	
	
	/**
	 * 返回是否显示横向网格线
	 * @return 是否显示
	 */
	public boolean isShowHorizontalLines()
	{
		return mGridLinesHorizontalVisible;
	}	
	
	/**
	 * 显示竖向网格线
	 * 
	 */
	public void showVerticalLines() 
	{
		mGridLinesVerticalVisible = true;
	}
	
	/**
	 * 隐藏竖向网格线
	 */
	public void hideVerticalLines() 
	{
		mGridLinesVerticalVisible = false;
		if(null != mPaintGridLineVertical)mPaintGridLineVertical =null;
	}
	
	
	/**
	 * 返回是否显示竖向网格线
	 * @return 是否显示
	 */
	public boolean isShowVerticalLines()
	{
		return mGridLinesVerticalVisible;
	}
	
	
	/**
	 * 显示奇数行背景色
	 */
	public void showOddRowBgColor()
	{
		mOddRowBgColorVisible = true;
	}
	
	/**
	 * 隐藏奇数行背景色
	 */
	public void hideOddRowBgColor()
	{
		mOddRowBgColorVisible = false;
		if(null != mPaintOddBgColor) mPaintOddBgColor = null;
	}
	
	/**
	 * 返回是否显示奇数行填充
	 * @return 是否填充
	 */
	public boolean isShowOddRowBgColor() 
	{
		return mOddRowBgColorVisible;
	}
	
	/**
	 * 显示偶数行背景色
	 */
	public void  showEvenRowBgColor() 
	{
		mEvenRowBgColorVisible = true;
	}
	
	/**
	 * 隐藏偶数行背景色
	 */
	public void  hideEvenRowBgColor() 
	{
		mEvenRowBgColorVisible = false;
		if(null != mPaintEvenBgColor) mPaintEvenBgColor = null;
	}
	
	
	/**
	 * 返回是否显示偶数行填充
	 * @return 是否填充
	 */
	public boolean isShowEvenRowBgColor()
	{
		return mEvenRowBgColorVisible;
	}
				
	/**
	 * 开放横向网格线画笔
	 * @return 画笔
	 */
	public Paint getHorizontalLinePaint()
	{
		initHorizontalLinePaint();
		return mPaintGridLineHorizontal;	
	}
			 
	/**
	 * 开放竖向网格线画笔
	 * @return 画笔
	 */
	public Paint getVerticalLinePaint()
	{
		initVerticalLinePaint();
		return mPaintGridLineVertical;	
	}
	
	/**
	 * 开放奇数行填充画笔
	 * @return 画笔
	 */
	public Paint getOddRowsBgColorPaint()
	{
		initOddBgColorPaint();
		return mPaintOddBgColor;	
	}
	 
	/**
	 * 开放偶数行填充画笔
	 * @return 画笔
	 */
	public Paint getEvenRowsBgColorPaint()
	{
		initEvenBgColorPaint();
		return mPaintEvenBgColor;	
	}

	/**
	 * 返回竖向网格线当前绘制风格
	 * @return  绘制风格
	 */
	public XEnum.LineStyle getVerticalLineStyle()
	{ 
		return mVerticalLineStyle;
	}

	/**
	 * 设置竖向网格线当前绘制风格
	 * @param style 绘制风格
	 */
	public void setVerticalLineStyle(XEnum.LineStyle style)
	{
		mVerticalLineStyle = style;
	}
	
	/**
	 * 返回横向网格线当前绘制风格
	 * @return 绘制风格
	 */
	public XEnum.LineStyle getHorizontalLineStyle()
	{
		return mHorizontalLineStyle;
	}

	/**
	 * 设置横向网格线当前绘制风格 
	 * @param style 绘制风格
	 */
	public void setHorizontalLineStyle(XEnum.LineStyle style)
	{
		mHorizontalLineStyle = style;
	}
	 
} public class PlotGridRender extends PlotGrid {
		
	private boolean mMajorTickLine = false;	
	private final int BLOB_WIDTH =  2;;
	
	public PlotGridRender()
	{
	}
	
	/**
	 * 是否为主Tick对应的网格线,如果是,在划线时需加粗
	 * @param primary 是否为主Tick如是则会加粗显示
	 */
	public void setPrimaryTickLine(boolean primary)
	{
		mMajorTickLine = primary;
	}
		
	/**
	 * 绘制奇数行填充
	 * @param left		左边X坐标
	 * @param top		顶上Y坐标
	 * @param right		右边X坐标
	 * @param bottom	底上Y坐标
	 */
	public void renderOddRowsFill(Canvas canvas,
									float left,float top,float right,float bottom)
	{
		 if(null != canvas && isShowOddRowBgColor())
		 {
             canvas.drawRect( left,  bottom  ,right, top,getOddRowsBgColorPaint());
		 }		
	}
	
	/**
	 * 绘制偶数行填充
	 * @param left 		左边X坐标
	 * @param top		顶上Y坐标
	 * @param right		右边X坐标
	 * @param bottom	 底上Y坐标
	 */
	public void renderEvenRowsFill(Canvas canvas,
									float left,float top,float right,float bottom)
	{
		 if(null != canvas && isShowEvenRowBgColor())
		 {				
			 canvas.drawRect( left,  bottom  ,right, top,getEvenRowsBgColorPaint());
		 }		
	}
	
		
	
	/**
	 * 绘制横向网格线
	 * @param startX	起始点X坐标
	 * @param startY	起始点Y坐标
	 * @param stopX		终止点X坐标
	 * @param stopY		终止点Y坐标
	 */
	public void renderGridLinesHorizontal(Canvas canvas,
								float startX,float startY,float stopX,float stopY)
	{
		 if(null != canvas &&this.isShowHorizontalLines()) 
		 {	
			 float initWidth = 0.0f;
			 if(mMajorTickLine)
			 {
				 initWidth = getHorizontalLinePaint().getStrokeWidth() ;
				 getHorizontalLinePaint().setStrokeWidth( initWidth + BLOB_WIDTH );	
			 }
			 
			 DrawHelper.getInstance().drawLine(this.getHorizontalLineStyle(), 
									 startX, startY, stopX, stopY,
									canvas, getHorizontalLinePaint());
			 
			 if(mMajorTickLine)getHorizontalLinePaint().setStrokeWidth(initWidth);
		 }
	}
	
	/**
	 * 绘制竖向网格线
	 * @param startX	起始点X坐标
	 * @param startY	起始点Y坐标
	 * @param stopX		终止点X坐标
	 * @param stopY		终止点Y坐标
	 */
	public void renderGridLinesVertical(Canvas canvas,
							float startX,float startY,float stopX,float stopY)
	{
		 if(null != canvas && isShowVerticalLines()) 
		 {						
			 float initWidth = 0.0f ;
			 if(mMajorTickLine) //主线
			 {
				 initWidth = getVerticalLinePaint().getStrokeWidth() ;
				 getVerticalLinePaint().setStrokeWidth( initWidth + BLOB_WIDTH );	
			 }
			 
			 //默认是minor
			 DrawHelper.getInstance().drawLine(this.getVerticalLineStyle(), 
												 startX, startY, stopX, stopY,
												canvas, getVerticalLinePaint());
			
			 if(mMajorTickLine)getVerticalLinePaint().setStrokeWidth(initWidth);
			
		 }
	}
	


} public class PlotLegend {
	
		//数据集的说明描述与图这间的空白间距
		protected float mMargin  = 10f;	
		//数据集的说明描述画笔
		private Paint mKeyPaint = null;
					
		//是否显示图例
		private boolean mVisible = false;
		
		//图例起始偏移多少距离
		protected float mOffsetX = 0.0f;
		protected float mOffsetY = 0.0f;
		//行间距
		protected float mRowSpan = 10.0f;		
		protected float mColSpan = 10.0f;		
		
		//图例方向
		/*
		private XEnum.LegendType mLegendType = XEnum.LegendType.COLUMN;		
		private XEnum.HorizontalAlign mHorizontalAlign = XEnum.HorizontalAlign.RIGHT;		
		private XEnum.VerticalAlign mVerticalAlign = XEnum.VerticalAlign.MIDDLE;
		 */	
		private XEnum.LegendType mLegendType = XEnum.LegendType.ROW;		
		private XEnum.HorizontalAlign mHorizontalAlign = XEnum.HorizontalAlign.LEFT;
		private XEnum.VerticalAlign mVerticalAlign = XEnum.VerticalAlign.TOP;
	
		//box
		protected BorderRender mBorder = new BorderRender();
		protected boolean mShowBox = true;
		protected boolean mShowBoxBorder = true;
		protected boolean mShowBackground = true;
				
		public PlotLegend() {}

		/**
		 * 在图的上方显示图例
		 * 
		 */
		public void show()
		{
			mVisible = true;
		}
		
		/**
		 * 在图的上方不显示图例
		 */
		public void hide()
		{
			mVisible = false;
			if(null != mKeyPaint) mKeyPaint = null;
		}
						
		/**
		 * 是否需绘制图的图例
		 * @return 是否显示
		 */
		public boolean isShow()
		{
			return mVisible;
		}
		
		/**
		 * 不显示图例框		
		 */
		public void hideBox()
		{
			mShowBox = false;
		}
		
		/**
		 * 不显示图例边框		
		 */
		public void hideBorder()
		{
			mShowBoxBorder = false;
		}
		
		/**
		 * 不显示图例背景	
		 */
		public void hideBackground()
		{
			mShowBackground = false;
		}
		
		/**
		 * 显示图例框		
		 */
		public void showBox()
		{
			mShowBox = true;
			showBorder();
			showBackground();
		}
		
		/**
		 * 显示图例边框		
		 */
		public void showBorder()
		{
			mShowBoxBorder = true;
		}
		
		/**
		 * 显示图背景		
		 */
		public void showBackground()
		{
			mShowBackground = true;
		}
		
		 
		 /**
		  * 开放图例绘制画笔
		  * @return 画笔
		  */
		 public Paint getPaint()
		 {		 
			 if(null == mKeyPaint)
			 {
				mKeyPaint = new Paint();
				mKeyPaint.setColor(Color.BLACK);
				mKeyPaint.setAntiAlias(true);			
				mKeyPaint.setTextSize(15);	
			 }
			 return mKeyPaint;
		 }
		 
		 /**
		  * 设置图例间距
		  * @param margin Key间距
		  */
		 public void setLabelMargin(float margin)
		 {		 
			 mMargin = margin;
		 }
		 
		 
		 /**
		 * 设置行间距
		 * @param span 间距
		 */
		public void setRowSpan(float span)
		{
			mRowSpan = span;		
		}
		
		public void setColSpan(float span)
		{
			mColSpan = span;
		}
			
		 /**
		  * 返回图例间距
		  * @return Key间距
		  */
		 public float getLabelMargin()
		 {
			 return mMargin;
		 }
		 
		 /**
		  * 图例起始向X方向偏移多少距离
		  * @param offset 偏移值
		  */
		 public void setOffsetX(float offset)
		 {		 
			 mOffsetX = offset;
		 }
		 
		 /**
		  * 图例起始向Y方向偏移多少距离
		  * @param offset 偏移值
		  */
		 public void setOffsetY(float offset)
		 {		 
			 mOffsetY = offset;
		 }
		 
		 /**
		  * 图例显示类型:使用行类型横向显示，或使用列类型竖向显示 
		  * @param type 显示类型
		  */
		 public void setType(XEnum.LegendType type)
		 {
			 mLegendType = type;
		 }
		 
		 /**
		  * 返回图例显示类型
		  * @return 显示类型
		  */
		 public XEnum.LegendType getType()
		 {
			 return mLegendType;
		 }
		 		 
		 /**
		  * 设置横向显示方式位置
		  * @param align 位置
		  */
		 public void setHorizontalAlign(XEnum.HorizontalAlign align)
		 {
			 mHorizontalAlign = align;
		 }
		 
		 /**
		  * 返回横向显示方式位置
		  * @return	位置
		  */
		 public XEnum.HorizontalAlign getHorizontalAlign()
		 {
			 return mHorizontalAlign;
		 }		 
		 
		 /**
		  * 设置竖向显示方式位置
		  * @param align 位置
		  */
		 public void setVerticalAlign(XEnum.VerticalAlign align)
		 {
			 mVerticalAlign = align;
		 }
		 
		 /**
		  * 设置竖向显示方式位置
		  * @return	位置
		  */
		 public XEnum.VerticalAlign getVerticalAlign()
		 {
			 return mVerticalAlign;
		 }
		 
		
		 /**
		  * 开放图例框绘制基类
		  * @return  框绘制类
		  */
		 public Border getBox()
		 {		
			 return mBorder;
		 }
		 
		 
} public class PlotLegendRender extends PlotLegend{
	
	//private static final String TAG = "PlotLegendRender";
	
	private PlotArea mPlotArea = null;
	private XChart mXChart = null;

	private float mKeyLabelX = 0.0f;
	private float mKeyLabelY = 0.0f;

	/////////////////////////////////////
	
	private ArrayList<PlotDot> mLstDotStyle = null;
	private ArrayList<String> mLstKey = null;
	private ArrayList<Integer> mLstColor = null;
	
	private float mRectWidth = 0.0f;
	private float mRectHeight = 0.0f;
	
	LinkedHashMap<Integer,Integer> mMapID = new LinkedHashMap<Integer,Integer>();
	
	private boolean mIsLnChart = false;
	private Paint mPaintLine = null;
	
	enum EnumChartType{AXIS,CIR,LN,RD};	
	EnumChartType mType = EnumChartType.AXIS;
	
	//此处的5.f相当于this.getBox().getLinePaint()的高度	
	private final int BOX_LINE_SIZE = 5;	
	
	///////////////////////////////////
	public PlotLegendRender()
	{
	}
		
	public PlotLegendRender(XChart xChart)
	{
		mXChart = xChart;		
	}
		
	public void setXChart(XChart xChart)
	{
		mXChart = xChart;
	}	
	
	private void initEnv()
	{
		mKeyLabelX = mKeyLabelY = 0.0f;
		mRectWidth = mRectHeight = 0.0f;			
	}
					
	private float getLabelTextWidth(String key)
	{
		return  DrawHelper.getInstance().getTextWidth(getPaint(),key );
	}
	
	private float getLabelTextHeight()
	{
		return DrawHelper.getInstance().getPaintFontHeight(getPaint());
	}		
	
	///////////////////////////////
	
	// 1. 转成arraylist,convertArray
	// 2. calcRect
	// 3. calcStartXY
	// 4. drawLegend
	
	public boolean renderBarKey(Canvas canvas,List<BarData> dataSet) {
		if (isShow() == false) return false;	
		refreshLst();
		convertArrayBarKey(dataSet);
		render(canvas);
		
		return true;
	}
	
	public void renderLineKey(Canvas canvas, List<LnData> dataSet) {	
		if (isShow() == false) return;	
		
		setLnChartStatus();
		refreshLst();
		convertArrayLineKey(dataSet);
		render(canvas);
	}
	
	
	public void renderPieKey(Canvas canvas,List<PieData> dataSet)
	{		
		if (isShow() == false) return;	
		refreshLst();
		mType = EnumChartType.CIR;
		convertArrayPieKey(dataSet);
		render(canvas);
	}
	
	public void renderRdKey(Canvas canvas,List<RadarData> dataSet)
	{
		if (isShow() == false) return;	
		
		setLnChartStatus();
		refreshLst();
		convertArrayRadarKey(dataSet);
		render(canvas);
	}
	
	public void renderPointKey(Canvas canvas, List<ScatterData> dataSet) 
	{
		if (isShow() == false) return;		
		refreshLst();
		convertArrayPointKey(dataSet);
		render(canvas);
	}
				
	public void renderBubbleKey(Canvas canvas, List<BubbleData> dataSet) 
	{
		if (isShow() == false) return;	
		refreshLst();
		convertArrayBubbleKey(dataSet);
		render(canvas);
	}
	
	public void renderRoundBarKey(Canvas canvas,List<ArcLineData> dataSet)
	{
		if (isShow() == false) return;	
		refreshLst();
		convertArrayArcLineKey(dataSet);
		render(canvas);
	}
	
	public void renderRangeBarKey(Canvas canvas,String key,int textColor)
	{		
		if (isShow() == false) return;	
		if("" == key||key.length() == 0) return;	
		
		refreshLst();
									
		mLstKey.add(key);
		mLstColor.add(textColor);		
		PlotDot pDot = new PlotDot();
		pDot.setDotStyle(XEnum.DotStyle.RECT);
		mLstDotStyle.add(pDot);
		
		render(canvas);		
	}
	
	
	private void setLnChartStatus()
	{
		if(null == mPaintLine)mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.mPaintLine.setStrokeWidth(2);
		mIsLnChart = true;
	}
	
	
	private void render(Canvas canvas)
	{
		if(null == mXChart) return;	
		if(null == mPlotArea) mPlotArea = mXChart.getPlotArea();
		calcContentRect();		
		getStartXY();
		drawLegend(canvas);		
	}
	
	private float getRectWidth()
	{
		float rectWidth = 0.0f;
		float textHeight = getLabelTextHeight();
		
		if( mIsLnChart)
		{
			rectWidth = 2 * textHeight;
		}else{
			rectWidth = textHeight/2 + textHeight;
		}
		return rectWidth;
	}
	
	private void calcContentRect()
	{
		int countDots = (null != mLstDotStyle)? mLstDotStyle.size():0 ;	
		int countText = (null != mLstKey)?mLstKey.size():0;
		if(0 == countText && 0 == countDots ) return;
		//int count = (countText > countDots)?countText:countDots;
															
		String text = "";
		float textHeight = getLabelTextHeight();
										
		int row = 1;
		mMapID.clear();
		
		float areaWidth = mPlotArea.getWidth() - 2 * mMargin;
		float rectWidth = getRectWidth();
		
		float rowWidth = 0.0f;	
		float rowHeight = textHeight;	
		float maxHeight = rowHeight;
		float maxWidth = 0.0f;					
		
		for(int i=0;i<countText;i++)
		{									
			if(countDots > i) 
			{
				PlotDot plot = mLstDotStyle.get(i);		
				if(mIsLnChart)
				{
					rowWidth += rectWidth + mColSpan;	
				}else{
					if( plot.getDotStyle() !=  XEnum.DotStyle.HIDE )		
										rowWidth += rectWidth + mColSpan;				
				}
			}			
			
			text = mLstKey.get(i);				
			float labelWidth = getLabelTextWidth( text);
			rowWidth += labelWidth;
			
			switch(getType())
			{
				case ROW:					
						if(Float.compare(rowWidth , areaWidth) == 1)
						{	//换行			
							rowWidth = rectWidth + mColSpan +labelWidth;
							maxHeight += rowHeight + mRowSpan;							
							row++;													
						}else{			
							rowWidth += mColSpan;
							if(Float.compare(rowWidth, maxWidth) == 1) maxWidth = rowWidth;														
						}				
					break;
				case COLUMN:						
						if(Float.compare(rowWidth, maxWidth) == 1)maxWidth = rowWidth;		
						maxHeight += rowHeight + mRowSpan;	
						
						rowWidth = 0.0f;
						row++;
						break;
				 default:
					 break;
			}	
						
			mMapID.put(i,row);
		}			
	
		mRectWidth = maxWidth +  2 * mMargin;
		mRectHeight = maxHeight +  2 * mMargin ;	
		
		if(XEnum.LegendType.COLUMN == getType() ) mRectHeight -= 2 * mRowSpan;
	}
	
	
	private void getStartXY()
	{
		float mBoxLineSize = BOX_LINE_SIZE;
		if(!this.mShowBox) mBoxLineSize = 0.0f;
		
		switch(getHorizontalAlign())
		{
			case LEFT:
				if(EnumChartType.CIR == mType)
				{
					mKeyLabelX = mXChart.getLeft() + mOffsetX ;
				}else{
					mKeyLabelX = mPlotArea.getLeft() + mOffsetX ;
				}
				
				mKeyLabelX += mBoxLineSize;
				break;
			case CENTER:				
					mKeyLabelX = this.mXChart.getLeft() + 
							(mXChart.getWidth()- mRectWidth) / 2 + mOffsetX ;					
				break;
			case RIGHT:
				if(EnumChartType.CIR == mType)
				{
					mKeyLabelX = mXChart.getRight() - mOffsetX - mRectWidth;
				}else{
					mKeyLabelX = mPlotArea.getRight() - mOffsetX - mRectWidth;
				}
				mKeyLabelX -= mBoxLineSize;
				break;
			default:
				break;
		}
				
	
		switch(getVerticalAlign())
		{
			case TOP:
				
				if(XEnum.LegendType.COLUMN == getType())
				{
					mKeyLabelY = mPlotArea.getTop()  + mOffsetY;
					mKeyLabelY += mBoxLineSize;
				}else{
					mKeyLabelY = mPlotArea.getTop() -  mRectHeight - mOffsetY;	
					mKeyLabelY -= mBoxLineSize;
				}
				
				break;
			case MIDDLE:						
				mKeyLabelY = mPlotArea.getTop() + ( mPlotArea.getHeight() - mRectHeight) /2;
				break;
			case BOTTOM:
				
				if(XEnum.LegendType.COLUMN == getType())
				{
					mKeyLabelY = mXChart.getBottom() + mOffsetY;				
					mKeyLabelY += mXChart.getBorderWidth();	
					
					mKeyLabelY += mBoxLineSize;					
				}else{
					mKeyLabelY = mXChart.getBottom() - mRectHeight - mOffsetY;				
					mKeyLabelY -= mXChart.getBorderWidth();	
					
					mKeyLabelY -= mBoxLineSize;
				}								
				break;
			default:
				break;
		}	
				
	}
		
	
	private void drawLegend(Canvas canvas)
	{			
		int countDots = (null != mLstDotStyle)? mLstDotStyle.size():0 ;	
		int countText = (null != mLstKey)?mLstKey.size():0;
		if(0 == countText && 0 == countDots ) return;
		int countColor = (null != mLstColor)? mLstColor.size():0 ;
							
		float currDotsX = mKeyLabelX + mMargin ;		
		float currRowX = currDotsX;
		float currRowY = mKeyLabelY + mMargin;	
		
		float textHeight = getLabelTextHeight();
		float rowHeight = textHeight;
		float rectWidth = getRectWidth(); //2 * textHeight;		
		
		int currRowID = 0;
		Iterator iter = this.mMapID.entrySet().iterator();		
		
		//背景
		drawBox(canvas);	
			
		//图例
		while(iter.hasNext()){
			    Entry  entry=(Entry)iter.next();
			
			    Integer id =(Integer) entry.getKey();
			    Integer row =(Integer) entry.getValue();//行号
			    
			    if(row > currRowID) //换行
			    {
			    	if(0 < currRowID)currRowY += rowHeight + mRowSpan;				    		    
			    	currRowX = mKeyLabelX + mMargin;	
			    	currRowID = row;
			    }
			    
			    //颜色
			    if(countColor > id)
			    {
			    	this.getPaint().setColor(mLstColor.get(id));			    	
			    	if( mIsLnChart)mPaintLine.setColor(mLstColor.get(id));
			    }else{
			    	this.getPaint().setColor(Color.BLACK);
			    	if( mIsLnChart)mPaintLine.setColor(Color.BLACK);
			    }			    
			   	
			    if(countDots > id)
				{			    				    	
					PlotDot plot = mLstDotStyle.get(id);		
					
					if( mIsLnChart) //line
					{																			
						canvas.drawLine(currRowX            , currRowY + rowHeight/2, 
								        currRowX + rectWidth, currRowY + rowHeight/2,  
								        this.mPaintLine);
						
						PlotDotRender.getInstance().renderDot(canvas,plot, 
								currRowX + rectWidth/2,
								currRowY + rowHeight/2,
								this.getPaint());
						currRowX += rectWidth + mColSpan;	
						
					}else{
						if( plot.getDotStyle() !=  XEnum.DotStyle.HIDE )
						{		
							PlotDotRender.getInstance().renderDot(canvas,plot, 
									currRowX + rectWidth/2,
									currRowY + rowHeight/2 , 
									this.getPaint());																				
							currRowX += rectWidth + mColSpan;															
						}
					}
				}
			    String label = mLstKey.get(id);
			    if("" != label)
			    	canvas.drawText(label,currRowX , currRowY + rowHeight,this.getPaint());		
			    			    
			    currRowX += this.getLabelTextWidth(label);			
			    currRowX += mColSpan;				  
		}
		
		mMapID.clear();
		clearLst();
	}
	
	private void clearLst()
	{
		if(null != mLstDotStyle)
		{
			mLstDotStyle.clear();
			mLstDotStyle = null;
		}
		if(null != mLstKey)
		{
			mLstKey.clear();
			mLstKey = null;
		}
		if(null != mLstColor)
		{
			mLstColor.clear();
			mLstColor = null;
		}
	}
	

	private void drawBox(Canvas canvas)
	{				
		if(!mShowBox)return;
		
		RectF rect = new RectF();	
		rect.left = mKeyLabelX ;
		rect.right = mKeyLabelX + mRectWidth;
		rect.top = mKeyLabelY;
		rect.bottom = mKeyLabelY + mRectHeight;	
				
		mBorder.renderRect(canvas, rect,mShowBoxBorder,mShowBackground);			
	}
		
	private void refreshLst()
	{
		initEnv();
		
		if(null == mLstKey)
			mLstKey = new ArrayList<String>();
		else
			mLstKey.clear();
			
		if(null == mLstDotStyle)
			mLstDotStyle = new ArrayList<PlotDot>();
		else
			mLstDotStyle.clear();
		
		if(null == mLstColor)
			mLstColor = new ArrayList<Integer>();
		else
			mLstColor.clear();		
	}
	

	////////////////////////////////

	private void convertArrayLineKey(List<LnData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for (LnData cData : dataSet) {
			key = cData.getLineKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getLineColor());
			mLstDotStyle.add(cData.getPlotLine().getPlotDot());
		}
	}
	
	private void convertArrayBarKey(List<BarData> dataSet)
	{
		if(null == dataSet) return;
				
		String key = "";
		for (BarData cData : dataSet) {
			key = cData.getKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getColor());
			
			PlotDot dot = new PlotDot();
			dot.setDotStyle(XEnum.DotStyle.RECT);
			mLstDotStyle.add(dot);			
		}
	}
	
	
	private void convertArrayPieKey(List<PieData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for(PieData cData : dataSet){
			key = cData.getKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getSliceColor());
			
			PlotDot dot = new PlotDot();
			dot.setDotStyle(XEnum.DotStyle.RECT);
			mLstDotStyle.add(dot);
		}
	}
	
	private void convertArrayRadarKey(List<RadarData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for(RadarData cData : dataSet){
			key = cData.getLineKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getLineColor());			
			mLstDotStyle.add(cData.getPlotLine().getPlotDot());
		}
	}
	

	private void convertArrayPointKey(List<ScatterData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for (ScatterData cData : dataSet) {
			key = cData.getKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getPlotDot().getColor());
			mLstDotStyle.add(cData.getPlotDot());
		}
	}
	
	private void convertArrayBubbleKey(List<BubbleData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for (BubbleData cData : dataSet) {
			key = cData.getKey();				
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getColor());
			
			PlotDot pDot = new PlotDot();
			pDot.setDotStyle(XEnum.DotStyle.DOT);
			mLstDotStyle.add(pDot);
		}
	}
		
	private void convertArrayArcLineKey(List<ArcLineData> dataSet)
	{
		if(null == dataSet) return;
		
		String key = "";
		for (ArcLineData cData : dataSet) {
			key = cData.getKey();	
			if(!isDrawKey(key))continue;
			if("" == key)continue;
			
			mLstKey.add(key);
			mLstColor.add(cData.getBarColor());
			
			PlotDot pDot = new PlotDot();
			pDot.setDotStyle(XEnum.DotStyle.RECT);
			mLstDotStyle.add(pDot);
		}
	}
	
	private boolean isDrawKey(String key)
	{
		if("" == key||key.length() == 0) return false;
		return true;
	}
	
	////////////////////////////////
} public class PlotTitle {	

	//图表标题文字
	private  String mChartTitle = "";
	private  String mSubtitle = "";	
	//图表标题画笔
	private Paint mPaintTitle = null;
	private Paint mPaintSubtitle = null;	
	//图表标题显示位置
	private XEnum.HorizontalAlign mChartTitleAlign = XEnum.HorizontalAlign.CENTER;	
	//标题的显示位置(TOP,CENTER,BOTTOM)即是否靠最上面，
	//还是Chart top与Plot top的中间位置，还是PLOT TOP的位置
	private XEnum.VerticalAlign mTitlePosition = XEnum.VerticalAlign.MIDDLE;
	
	public PlotTitle()
	{
	}

	/**
	 * 设置标题
	 * @param title 标题内容
	 */
	public void setTitle(String title)
	{
		mChartTitle = title;		
	}
	
	/**
	 * 返回标题
	 * @return 标题
	 */
	public String getTitle()
	{
		return mChartTitle;
	}
	
	
	/**
	 * 设置子标题
	 * @param subtitle 子标题
	 */
	public void setSubtitle(String subtitle)
	{
		mSubtitle = subtitle;					
	}
	
	/**
	 * 返回子标题
	 * @return 子标题
	 */
	public String getSubtitle()
	{
		return mSubtitle;
	}
	 
	
	/**
	 * 开放标题画笔
	 * @return 画笔
	 */
	public Paint getTitlePaint()
	 {
		
		if(null == mPaintTitle)
		{
			mPaintTitle  = new Paint();				
			mPaintTitle.setTextSize(32);				
			mPaintTitle.setColor(Color.BLACK);				
			mPaintTitle.setAntiAlias(true);
		}
		
		 return mPaintTitle ;
	 }

	
	/**
	 * 开放子标题画笔
	 * @return 画笔
	 */
	public Paint getSubtitlePaint()
	 {
		if(null == mPaintSubtitle)
		{
			mPaintSubtitle  = new Paint();
			mPaintSubtitle.setTextSize(22);
			mPaintSubtitle.setColor(Color.BLACK);	
			mPaintSubtitle.setAntiAlias(true);	
		}
		 return mPaintSubtitle ;
	 }
			
	/**
	 * 设置标题横向显示位置(靠左，居中，靠右)
	 * @param align 横向显示位置
	 */
	public void setTitleAlign(XEnum.HorizontalAlign align)
	{
		mChartTitleAlign = align;
	}
		
	/**
	 * 返回标题横向显示位置
	 * @return 横向显示位置
	 */
	public XEnum.HorizontalAlign getTitleAlign()
	{
		return mChartTitleAlign;
	}
	
	/**
	 * 设置标题上下显示位置,即图上边距与绘图区间哪个位置(靠上，居中，靠下).
	 * @param Position  上下显示位置
	 */
	public void setVerticalAlign(XEnum.VerticalAlign Position)
	{
		mTitlePosition = Position;
	}
		
	/**
	 * 设置标题上下显示位置
	 * @return 上下显示位置
	 */
	public XEnum.VerticalAlign getVerticalAlign()
	{
		return mTitlePosition;
	}
	
	
} public class PlotTitleRender extends PlotTitle{
	
	
	//protected static final int mBorderSpadding = 5;

	public PlotTitleRender()
	{
			
	}
	
	/**
	 * 绘制标题
	 */
	public void renderTitle(float chartLeft,
							float chartRight,
							float chartTop,
							float chartWidth,
							float plotTop,
							Canvas canvas)
	{
		//排除掉border width
	
		String title = getTitle();
		String subTitle = getSubtitle();
		
		float titleHeight = 0.f;
		float subtitleHeight = 0.f;
		float totalHeight = 0.f;
		
		float titleInitY = 0.0f;
		
		float titleX = 0.0f;
		float titleY = 0.0f;
		
		float subtitleX = 0.0f;
		float subtitleY = 0.0f;
		
		if(title.length() == 0 && subTitle.length() == 0) return;	

		if(title.length() > 0 )
		{
			 titleHeight = DrawHelper.getInstance().getPaintFontHeight(getTitlePaint());			
		}
		if(title.length() > 0 )
		{
			subtitleHeight = DrawHelper.getInstance().getPaintFontHeight(getSubtitlePaint());
		}			
		totalHeight = titleHeight + subtitleHeight;	
		float pcHeight = Math.abs(plotTop - chartTop) ;		
		
		//用来确定 titleY,需要Chart top的值
		switch(this.getVerticalAlign())
		{
		case TOP:			
			titleInitY = chartTop + titleHeight;
			break;
		case MIDDLE:			
			titleInitY = Math.round(chartTop + pcHeight/2 - totalHeight/2);			
			break;
		case BOTTOM:
			titleInitY = plotTop - titleHeight;			
			break;
		}
		
		
		switch(this.getTitleAlign())
		{
		case LEFT:
			titleX = chartLeft;
			titleY = titleInitY;
			
			subtitleX = chartLeft;
			subtitleY = titleY + subtitleHeight;
			
			getTitlePaint().setTextAlign(Align.LEFT);			
			getSubtitlePaint().setTextAlign(Align.LEFT);			
			break;
		case CENTER:
			
			titleX = Math.round(chartLeft + chartWidth / 2);
			titleY = titleInitY;
						
			getTitlePaint().setTextAlign(Align.CENTER);			
			getSubtitlePaint().setTextAlign(Align.CENTER);	
			break;
		case RIGHT:
			
			titleX = chartRight;
			titleY = titleInitY;
									
			getTitlePaint().setTextAlign(Align.RIGHT);			
			getSubtitlePaint().setTextAlign(Align.RIGHT);								
			break;
		}
	
		subtitleY = DrawHelper.getInstance().drawText(canvas, this.getTitlePaint(), title, titleX, titleY);		
		subtitleX = titleX;
		subtitleY = titleY + subtitleHeight;
		
		DrawHelper.getInstance().drawText(canvas, this.getSubtitlePaint(), subTitle, subtitleX, subtitleY);
		
	}
}
import java.util.List;
import org.xclcharts.common.MathHelper;
import org.xclcharts.renderer.info.AnchorDataPoint;
import org.xclcharts.renderer.info.AnchorRender;
import org.xclcharts.renderer.info.DyLine;
import org.xclcharts.renderer.info.DyLineRender;
import org.xclcharts.renderer.info.Legend;
import org.xclcharts.renderer.info.LegendRender;
import org.xclcharts.renderer.plot.Border;
import org.xclcharts.renderer.plot.BorderRender;
import org.xclcharts.renderer.plot.PlotArea;
import org.xclcharts.renderer.plot.PlotAreaRender;
import org.xclcharts.renderer.plot.PlotGrid;
import org.xclcharts.renderer.plot.PlotGridRender;
import org.xclcharts.renderer.plot.PlotLegend;
import org.xclcharts.renderer.plot.PlotLegendRender;
import org.xclcharts.renderer.plot.PlotTitle;
import org.xclcharts.renderer.plot.PlotTitleRender;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Shader;
/**
 * Copyright 2014  XCL-Charts
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 	
 * @Project XCL-Charts 
 * @Description Android图表基类库
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 * @license http://www.apache.org/licenses/  Apache v2 License
 * @version 1.0
 */

/**
 *  version	 	date
 *  0.1 		2014-06-12
 *  1.0 		2014-07-04
 *  1.2			2014-07-13
 */

package org.xclcharts.renderer;

/**
 * @ClassName XChart
 * @Description 所有图表类的基类,定义了图表区，标题，背景等
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 * 
 */




public class XChart implements IRender {
		
	//private static final String TAG = "XChart";
	// 开放主图表区
	protected PlotAreaRender plotArea = null;
	// 开放主图表区网格
	protected PlotGridRender plotGrid = null;
	// 标题栏
	private PlotTitleRender plotTitle = null;
	// 图大小范围
	private float mLeft = 0.0f;
	private float mTop = 0.0f;
	private float mRight = 0.0f;
	private float mBottom = 0.0f; //5f;
	// 图宽高
	private float mWidth = 0.0f;
	private float mHeight = 0.0f;

	// 图的内边距属性
	private float mPaddingTop = 0.f;
	private float mPaddingBottom = 0.f;
	private float mPaddingLeft = 0.f;
	private float mPaddingRight = 0.f;
	// 是否画背景色
	private boolean mBackgroundColorVisible = false;
	
	//坐标系原点坐标
	protected float[] mTranslateXY = new float[2];		
		
	//是否显示边框
	private boolean mShowBorder = false;
	private BorderRender mBorder = null;
	
	//图例类
	protected PlotLegendRender plotLegend = null;