自定义统计图实现3D饼图
1. 问题概述
润乾报表本身提供了丰富的统计图,但有时候也难以满足有些客户心里想的那种效果,
如下是通过润乾三维饼图实现效果:
客户觉得有些地方不太完美:
1.各个省份的数据能否都分扇显示和带上当前省份?
2.占比比较小的情况下,能否区分开省份,不要那么挤?
3.能否整体布局调整?
因此需要自定义统计图的方式实现,见实例演示
2. 实例演示
根据WORD2007里统计图配色实现润乾取色
配色方案1:
配色方案2:
配色方案3:
3. 案例
通联支付
4. 解决思路
1. 继承润乾报表提供的com.runqian.report4.model.expression.graph.DrawBase类,重载它的public void draw(StringBuffer htmlLink) 方法
DrawBase类里有一些重要的方法和变量可能被用到,这里介绍一下:
protected Graphics2D g; //画布,在其上直接画统计图即可
protected GraphParam gp; //存放统计图的大部分参数
protected ExtGraphProperty egp; //存放统计图的数据以及用户自定义参数(3.4.5.2介绍)
protected Color getColor(int index)//获取配色方案里的第几个颜色值
2. 根据WORD2007里统计图配色实现润乾取色统计图的配色方案,柱图,饼图,折线图.见附件
5. 程序说明
1. Draw3Dpie代码:
package java3d;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import com.runqian.report4.model.expression.graph.DrawBase;
import com.runqian.report4.model.expression.graph.ExtGraphCategory;
import com.runqian.report4.model.expression.graph.ExtGraphSery;
public class Draw3DPie extends DrawBase
{
Point2D.Double cps;
int w = 0;
int h = 0;
int hight = 40;
double pr = 0.0D;
double r1 = 0.0D;
double r2 = 0.0D;
int linel = 0;
static final BasicStroke wideStroke = new BasicStroke(1.2F);
static final double arcPi = 0.0174532925199433D;
private void initProperty(StringBuffer htmlLink)
{
this.gp.coorWidth = 0;
initGraphInset();
createCoorValue();
drawLegend(htmlLink);
drawTitle();
drawLabel();
keepGraphSpace();
adjustCoorInset();
this.gp.graphRect =
new Rectangle(0, 0, this.gp.graphWidth,
this.gp.graphHeight);
if ((this.gp.graphRect.width < 10) || (this.gp.graphRect.height < 10)) {
System.out.println(“The area is too small to draw a picture!”);
return;
}
}
private void initGeometry()
{
this.gp.graphRect =
new Rectangle(0, 0, this.gp.graphWidth,
this.gp.graphHeight);
this.w = (this.gp.graphRect.width - this.gp.leftInset - this.gp.rightInset - this.gp.leftMargin);
this.h =
(this.gp.graphRect.height - this.gp.topMargin - this.gp.topInset -
this.gp.bottomInset);
this.h = Math.min(this.w, this.h);
double s = this.h / 135;
this.pr = (20.0D * s);
this.r1 = (80.0D * s);
this.r2 = (90.0D * s);
this.linel = (int)(135.0D * s);
double x = 145.0D * s + this.gp.leftInset + this.gp.leftMargin;
double y = 55.0D * s + this.gp.topInset + this.gp.topMargin;
this.cps = new Point2D.Double(x, y);
}
public void draw(StringBuffer htmlLink) {
double val;
java.lang.Double d;
double py;
double party;
double prx;
double pry;
Point2D.Double curcps;
java.lang.Double dR1;
double x1;
double y1;
java.lang.Double dX1;
java.lang.Double dY1;
java.lang.Double dR2;
double x2;
double y2;
java.lang.Double dX2;
java.lang.Double dY2;
Color currColor;
initProperty(htmlLink);
initGeometry();
this.g.setBackground(this.g.getBackground());
RenderingHints qualityHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
qualityHints.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
this.g.setRenderingHints(qualityHints);
ArrayList cats = this.egp.categories;
double dSum = 0.0D;
String[][] catvals = new String[this.gp.catNum][2];
for (int i = 0; i < this.gp.catNum; ++i) {
ExtGraphCategory egc = (ExtGraphCategory)cats.get(i);
catvals[i][0] = egc.getNameString();
for (int j = 0; j < this.gp.serNum; ++j) {
ExtGraphSery egs = egc.getExtGraphSery(this.gp.serNames.get(j));
if (egs.isNull()) {
catvals[i][1] = “0″;
}
else {
val = egs.getValue();
dSum += val;
catvals[i][1] = java.lang.Double.toString(val);
}
}
}
String[] temp = new String[2];
for (int i = 0; i < catvals.length / 2 + 1; ++i)
{
int j = 0; for (int k = catvals.length - 1; j < catvals.length - 1; )
{
if (java.lang.Double.parseDouble(catvals[j][1]) >
java.lang.Double.parseDouble(catvals[(j + 1)][1]))
{
temp[0] = catvals[j][0];
temp[1] = catvals[j][1];
catvals[j][0] = catvals[(j + 1)][0];
catvals[j][1] = catvals[(j + 1)][1];
catvals[(j + 1)][0] = temp[0];
catvals[(j + 1)][1] = temp[1];
}
if (java.lang.Double.parseDouble(catvals[k][1]) <
java.lang.Double.parseDouble(catvals[(k - 1)][1]))
{
temp[0] = catvals[k][0];
temp[1] = catvals[k][1];
catvals[k][0] = catvals[(k - 1)][0];
catvals[k][1] = catvals[(k - 1)][1];
catvals[(k - 1)][0] = temp[0];
catvals[(k - 1)][1] = temp[1];
}
++j; –k;
}
}
if (dSum == 0.0D) {
System.out.println(“sum is 0 exit!”);
return;
}
int startAngle = 90;
int arcAngle = 0;
int perPart = 1;
int i = 0; for (int j = 0; i < catvals.length; ++i) {
val = java.lang.Double.parseDouble(catvals[i][1]);
d = new java.lang.Double(360.0D * val / dSum);
if (d != null) {
arcAngle = d.intValue();
party = startAngle + arcAngle / 2;
if (party > 180)
{
perPart = 180 / (i – j);
}
startAngle = startAngle +
arcAngle;
}
}
startAngle = 90;
i = 0; for (int j = 0; i < catvals.length; ++i) {
val = java.lang.Double.parseDouble(catvals[i][1]);
d = new java.lang.Double(360.0D * val / dSum);
if (d != null) {
arcAngle = d.intValue();
py = (startAngle + arcAngle) * 0.0174532925199433D;
party = (startAngle + arcAngle / 2) * 0.0174532925199433D;
prx = (int)this.pr * Math.cos(party) * 12.0D / 17.0D;
pry = (int)this.pr * Math.sin(party) * 5.0D / 17.0D;
curcps = new Point2D.Double(this.cps.x + prx, this.cps.y -
pry);
dR1 = new java.lang.Double(this.r1);
x1 = curcps.x - (dR1.intValue() * 12 / 17) – ((int)this.pr * 12 /
17);
y1 = curcps.y - (dR1.intValue() * 5 / 17) – ((int)this.pr * 5 /
17);
dR2 = new java.lang.Double(this.r2);
x2 = curcps.x - (dR2.intValue() * 12 / 17);
y2 = curcps.y - (dR2.intValue() * 5 / 17);
int[] xx1 = new int[4];
int[] yy1 = new int[4];
xx1[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 *
Math.cos(startAngle *
0.0174532925199433D)));
yy1[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 *
Math.sin(startAngle *
0.0174532925199433D)) +
this.hight);
xx1[1] = xx1[0];
yy1[1] = (yy1[0] - this.hight);
xx1[2] = (int)curcps.x;
yy1[2] = (int)curcps.y;
xx1[3] = (int)curcps.x;
yy1[3] = ((int)curcps.y + this.hight);
int[] xx2 = new int[4];
int[] yy2 = new int[4];
xx2[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 * Math.cos(py)));
yy2[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 * Math.sin(py)) +
this.hight);
xx2[1] = xx2[0];
yy2[1] = (yy2[0] - this.hight);
xx2[2] = (int)curcps.x;
yy2[2] = (int)curcps.y;
xx2[3] = (int)curcps.x;
yy2[3] = ((int)curcps.y + this.hight);
this.g.setPaint(Color.BLACK);
this.g.fillPolygon(xx1, yy1, 4);
this.g.fillPolygon(xx2, yy2, 4);
String percent = getFormattedValue(val / dSum);
int[] linex = new int[3];
int[] liney = new int[3];
linex[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 * Math.cos(party)));
liney[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 * Math.sin(party)) +
(((party > 3.141592653589793D) && (party < 6.283185307179586D)) ? this.hight :
0));
if (party < 3.141592653589793D)
party = (60 + perPart * (i – j)) * 0.0174532925199433D;
linex[1] =
((int)curcps.x +
(int)(this.linel * 12 / 17 * Math.cos(party)));
liney[1] =
((int)curcps.y -
(int)(this.linel * 5 / 17 * Math.sin(party)) +
(((party > 3.141592653589793D) && (party < 6.283185307179586D)) ? this.hight :
0));
linex[2] =
(linex[1] +
(((party > 1.570796326794897D) && (party < 4.71238898038469D)) ? 5 :
-5));
if ((Math.abs(party / 0.0174532925199433D – 90.0D) < 6.0D) ||
(Math.abs(party / 0.0174532925199433D – 270.0D) < 6.0D))
linex[2] = linex[1];
liney[2] = liney[1];
this.g.setColor(Color.BLACK);
this.g.setStroke(wideStroke);
this.g.drawLine(linex[0], liney[0], linex[2], liney[2]);
this.g.drawLine(linex[1], liney[1], linex[2], liney[2]);
this.g.setFont(new Font(“宋体“, 1, 10));
this.g
.drawString(
catvals[i][0],
linex[1] -
(((party > 1.570796326794897D) && (party < 4.71238898038469D)) ?
catvals[i][0].length() * 10 :
0),
liney[1] -
(((party > 3.141592653589793D) && (party < 6.283185307179586D)) ? -10 :
10));
this.g
.drawString(
percent,
linex[1] -
(((party > 1.570796326794897D) && (party < 4.71238898038469D)) ?
(percent
.length() + 1) *
5 :
0),
liney[1] +
(((party > 3.141592653589793D) && (party < 6.283185307179586D)) ? 20 :
0));
startAngle += arcAngle;
}
}
startAngle = 90;
for (i = 0; i < catvals.length; ++i) {
val = java.lang.Double.parseDouble(catvals[i][1]);
d = new java.lang.Double(360.0D * val / dSum);
if (d != null) {
arcAngle = d.intValue();
if (startAngle + arcAngle < 180) {
startAngle += arcAngle;
}
else
{
py = (startAngle + arcAngle) * 0.0174532925199433D;
party = (startAngle + arcAngle / 2) * 0.0174532925199433D;
prx = (int)this.pr * Math.cos(party) * 12.0D / 17.0D;
pry = (int)this.pr * Math.sin(party) * 5.0D / 17.0D;
curcps = new Point2D.Double(this.cps.x + prx,
(int)this.cps.y - pry);
dR1 = new java.lang.Double(this.r1);
x1 = curcps.x - (dR1.intValue() * 12 / 17) – ((int)this.pr * 12 /
17);
y1 = curcps.y - (dR1.intValue() * 5 / 17) – ((int)this.pr * 5 /
17);
dX1 = new java.lang.Double(x1);
dY1 = new java.lang.Double(y1);
dR2 = new java.lang.Double(this.r2);
x2 = (int)curcps.x - (dR2.intValue() * 12 / 17);
y2 = (int)curcps.y - (dR2.intValue() * 5 / 17);
dX2 = new java.lang.Double(x2);
dY2 = new java.lang.Double(y2);
currColor = getColor(i);
int[] xx = new int[4];
int[] yy = new int[4];
xx[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 *
Math.cos(startAngle *
0.0174532925199433D)));
yy[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 *
Math.sin(startAngle *
0.0174532925199433D)));
if ((startAngle < 180) && (startAngle + arcAngle > 180)) {
xx[0] = ((int)curcps.x - (dR2.intValue() * 12 / 17));
yy[0] = (int)curcps.y;
}
xx[1] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 * Math.cos(py)));
yy[1] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 * Math.sin(py)));
if (startAngle + arcAngle > 360) {
xx[1] = ((int)curcps.x + dR2.intValue() * 12 / 17);
yy[1] = (int)curcps.y;
}
xx[2] = xx[1];
yy[2] = (yy[1] + this.hight);
xx[3] = xx[0];
yy[3] = (yy[0] + this.hight);
int[] xx3 = new int[3];
int[] yy3 = new int[3];
xx3[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 *
Math.cos(startAngle *
0.0174532925199433D)));
yy3[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 *
Math.sin(startAngle *
0.0174532925199433D)) +
this.hight);
xx3[1] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 * Math.cos(py)));
yy3[1] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 * Math.sin(py)) +
this.hight);
xx3[2] =
((int)curcps.x -
(int)(5 * dR2.intValue() * 12 / 17 * Math.cos(party)));
yy3[2] =
((int)curcps.y +
(int)(5 * dR2.intValue() * 5 / 17 * Math.sin(party)) +
this.hight);
int[] xx4 = new int[3];
int[] yy4 = new int[3];
xx4[0] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 *
Math.cos((startAngle – 2) * 0.0174532925199433D)));
yy4[0] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 *
Math.sin((startAngle – 2) * 0.0174532925199433D)) +
this.hight);
if ((startAngle < 180) && (startAngle + arcAngle > 180)) {
xx4[0] = ((int)curcps.x - (dR2.intValue() * 12 / 17));
yy4[0] = (int)curcps.y;
}
xx4[1] =
((int)curcps.x +
(int)(dR2.intValue() * 12 / 17 * Math.cos(py + 0.03490658503988659D)));
yy4[1] =
((int)curcps.y -
(int)(dR2.intValue() * 5 / 17 * Math.sin(py + 0.03490658503988659D)) +
this.hight);
if ((startAngle < 360) && (startAngle + arcAngle > 360)) {
xx4[1] = ((int)curcps.x + dR2.intValue() * 12 / 17);
yy4[1] = (int)curcps.y;
}
xx4[2] = (int)curcps.x;
yy4[2] =
((int)curcps.y +
this.hight);
this.g.setPaint(currColor.darker());
Area area1 = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue() +
this.hight, 2 * dR2.intValue() * 12 / 17, 2 *
dR2.intValue() * 5 /
17, startAngle, arcAngle,
1));
System.out.println(area1.toString());
Area areapie = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue() +
this.hight, 2 * dR2.intValue() * 12 / 17, 2 *
dR2.intValue() * 5 /
17, startAngle, arcAngle, 2));
if ((startAngle < 180) && (startAngle + arcAngle > 180) &&
(startAngle + arcAngle < 360))
areapie = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue() +
this.hight, 2 * dR2.intValue() * 12 / 17, 2 *
dR2.intValue() * 5 /
17, 180.0D, startAngle + arcAngle -
180, 2));
else if ((startAngle < 180) && (startAngle + arcAngle > 360))
areapie = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue() +
this.hight, 2 * dR2.intValue() * 12 / 17, 2 *
dR2.intValue() * 5 /
17, 180.0D, 180.0D, 2));
else if ((startAngle > 180) && (startAngle + arcAngle > 360))
areapie = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue() +
this.hight, 2 * dR2.intValue() * 12 / 17, 2 *
dR2.intValue() * 5 /
17, startAngle,
360 – startAngle, 2));
Area trianglarea = new Area(new Polygon(xx3, yy3, 3));
System.out.println(trianglarea.toString());
Area trianglarea2 = new Area(new Polygon(xx4, yy4, 3));
Area pillararea = new Area(new Polygon(xx, yy, 4));
areapie.subtract(trianglarea2);
areapie.add(pillararea);
if (startAngle + arcAngle > 180)
this.g.fill(areapie);
startAngle += arcAngle;
}
}
}
startAngle = 90;
for (i = 0; i < catvals.length; ++i) {
val = java.lang.Double.parseDouble(catvals[i][1]);
d = new java.lang.Double(360.0D * val / dSum);
if (d != null) {
arcAngle = d.intValue();
py = (startAngle + arcAngle) * 0.0174532925199433D;
party = (startAngle + arcAngle / 2) * 0.0174532925199433D;
prx = (int)this.pr * Math.cos(party) * 12.0D / 17.0D;
pry = (int)this.pr * Math.sin(party) * 5.0D / 17.0D;
curcps = new Point2D.Double(this.cps.x + prx, this.cps.y -
pry);
dR1 = new java.lang.Double(this.r1);
x1 = curcps.x - (dR1.intValue() * 12 / 17);
y1 = curcps.y - (dR1.intValue() * 5 / 17);
dX1 = new java.lang.Double(x1);
dY1 = new java.lang.Double(y1);
dR2 = new java.lang.Double(this.r2);
x2 = (int)curcps.x - (dR2.intValue() * 12 / 17);
y2 = (int)curcps.y - (dR2.intValue() * 5 / 17);
dX2 = new java.lang.Double(x2);
dY2 = new java.lang.Double(y2);
currColor = getColor(i);
this.g.setPaint(currColor);
Area careapie = new Area(
new Arc2D.Double(dX2.intValue(),
dY2.intValue(), 2 * dR2.intValue() * 12 / 17,
2 * dR2.intValue() * 5 / 17, startAngle,
arcAngle, 2));
this.g.fill(careapie);
this.g.setStroke(new BasicStroke(1.0F));
this.g.draw(careapie);
Color arcColor = currColor;
int curstartAngle = startAngle;
int curarcAngle = arcAngle;
if ((startAngle + arcAngle < 180) || (startAngle > 360)) {
startAngle += arcAngle;
} else {
if ((startAngle < 180) && (startAngle + arcAngle < 360)) {
curstartAngle = 180;
curarcAngle = startAngle + arcAngle – 180;
} else if ((startAngle < 180) && (startAngle + arcAngle > 360)) {
curstartAngle = 180;
curarcAngle = 180;
} else if (startAngle + arcAngle > 360) {
curarcAngle = 360 – startAngle;
}
for (int j = 0; j < 10; ++j)
{
arcColor = currColor.brighter();
this.g.setPaint(arcColor);
this.g
.drawArc(
dX2.intValue() + j / 2,
dY2.intValue() + j / 2 + 2,
2 * dR2.intValue() * 12 / 17 – j,
2 * dR2.intValue() * 5 / 17 – j,
curstartAngle, curarcAngle);
}
startAngle += arcAngle;
}
}
}
}
}