Fork me on GitHub

用Java自制一张雷达图

前言

今天整理资料,看到了之前自己用Java画了张雷达图,遂又拿来研究了下,感觉比较好玩,特地分享一下。

众所周知,Java在绘制图像方面的能力是比较差(la)劲(ji)的。自带的主要的一些图像处理类有Java2D中绘图类Graphics,图像流处理类ImageIO等。

有一些基于Java的图像处理开源包也仅仅是对原图像进行缩放、变化、水印等操作,使用Java进行绘图的少之又少。

今天我们用Java自带的图像处理类(Graphics、ImageIO等)来绘制一张雷达图吧。

正文

为什么要画雷达图?而不是用Java绘制动漫人物?

咳咳……因为雷达图应用广泛(就不要为难Java画动漫人物了TAT)。

我们开始吧,先随便看一张雷达图。

可知其主要内容:

外层环、圆环数量、圆环半径、分类名称、各个部分的数值、各种颜色等等很多很多属性。

upload successful

这里,我们不妨绘制一个考试分数雷达图,这样更结合实际。

我们需要一个Java Bean,里面存放雷达图的一些属性参数。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* 雷达图数据bean
* @author zwt
* ------------------关于雷达图,以下的说明---------------------
* 默认圆环最大半径为200
* 生成的图片为 宽600*高700 默认
* 雷达图中心点的位置为 300,300 默认
* 线及文字大概占 600*100 默认
* 这些参数都可以调整,但调整后应尽量保证生成图的美观性
* -------------------------------------------------------------
*/
public class RadarMapInit {
// 圆环数量
private int cirNum=2;
// 圆的最大半径
private int r=200;
// 圆心坐标
private Point point=new Point(300,300);
// 圆环颜色
private Color cirColor=new Color(24,165,255);
// 射线起始角度 默认顺时针旋转
private float startAngle=-90;
// 射线颜色
private Color spoColor=new Color(0,0,255,100);
// 绘图参数g 画图时该参数不需要设置,设置了也没用
private Graphics2D g;
//填充色
private Color fillColor=new Color(146,199,234,200);
//中部文字颜色
private Color cenColor=Color.WHITE;
//中部文字
private String cenText;
//中部文字字体样式
private Font cenFont=new Font("宋体", Font.TYPE1_FONT, 50);
// 外围文字颜色
private Color outColor=Color.BLUE;
//外围文字样式 有默认值
private Font outFont=new Font("宋体", Font.TYPE1_FONT,12);
//生成图片路径 无默认值,必填
private String imgPath;
//生成图片格式 默认jpg 支持 jpg和png 其他格式没测
private String imgType="jpg";
//图片大小设置 宽 默认600*700 像素
private int picWidth=600;
//图片大小设置 高
private int picHeight=700;
//文字及线段的x方向距图片边的距离
private int shiftX=100;
//文字距雷达图y方向的距离
private int shiftY=100;
//生成的图片的背景颜色 默认白色
private Color picBackColor=Color.WHITE;

//又要开始添加参数了(⊙o⊙).....下面的主要是那一道线的参数
//线的最大值
private int lineMaxVal=1000;
//线的当前值
private int lineCurVal=-1;
//线的起始值
private int lineStaVal=0;
//线的已达到的颜色
private Color lineArrColor=new Color(24,165,255);
//线的未达到的颜色
private Color lineNotArrColor=Color.GRAY;
//线的粗细
private BasicStroke lineStroke=new BasicStroke(5.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER);
//下面的一般说明字体 一般说明文字写死吧,参数太多了,不想写了....
private Font genLineFont=new Font("宋体", Font.TYPE1_FONT,12);
//下面的特殊说明字体
private Font speLineFont=new Font("宋体", Font.TYPE1_FONT,25);
//特殊说明字体百分数
private String speLineValue;
//特殊说明自己文字
private String speLineText;
//一般说明字体颜色
private Color genTextColor=Color.BLACK;
//特殊说明字体颜色
private Color speTextColor=Color.BLUE;
......
//Get Set 及构造方法略
}

上面省略掉了get set和构造方法。

另外我里面还有一些参数设置没提到的,主要是用来展示效果让其更人性化应付客户使其更加满意)的,比如底部的分数击败直线,雷达图中央的分数显示等,一会儿大家可以看到效果。

参数很多,没办法……

