/**风向玫瑰图绘制Demo,默认使用16个风向
* Created by yang_lei 2017/3/9.
*/
public class RoseChart extends View {
//图标尺寸
private int chart_size;
private static Context context;
//传入参数(各个风向百分比)
private List<Float> percentageList;
//风向标签
private final String arrPerLabel[] = new String[]{"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
public RoseChart(Context context, AttributeSet attrs) {
this(context, attrs, 0, null);
}
public RoseChart(Context context) {
this(context, null);
}
/**(默认顺时针方向 N-->NNE-->NE-->ENE-->E.....)
* @param context
* @param attrs
* @param defStyle
* @param percentageList 风向百分比(默认顺时针方向从正北开始 N-->NNE-->NE-->ENE-->E.....两个方向之间数据不可缺省,数据末尾可以缺省)
*/
public RoseChart(Context context, AttributeSet attrs, int defStyle, List<Float> percentageList) {
super(context, attrs, defStyle);
//初始化 风向百分比 集合
this.percentageList = percentageList;
this.context = context;
/**
* 获得我们所定义的自定义样式属性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoseChart, defStyle, 0);
chart_size = a.getDimensionPixelSize(R.styleable.RoseChart_chart_size, 0);
a.recycle();
}
@Override
public void onDraw(Canvas canvas) {
//画布背景
canvas.drawColor(getResources().getColor(R.color.blue1));
float cirX = getWidth() / 2;
float cirY = getHeight() / 2;
//计算绘制区域半径
float radius = (float) (getHeight() * 0.42);//150;
float arcLeft = cirX - radius;
float arcTop = cirY - radius;
float arcRight = cirX + radius;
float arcBottom = cirY + radius;
RectF arcRF0 = new RectF(arcLeft, arcTop, arcRight, arcBottom);
//画笔初始化
Paint PaintArc = new Paint();
Paint PaintLabel = new Paint();//汉字标识
PaintLabel.setColor(Color.WHITE);
PaintLabel.setAntiAlias(true);
PaintArc.setAntiAlias(true);
//位置计算类
XChartCalc xcalc = new XChartCalc();
float Percentage = 0.0f;
float CurrPer = 0.0f;//绘制 扇形区域 当前起始角度
float CurrPerLabel = 0.0f;//绘制 风向标识 当前起始角度
float NewRaidus = 0.0f;
//计算每个扇区的圆心角度数
// Percentage = 360 / arrPerLabel.length;
// Percentage = (float) (Math.round(Percentage * 100)) / 100;
Percentage = (float) round(360.00 / arrPerLabel.length, 2);
//计算起始扇形区域角度(默认顺时针方向 N-->NNE-->NE-->ENE-->E.....填充扇区)
CurrPer -= (float) round((Percentage - 4) / 2,2);
CurrPerLabel -= (float) round((Percentage - 4) / 2,2);
//绘制三个不同百分比同心圆
PaintLabel.setStyle(Paint.Style.STROKE);
PaintLabel.setStrokeCap(Paint.Cap.BUTT);
canvas.drawCircle(cirX, cirY, radius, PaintLabel);
canvas.drawCircle(cirX, cirY, (float) (radius * 0.75), PaintLabel);
canvas.drawCircle(cirX, cirY, (float) (radius * 0.5), PaintLabel);
canvas.drawCircle(cirX, cirY, (float) (radius * 0.25), PaintLabel);
//绘制三个不同百分比标识
//1,取出最大百分比
Float max = Collections.max(percentageList);
//绘制 风向 扇区
for (int i = 0; i < percentageList.size(); i++) {
//将百分比转换为新扇区的半径
if (percentageList.get(i) == max) {
NewRaidus = radius;
} else {
NewRaidus = radius * (percentageList.get(i) / max);
NewRaidus = (float) (Math.round(NewRaidus * 100)) / 100;
}
float NewarcLeft = cirX - NewRaidus;
float NewarcTop = cirY - NewRaidus;
float NewarcRight = cirX + NewRaidus;
float NewarcBottom = cirY + NewRaidus;
RectF NewarcRF = new RectF(NewarcLeft, NewarcTop, NewarcRight, NewarcBottom);
//分配颜色
// PaintArc.setARGB(255, arrColorRgb[i][0], arrColorRgb[i][1], arrColorRgb[i][2]);
PaintArc.setColor(getResources().getColor(R.color.yellow1));
PaintArc.setAlpha(200);
//在饼图中显示所占比例
canvas.drawArc(NewarcRF, CurrPer - 90, Percentage - 4, true, PaintArc);
//下次的起始角度
CurrPer += Percentage;
}
//2,计算每个同心圆半径所占百分比
float ThreePercentage = max / 4;
ThreePercentage = (float) (Math.round(ThreePercentage * 100)) / 100;
//3,绘制百分比标识
PaintLabel.setColor(getResources().getColor(R.color.red1));
PaintLabel.setTextSize(getResources().getDimension(R.dimen.RoseChart_persent));
PaintLabel.setFakeBoldText(true);
canvas.drawText(ThreePercentage + "%", cirX + (float) (radius * 0.18), cirY-18, PaintLabel);
canvas.drawText(ThreePercentage * 2 + "%", cirX + (float) (radius * 0.43), cirY-18, PaintLabel);
canvas.drawText(ThreePercentage * 3 + "%", cirX + (float) (radius * 0.68), cirY-18, PaintLabel);
canvas.drawText(ThreePercentage * 4 + "%", cirX + (float) (radius * 0.93), cirY-18, PaintLabel);
//绘制16个外圈风向标识
for (int j = 0; j < arrPerLabel.length; j++) {
//计算百分比标签
xcalc.CalcArcEndPointXY(cirX, cirY, radius, (float) (CurrPerLabel + (Percentage - 4) * 0.5));
//标识
PaintLabel.setColor(Color.WHITE);
PaintLabel.setTextSize(getResources().getDimension(R.dimen.RoseChart_direction));
PaintLabel.setStrokeWidth((float) 0.8);
canvas.drawText(arrPerLabel[j], xcalc.getPosX(), xcalc.getPosY(), PaintLabel);
//下次的起始角度
CurrPerLabel += Percentage;
}
PaintLabel.setColor(Color.BLACK);
canvas.drawText("author:Yang_lei", cirX - radius, cirY + radius+context.getResources().getDimension(R.dimen.RoseChart_distance4), PaintLabel);
}
public static class XChartCalc {
private static float x;
private static float y;
private static float r;
public static void CalcArcEndPointXY(float cirX, float cirY, float radius, float Percentage) {
double a = 2 * Math.PI * (Percentage / 360);
if (Percentage >= 0 && Percentage < 130) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance1);
} else if (Percentage >= 130 && Percentage < 180) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance2);
} else if (Percentage == 180) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance3);
} else if (Percentage > 180 && Percentage < 240) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance4);
} else if (Percentage > 240 && Percentage < 270) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance5);
} else if (Percentage == 270) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance6);
} else if (Percentage > 270 && Percentage < 300) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance5);
} else if (Percentage >= 300 && Percentage < 330) {
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance6);
} else if (Percentage >= 330 && Percentage < 350){
r = radius + context.getResources().getDimension(R.dimen.RoseChart_distance3);
}
y = cirY - (float) (r * (Math.cos(a)));
x = cirX + (float) (r * (Math.sin(a)));
}
public static float getPosX() {
return x;
}
public static float getPosY() {
return y;
}
}
/**返回指定小数位数
* @param v
* @param scale
* @return
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
<resources>
<dimen name="RoseChart_persent">10sp</dimen>
<dimen name="RoseChart_direction">8sp</dimen>
<dimen name="RoseChart_distance1">4dp</dimen>
<dimen name="RoseChart_distance2">8dp</dimen>
<dimen name="RoseChart_distance3">10dp</dimen>
<dimen name="RoseChart_distance4">16dp</dimen>
<dimen name="RoseChart_distance5">22dp</dimen>
<dimen name="RoseChart_distance6">12dp</dimen>
</resources>