今天有一个任务,在学生教育系统的客户端打开的页面实现一个雷达图,将雷达图的数据分成语文、数学、外语、文科、理科和其他。
效果图是这样
于是我就开始了思考,为了这个自定义的view组件可以在以后进行复用,所以我增加了可变的成员变量count,代表要表示的项的总数。
根据雷达图的样式,可以获得大概的绘制步骤
- 雷达图的形状实质是一个正n边形,确定正n边形的顶点坐标,需要确定这个正n边形的外接圆。如图所示
如图分析,设多边形为n边形,顺时针算起每个顶点的角度为 360 / n * i,外接圆的半径为r,则根据左上角坐标(0,0)可得圆心坐标为(r,r),由此可算出各个顶点的坐标。
根据分析则可以进行如下步骤的编码:
定义类RadoView.java
代码如下;
public class RadoView extends View {
private int count = 6; //多边形的变数
private int[] radius = new int[]{
100, 200, 300, 400, 500}; //各个外接圆的变数
private int maxRadius = radius[radius.length - 1];
private int[] marks = new int[count];
private String[] keys = new String[count];
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
private Paint paintLine; //画线
private Paint paintMarkLine; //分值连线
private Paint paintMarkPoint; //分值画点
private Paint paintText; //绘制文字
private double x; //当前点的横坐标
private double y; //当前点的纵坐标
private double lastX; //上一次的坐标
private double lastY;
public RadoView(Context context) {
super(context);
}
public RadoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RadoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
根据分析图可以发现,根据三角函数计算坐标的角度并非是360 / n,而是构造直角三角形根据三角函数计算
写一个方法计算这个角度
/**
* 得到需要计算的角度
*
* @param angle 角度,例:30.60.90
* @return res
*/
private double getNewAngle(double angle) {
double res = angle;
if (angle >= 0 && angle <= 90) {
res = 90 - angle;
} else if (angle > 90 && angle <= 180) {
res = angle - 90;
} else if (angle > 180 && angle <= 270) {
res = 270 - angle;
} else if (angle > 270 && angle <= 360) {
res = angle - 270;
}
return res;
}
算出角度后,应该计算出每个角度的所在象限
注意,这个角度的所在象限是根据外接圆的圆心来判断的,以6边形为例子,每个角的度数分别是30,60,90,120….,30和60度的顶点所在的象限为第一象限,120度所在为第二象限,以此类推
编写函数int getQr(double),计算所在象限
private int getQr(double angle) {
int res = 0;
if (angle >= 0 && angle <= 90) {
res = 1;
} else if (angle > 90 && angle <= 180) {
res = 2;
} else if (angle > 180 && angle <= 270) {
res = 3;
} else if (angle > 270 && angle <= 360) {
res = 4;
}
return res;
}
此时根据点的象限和角度,便可以计算出顶点的x坐标和y坐标
角度在1,2象限的时候,横坐标为一个半径加上这个顶点在第二象限部分的横坐标,这个横坐标可以根据构造直角三角形,使用三角函数计算得出
private double getPointX(double angle, double radius) {
double newAngle = getNewAngle(angle);
double res = 0;
double width = radius * Math.cos(newAngle / 180 * Math.PI);
int qr = getQr(angle);
switch (qr) {
case 1:
case 2:
res = maxRadius + width;
break;
case 3:
case 4:
res =