自定义统计图的实例—曲线图

自定义统计图的实例-曲线图

润乾的自定义统计图功能给客户提供了丰富的统计图实现方法,客户可以根据自己的需求通过实现润乾的 API 接口,用 java 类画出符合自己需求的自定义统计图。下面就介绍一种自定义统计图实现的例子。

这里采用 java 的画图方法,实现一个自定义的曲线图。

第一步:制作一张报表。

连接 demo 数据源,采用内建数据集,制作一张简单的报表,报表的样式如下图所示:

其中 c1,c2,c3 字段都是字符串类型的。

第二步:用 java 画图。

润乾的自定义统计图一定要继承 DrawBase 类,重写其中的 draw() 方法。

在自定义统计图中重写 draw() 方法里面比较重要的就是给统计图设置分类和系列的值,然后就是根据客户的需求设置一些边框属性,背景色之类的属性。具体的可以参见下面的完整代码:

package example;

import com.runqian.report4.model.expression.graph.*;

import java.awt.*;

import java.util.ArrayList;

import java.util.Vector;

public class CustomCurveGraph extends DrawBase

{

public CustomCurveGraph()

{

}

public void draw(StringBuffer htmlLink)

{

gp.coorWidth = 0;

initGraphInset();

createCoorValue();

drawLegend(htmlLink);

drawTitle();

drawLabel();

keepGraphSpace();

adjustCoorInset();

gp.graphRect = new Rectangle(gp.leftInset, gp.topInset, gp.graphWidth – gp.leftInset – gp.rightInset, gp.graphHeight – gp.topInset – gp.bottomInset);

if (gp.graphRect.width < 10 || gp.graphRect.height < 10)

return;

if (gp.coorWidth < 0 || gp.coorWidth > 10000)

gp.coorWidth = 0;

double seriesWidth = (double)gp.graphRect.width / (((double)(gp.catNum + 1) * gp.categorySpan) / 100D + (double)gp.coorWidth / 200D + (double)(gp.catNum * gp.serNum));

double coorWidth = seriesWidth * ((double)gp.coorWidth / 200D);

double categorySpan = seriesWidth * (gp.categorySpan / 100D);

int tmpInt = (int)((double)(gp.catNum + 1) * categorySpan + coorWidth + (double)(gp.catNum * gp.serNum) * seriesWidth);

gp.graphRect.x += (gp.graphRect.width – tmpInt) / 2;

gp.graphRect.width = tmpInt;

double dely = ((double)gp.graphRect.height – coorWidth) / (double)gp.tickNum;

tmpInt = (int)(dely * (double)gp.tickNum + coorWidth);

gp.graphRect.y += (gp.graphRect.height – tmpInt) / 2;

gp.graphRect.height = tmpInt;

gp.gRect1 = new Rectangle(gp.graphRect);

gp.gRect2 = new Rectangle(gp.graphRect);

gp.gRect1.y += coorWidth;

gp.gRect1.width -= coorWidth;

gp.gRect1.height -= coorWidth;

gp.gRect2.x += coorWidth;

gp.gRect2.width -= coorWidth;

gp.gRect2.height -= coorWidth;

drawGraphRect();

Rectangle TR = new Rectangle();

for (int i = 0; i <= gp.tickNum; i++)

{

drawGridLine(dely, i);

Number coory = (Number)gp.coorValue.get(i);

String scoory = getFormattedValue(coory.doubleValue());

TR.setBounds(gp.GFV_YLABEL.getTextSize(scoory));

int x = gp.gRect1.x – TR.width – gp.tickLen;

int y = (int)(((double)(gp.gRect1.y + gp.gRect1.height) – (double)i * dely) + (double)(TR.height / 2));

gp.GFV_YLABEL.outText(x, y, scoory, (byte)11);

if (coory.doubleValue() == gp.baseValue + gp.minValue)

gp.valueBaseLine = (int)((double)(gp.gRect1.y + gp.gRect1.height) – (double)i * dely);

}

drawWarnLine();

Point beginPoint[] = new Point[gp.serNum];

double beginVal[] = new double[gp.serNum];

ArrayList catPoints[] = new ArrayList[gp.serNum];

for (int j = 0; j < gp.serNum; j++)

{

ArrayList catList = new ArrayList();

catPoints[j] = catList;

}

ArrayList cats = egp.categories;

int cc = cats.size();

for (int i = 0; i < cc; i++)

{

ExtGraphCategory egc = (ExtGraphCategory)cats.get(i);

int delx = (int)((double)(i + 1) * categorySpan + (double)i * seriesWidth * (double)gp.serNum + (seriesWidth * (double)gp.serNum) / 2D);

boolean vis = i % (gp.graphXInterval + 1) == 0;

if (vis)

drawLine(gp.gRect1.x + delx, gp.gRect1.y + gp.gRect1.height, gp.gRect1.x + delx, gp.gRect1.y + gp.gRect1.height + gp.tickLen, egp.getAxisColor(1));

String value = egc.getNameString();

TR.setBounds(gp.GFV_XLABEL.getTextSize(value));

int x = (gp.gRect1.x + delx) – TR.width / 2;

int y = gp.gRect1.y + gp.gRect1.height + gp.tickLen + TR.height;

gp.GFV_XLABEL.outText(x, y, value, vis);

for (int j = 0; j < gp.serNum; j++)

{

ExtGraphSery egs = egc.getExtGraphSery(gp.serNames.get(j));

double val = egs.getValue();

double tmp = val – gp.baseValue;

int len = (int)((dely * (double)gp.tickNum * (tmp – gp.minValue)) / (gp.maxValue * gp.coorScale));

double lb = (double)gp.gRect1.x + (double)(i + 1) * categorySpan + ((double)((2 * i + 1) * gp.serNum) * seriesWidth) / 2D;

Point endPoint;

if (egs.isNull())

endPoint = null;

else

endPoint = new Point((int)lb, gp.valueBaseLine – len);

int VALUE_RADIUS = 4;

if (gp.dispValueOntop && !egs.isNull() && vis)

{

String sval = getDispValue(egs);

TR.setBounds(gp.GFV_VALUE.getTextSize(sval));

x = endPoint.x;

y = endPoint.y;

gp.GFV_VALUE.outText(x, y – VALUE_RADIUS, sval);

}

if (!egs.isNull() && gp.drawLineDot && vis)

{

int xx = endPoint.x – VALUE_RADIUS;

int yy = endPoint.y – VALUE_RADIUS;

int ww = 2 * VALUE_RADIUS;

int hh = ww;

if (!gp.isMultiSeries)

setPaint(xx, yy, ww, hh, getColor(i), true);

else

setPaint(xx, yy, ww, hh, getColor(j), true);

fillRect(xx, yy, ww, hh);

drawRect(xx, yy, ww, hh, egp.getAxisColor(5));

htmlLink(xx, yy, ww, hh, htmlLink, egc.getNameString(), egs);

}

if (i > 0)

{

g.setColor(getColor(j));

DrawLine.drawVTrendLine(this, beginPoint[j], endPoint, val – beginVal[j]);

}

DrawLine.drawHTrendLine(this, beginPoint[j]);

beginPoint[j] = endPoint;

if (endPoint != null)

{

ArrayList catList = catPoints[j];

catList.add(endPoint);

}

beginVal[j] = val;

}

}

java.awt.Stroke stroke = getLineStroke();

if (stroke != null)

g.setStroke(stroke);

for (int j = 0; j < gp.serNum; j++)

{

ArrayList serPoints = catPoints[j];

if (serPoints.size() != 0)

{

Point p1 = (Point)serPoints.get(0);

Point p2 = (Point)serPoints.get(serPoints.size() – 1);

g.setColor(getColor(j));

int x1 = p1.x;

int y1 = p1.y;

for (int x2 = p1.x + 1; x2 <= p2.x; x2++)

{

int y2 = (int)Lagrange(serPoints, x2, gp.valueBaseLine);

g.drawLine(x1, y1, x2, y2);

x1 = x2;

y1 = y2;

} }

}

}

private double Lagrange(ArrayList points, double deltaX, int BottomY)

{

double sum = 0.0D;

for (int i = 0; i < points.size(); i++)

{

double L = 1.0D;

Point pi = (Point)points.get(i);

for (int j = 0; j < points.size(); j++)

{

Point pj = (Point)points.get(j);

if (j != i)

L = (L * (deltaX – (double)pj.x)) / (double)(pi.x – pj.x);

} sum += L * (double)pi.y;

}

if (sum > (double)BottomY)

return (double)BottomY;

else

return sum;

}

}

自定义统计图里面要设置的属性比较复杂,但是大致的流程都跟上面的写法几乎一致,只是在定义不同种类统计图的时候可能有一些区别。

第三步:在报表中使用自定义统计图。

将第一步中的报表加入自定义统计图,把 C 列隐藏,统计图的写法可以参见下图:

然后把上面的 java 代码编译成 java 类,连同包一起放到 reportHome\designer\web\WEB-INF\classes

然后重启一下设计器,点击预览报表,可以看到下图的效果:

这样自定义统计图的需求就实现了。

热门文章