对于每个分类,我们也新建一个属于它们的Java Bean,用来存储它们的属性。(PS:因为到底有多少分类是不确定的,故应该在画图时传入一个Bean List)。

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RadarMapData {
//数值
private String value;
//该维度数值最大值
private String maxValue;
//分组
private String group;
//文字
private String textValue;
//图片路径
private String picPath;
......
//Get Set 及构造方法略
}

同样省略了Get Set 和构造方法,我又增加了图片路径可以在分类的文字部分添加小图标,还可以对分类进行分组(比如数学是理科分组,语文英语是文科分组),可以说很Nice了以应对莫名其妙的需求)。

好了,开始使用我们的Graphics类进行绘图等操作了。

首先,这个关键类要使用我们刚才的那两个Bean,应该如下代码,同样Get,Set和构造方法略。

1
2
3
4
5
6
7
8
9
10
11
12
public class RadarMap {

// 日志记录
private Logger logger = LoggerFactory.getLogger(RadarMap.class);

// 数据集合
private List<RadarMapData> dataList;
// 初始化参数
private RadarMapInit init;
......
//Get Set 及构造方法略
}

开始绘制逻辑,首先有个画圆环方法,可以画出数个同心圆,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 画圆环
*
*/
private void drawCircles() {
Graphics2D g = init.getG();
// 根据圆心,半径,画出同心圆
g.setColor(init.getCirColor());
// 获取圆心
int x = init.getPoint().x;
int y = init.getPoint().y;
// 获取各个圆的直径并画圆环
for (int i = 1; i <= init.getCirNum(); i++) {
int d = 2 * i * init.getR() / init.getCirNum();
g.drawOval(x - d / 2, y - d / 2, d, d);
}
}

主要方法就是g.drawOval画圆,不在详细解释。

然后我们以圆心绘制分类的每条射线,同时拿到每个分类的最大数值和这个人的数值并标记,然后连接这个人的各个数值,并将这个多边形内部填充起来。

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* 以圆心画射线
*
*/
private void drawSpokes() {
Graphics2D g = init.getG();
Point point = init.getPoint();
// 解析数组
int num = dataList.size();
// 设置颜色
g.setColor(init.getSpoColor());
// 每个角度
float angle = init.getStartAngle();
float angleStep = 360 / num;

for (int i = 1; i <= num; i++) {
Point pt = getMappedPoint(init.getR(), angle, point);
g.drawLine(point.x, point.y, pt.x, pt.y);
addCirWordPic(dataList.get(i - 1).getTextValue(), pt, angle, dataList.get(i - 1).getPicPath());
g.setColor(init.getSpoColor());
angle += angleStep;
}

// 获取各个点的坐标
Polygon p = new Polygon();
g.setColor(init.getFillColor());
float angle1 = init.getStartAngle();
Point ptNext = new Point();
for (int i = 1; i <= num; i++) {
int myR = (int)(Double.parseDouble(dataList.get(i - 1).getValue())*(double)init.getR()/Double.parseDouble(dataList.get(i - 1).getMaxValue()));
Point pt = getMappedPoint(myR, angle1, point);
p.addPoint(pt.x, pt.y);
if (i < num) {
angle1 += angleStep;
int myRNext = (int)(Double.parseDouble(dataList.get(i).getValue())*(double)init.getR()/Double.parseDouble(dataList.get(i).getMaxValue()));
ptNext = getMappedPoint(myRNext, angle1, point);
} else {
angle1 += angleStep;
int myRNext = (int)(Double.parseDouble(dataList.get(0).getValue())*(double)init.getR()/Double.parseDouble(dataList.get(0).getMaxValue()));
ptNext = getMappedPoint(myRNext, angle1, point);
}
//g.drawLine(pt.x, pt.y, ptNext.x, ptNext.y);
}
g.drawPolygon(p);
g.fillPolygon(p);
}

这个方法首先解析分类数组,有几个就画几条射线(根据角度,这里逆时针旋转,起始角度-90,也就是从正上方开始旋转),从圆心与角度点之间画直线,并为这条直线的终点(角度点)添加文字和图片(分类文字及图片,方法addCirWordPic)。

完成后对于各个实际值点(实际分,比如语文100分,实际78分,78就是这儿的实际值),绘制成多边形。
(PS: Polygon p = new Polygon();绘制多边形,p.addPoint为多边形添加指定点,g.drawPolygon(p)为绘制多边形,g.fillPolygon(p)为多边形填充颜色)

