自定义统计图的实例—曲线图
自定义统计图的实例-曲线图
润乾的自定义统计图功能给客户提供了丰富的统计图实现方法,客户可以根据自己的需求通过实现润乾的 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 下
然后重启一下设计器,点击预览报表,可以看到下图的效果:
这样自定义统计图的需求就实现了。