上面方法调用了两个方法getMappedPoint和addCirWordPic,大家可以看下,分别为寻找绘图点方法和添加分类图片文字方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
* 根据点,角度,半径获取另一个点坐标
*
* @param r
* @param angle
* @param point
* @return
*/
private Point getMappedPoint(int r, float angle, Point point) {
// 计算坐标
Point pt = new Point();
pt.x = (int) (r * Math.cos(angle * Math.PI / 180) + point.x);
pt.y = (int) (r * Math.sin(angle * Math.PI / 180) + point.y);
return pt;
}

/**
* 添加圆外文字图片
*
* @param point
* 绘制起始点
* @param picValue
* 图片路径
*/
private void addCirWordPic(String wordValue, Point point, float angle, String picValue) {
Graphics2D g = init.getG();
double x = 0;
double y = 0;
double dx = 0;
double dy = 0;
if (wordValue == null || "".equals(wordValue)) {
logger.info(angle + "角度的点没有配置圆外文字");
Map<String, Double> map = setDxDy(angle, x, y, dx, dy);
dx = map.get("dx");
dy = map.get("dy");
} else {
FontRenderContext context = g.getFontRenderContext();
Font font = init.getOutFont();
g.setColor(init.getOutColor());
g.setFont(font);
Rectangle2D bounds = font.getStringBounds(wordValue, context);
x = (bounds.getWidth()) / 2;
y = (bounds.getHeight()) / 2;
Map<String, Double> map = setDxDy(angle, x, y, dx, dy);
dx = map.get("dx");
dy = map.get("dy");
g.drawString(wordValue, (int) (point.x + dx), (int) (point.y + dy));

}

if (picValue == null || "".equals(picValue)) {
logger.info(angle + "角度的点没有配置圆外图片");
return;
}

// 图片放到文字上面
ImageIcon imgIcon = new ImageIcon(picValue);
Image img = imgIcon.getImage();
g.drawImage(img, (int) (point.x + dx), (int) (point.y + dy - 5 * y), null);
}

/**
* 设置偏移量 圈外文字及图片使用
*
* @param dx
* @param dy
*/
private Map<String, Double> setDxDy(float angle, double x, double y, double dx, double dy) {
double cosVal = Math.cos(angle * Math.PI / 180);
double sinVal = Math.sin(angle * Math.PI / 180);
if (cosVal > 0 && sinVal > 0) {
dx = 5;
dy = 2 * y + 20; // 第一象限额外偏移15用于放置图片
} else if (cosVal > 0 && sinVal < 0) {
dx = 5;
dy = -5; // 第三象限
} else if (cosVal < 0 && sinVal > 0) {
dx = -2 * x - 5;
dy = 2 * y + 20; // 第二象限额外偏移15用于放置图片
} else if (cosVal < 0 && sinVal < 0) {
dx = -2 * x - 5;
dy = 5; // 第四象限
}
Map<String, Double> map = new HashMap<String, Double>();
map.put("dx", dx);
map.put("dy", dy);
return map;
}

绘制分类图片及文字时,由于要考虑文字大小,图片宽度等要求,故对图片及文字位置做了微调,会显得代码多些。

然后我们再对圆心加上一些文字,比如总分多少分什么的,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 添加圆心文字
*
*/
private void addWord() {
Graphics2D g = init.getG();
String value = init.getCenText();
if (value == null || "".equals(value)) {
logger.info("雷达图没有配置圆心文字,不添加圆心文字");
return;
}
FontRenderContext context = g.getFontRenderContext();
Font font = init.getCenFont();
g.setColor(init.getCenColor());
g.setFont(font);
Rectangle2D bounds = font.getStringBounds(value, context);
double x = (bounds.getWidth()) / 2;
double y = (bounds.getHeight()) / 2;
g.drawString(value, (int) (init.getPoint().x - x), (int) (init.getPoint().y + y - 10));
}

总的来说就是找到圆心位置,根据字体大小,对字体位置进行调整。

然后我们再来绘制下面的跑分直线部分,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 添加雷达图下面的线
*/
private void drawLineAndWord() {
int curVal=init.getLineCurVal();
//-1为开始设置的值,默认为没有填写,直接跳过线条打印
if(curVal==-1) {
return;
}
int staVal=init.getLineStaVal();
int maxVal=init.getLineMaxVal();
Graphics2D g = init.getG();
int width=init.getPicWidth();
//图片定的为 600*700 目前 雷达图占地 500 * 500 这边从y=600开始画 r+pointy+100
//可以将这些参数改为变量,目前不想改

//x方向前后都要空100单位
int shiftX=init.getShiftX();
//y方向距离雷达图100单位
int shiftY=init.getR()+init.getPoint().y+init.getShiftY();
//起点
Point point=new Point(shiftX,shiftY);
//两边空50 实际绘图区域为500
int lineCur=(width-2*shiftX)*curVal/maxVal;
int lineMax=(width-2*shiftX)*maxVal/maxVal;
Point p1=getMappedPoint(lineCur,0,point);
Point p2=getMappedPoint(lineMax,0,point);
g.setColor(init.getLineArrColor());
g.setStroke(init.getLineStroke());
g.drawLine(point.x,point.y,p1.x,p1.y);
g.setColor(init.getLineNotArrColor());
g.drawLine(p1.x,p1.y,p2.x,p2.y);

//画完线后标记起点和结束点
drawWord(g,init.getGenLineFont(),init.getGenTextColor(),point,staVal+"",-10,0);
drawWord(g,init.getGenLineFont(),init.getGenTextColor(),p2,maxVal+"",20,0);
drawWord(g,init.getGenLineFont(),init.getSpeTextColor(),p1,curVal+"",0,15);
//画小箭头
drawArrow(g,init.getLineArrColor(),p1);
//写文字
//特殊文字起点
Point speTextP=new Point(shiftX-5,shiftY+60);
drawWordNormal(g,init.getSpeLineFont(),init.getGenTextColor(),init.getSpeTextColor(),speTextP,init.getSpeLineText()+"的分数击败了全班",init.getSpeLineValue(),"的童鞋!");
}

这个线就是比分用的,比如小明总分500分,击败了全班80%的童鞋,这种直线及文字。
也没啥内容,主要就是绘制直线,要求变换直线宽度及颜色,然后在线的两端添加文字,然后在底部添加必要文字。
(PS:这儿的底部文字可以设置的,我直接写死了,其实也可以当参数传进来)

这个方法里面也用到了几个小方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 写字居中偏移方法
* @param g 绘图参数
* @param font 字体
* @param color 字体颜色
* @param point 绘制点
* @param value 绘制文本内容
* @param dx x偏移量
* @param dy y偏移量 如果x,y偏移量不设置理论上位于绘点中心
*/
private void drawWord(Graphics2D g,Font font,Color color,Point point,String value,double dx,double dy) {
FontRenderContext context = g.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(value, context);
g.setFont(font);
g.setColor(color);
double x = (bounds.getWidth()) / 2;
double y = (bounds.getHeight()) / 2;
g.drawString(value, (int) (point.x - x+dx), (int) (point.y + y+dy));
}

/**
* 特殊文字的文字绘制
*/
private void drawWordNormal(Graphics2D g,Font font,Color genColor,Color speColor,Point point,String firstValue,String cenVal,String endValue) {
FontRenderContext context = g.getFontRenderContext();
Rectangle2D bounds1 = font.getStringBounds(firstValue, context);
Rectangle2D bounds2 = font.getStringBounds(cenVal, context);
//Rectangle2D bounds3 = font.getStringBounds(endValue, context);
double x1 = bounds1.getWidth();
double x2 = bounds2.getWidth();
g.setFont(font);
g.setColor(genColor);
g.drawString(firstValue, (int) (point.x), (int) (point.y));
//画完后 再画特殊文字 再补上后面的内容
g.setColor(speColor);
g.drawString(cenVal, (int) (point.x+x1), (int) (point.y));
g.setColor(genColor);
g.drawString(endValue, (int) (point.x+x1+x2), (int) (point.y));
}

/**
* 绘制小箭头
* @param g 绘图参数
* @param color 箭头填充色
* @param point 箭头顶点
*/
private void drawArrow(Graphics2D g,Color color,Point point) {
g.setColor(color);
Polygon p = new Polygon();
p.addPoint(point.x,point.y);
p.addPoint(point.x-10,point.y-20);
p.addPoint(point.x,point.y-15);
p.addPoint(point.x+10,point.y-20);
g.fillPolygon(p);
}

相当于对一些细节的操作优化,这儿就不一一介绍了。

然后在程序出图之前,我们先用Java中比较古老的JFrame看看图片的效果,方便调试“修图”。

在RadarMap里添加如下方法,这个方法只有JFrame测试时用到,当图调好了就可以删了,如下:

1
2
3
4
5
6
7
8
9
/**
* 画雷达图主方法 这个方法主要是为了显示在jpanel上用,实际中主调
*/
public void drawRadarMap() {
drawCircles();
drawSpokes();
addWord();
drawLineAndWord();
}

很简单,依次调用上面的几个方法。

我们新建一个JFrame Test类,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* 测试类,可以把生成的图放到Jpanel可视化界面上,便于调试
*
* @author zwt
*
*/
public class MyTest extends JFrame {
MyPanel mp = null;

public static void main(String[] args) {
MyTest demo01 = new MyTest();
}

public MyTest() {
mp = new MyPanel();
this.add(mp);

this.setSize(600, 700);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}

// 定义一个MyPanel面板,用于绘图区域
class MyPanel extends JPanel {
// 覆盖JPanel
// Graphics 是绘图的重要类,可以理解成一支画笔
public void paint(Graphics g) {
// 1. 调用父类函数完成初始化任务
// 这句话不可以少
super.paint(g);

List<RadarMapData> dataList = new ArrayList<RadarMapData>();
RadarMapData map1 = new RadarMapData("100","150", "", "数学", "");
RadarMapData map2 = new RadarMapData("120","150", "", "语文", "");
RadarMapData map3 = new RadarMapData("90","150", "", "英语", "");
RadarMapData map4 = new RadarMapData("80","100", "", "物理", "");
RadarMapData map5 = new RadarMapData("95","100", "", "化学", "");
RadarMapData map6 = new RadarMapData("88","100","", "生物", "");
RadarMapData map7 = new RadarMapData("66","100", "", "历史", "");
RadarMapData map8 = new RadarMapData("77","100", "", "政治", "");
RadarMapData map9 = new RadarMapData("45","100", "", "地理", "");
RadarMapData map10 = new RadarMapData("88","100", "", "音乐", "");
RadarMapData map11 = new RadarMapData("80","100", "", "体育", "");
RadarMapData map12 = new RadarMapData("100","100", "", "美术", "");

dataList.add(map1);
dataList.add(map2);
dataList.add(map3);
dataList.add(map4);
dataList.add(map5);
dataList.add(map6);
dataList.add(map7);
dataList.add(map8);
dataList.add(map9);
dataList.add(map10);
dataList.add(map11);
dataList.add(map12);

int lineMaxValue = 0;
int currentValue = 0;

for(RadarMapData data:dataList){
lineMaxValue+=Integer.valueOf(data.getMaxValue());
currentValue+=Integer.valueOf(data.getValue());
}

RadarMapInit init = new RadarMapInit();
init.setCirNum(5);//20分一档,可以自己设置
init.setCenText(currentValue+"分");
init.setSpeLineValue("60%");//击败多少童鞋先瞎传一个数
init.setG((Graphics2D) g);
//init.setImgPath("/Users/zhangwentong/Desktop/image.jpg");
init.setLineCurVal(currentValue);
init.setLineMaxVal(lineMaxValue);
RadarMap test = new RadarMap(dataList, init);
test.drawRadarMap();
//test.createImage();
}
}

这个Test主要就是给一些参数赋值。然后测试,可以看到结果如下图所所示,哈哈,还是蛮不错的。

upload successful

这我们只在JFrame上测试了,我们的任务是生成图片,然后开始吧,在RadarMap里添加如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 生成图片文件
*/
public boolean createImage() {
boolean flag = false;
try {
File file = new File(init.getImgPath());
int width=init.getPicWidth();
int height=init.getPicHeight();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) bi.getGraphics();
//设置抗锯齿属性,不然图片锯齿化很模糊
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

g2.setBackground(init.getPicBackColor());
g2.clearRect(0, 0, width, height);
init.setG(g2);
//画圆
drawCircles();
//画射线及添加圆边的文字图片
drawSpokes();
//添加中心文字
addWord();
//添加下面那条线及内容
drawLineAndWord();
flag = ImageIO.write(bi, init.getImgType(), file);
} catch (Exception e) {
flag = false;
e.printStackTrace();
}
return flag;
}

这个方法主要就是利用了BufferedImage来生成一张图片。我们把刚才JFrame里的两行注掉的代码开启。

1
2
//init.setImgPath("/Users/zhangwentong/Desktop/image.jpg");
//test.createImage();

再次启动JFrame类,可以看到生成图片啦。

upload successful

upload successful

哈哈,蛮不错的……

然后我们把你的分数……这句话的你动态传入姓名(比如小红……)。
然后新建分数MapTest如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* @Author: zwt
* @Description: 总分雷达图
* @Name: ScoreMapTest
* @Date: 2019/1/5 11:49 PM
* @Version: 1.0
*/
public class ScoreMapTest {
private static final String [] names = {"小一","小二","小三","小四","小五","小六","小七","小八","小九","小十"};
//随机分数使用
private static int randomValue(int maxValue){
Random random = new Random();
return random.nextInt(maxValue);
}
public static void drawMapPic(){
for(String name:names){
List<RadarMapData> dataList = new ArrayList<RadarMapData>();
RadarMapData map1 = new RadarMapData(randomValue(150)+"","150", "", "数学", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map2 = new RadarMapData(randomValue(150)+"","150", "", "语文", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map3 = new RadarMapData(randomValue(150)+"","150", "", "英语", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map4 = new RadarMapData(randomValue(100)+"","100", "", "物理", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map5 = new RadarMapData(randomValue(100)+"","100", "", "化学", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map6 = new RadarMapData(randomValue(100)+"","100","", "生物", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map7 = new RadarMapData(randomValue(100)+"","100", "", "历史", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map8 = new RadarMapData(randomValue(100)+"","100", "", "政治", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map9 = new RadarMapData(randomValue(100)+"","100", "", "地理", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map10 = new RadarMapData(randomValue(100)+"","100", "", "音乐", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map11 = new RadarMapData(randomValue(100)+"","100", "", "体育", "/Users/zhangwentong/Desktop/book.png");
RadarMapData map12 = new RadarMapData(randomValue(100)+"","100", "", "美术", "/Users/zhangwentong/Desktop/book.png");

dataList.add(map1);
dataList.add(map2);
dataList.add(map3);
dataList.add(map4);
dataList.add(map5);
dataList.add(map6);
dataList.add(map7);
dataList.add(map8);
dataList.add(map9);
dataList.add(map10);
dataList.add(map11);
dataList.add(map12);

int lineMaxValue = 0;
int currentValue = 0;

for(RadarMapData data:dataList){
lineMaxValue+=Integer.valueOf(data.getMaxValue());
currentValue+=Integer.valueOf(data.getValue());
}

RadarMapInit init = new RadarMapInit();
init.setCirNum(5);//20分一档,可以自己设置
init.setCenText(currentValue+"分");
init.setSpeLineText(name);
init.setSpeLineValue("80%");//这个数可以计算,我这儿就不计算了(因为分数是随机的,计算比较蛋疼)
init.setImgPath("/Users/zhangwentong/Desktop/map/image"+name+".jpg");
init.setLineCurVal(currentValue);
init.setLineMaxVal(lineMaxValue);
RadarMap test = new RadarMap(dataList, init);
test.createImage();
}
}
public static void main(String[] args) {
drawMapPic();
}
}

同时添加图标(我这里只添加了一个相同的,不同的也是可以的),新建map文件夹(用于存放雷达图)。如下:

upload successful

运行测试类。打开map文件夹。

upload successful

随便选一张查看。

upload successful

总结

通过使用Java2D绘制雷达图,学到了Java2D的一些用途吧,虽然Java2D使用的很少,而且以后估计用的概率也不大,但是,我们就当一次对于Java程序的自娱自乐吧!

PS:Java图像处理方面确实很差,因为它的着重点不是这儿,而是大型Web项目,这篇文章的目的也不在于去理解Java2D的一些用途,而是通过一些学习,让我们知道,Java也是可以做一些莫名其妙的事情的,虽然不尽人意,也是,世界上哪有一种编程语言是完美的呢?




-------------文章结束啦 ~\(≧▽≦)/~ 感谢您的阅读-------------

SakuraTears wechat
扫一扫关注我的公众号
您的支持就是我创作的动力!
0%