分享
 
 
 

在JSP页面中轻松实现数据饼图

王朝java/jsp·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

JSP提供了很多简单实用的工具,其中包括从数据库中读出数据,发送数据,并能够把结果显示在一个饼状图形。现在让我们看看这一简单而实用的方法。

你所需要的东西

为了能正确运行这一文章相关的范例,你必须需要JDK 1.2或更高的版本、一个关系数据库管理系统、一个JSP网络服务器。我都是在Tomcat调试这些例子,同时我也使用了Sun Java 2 SDK发布的com.sun.image.codec.jpegclasses。数据库设计

假设你在一家从事销售新鲜水果的公司上班,公司出售的水果包括:苹果、桔子、葡萄。现在你的老板想用一个饼状图形显示每一种水果的总出售量,饼状图形能使每一种产品的销售情况一目了然,老板可以迅速掌握公司的产品成交情况。

表A使用了本文中的两种数据库列表。第一种列表(Products)包含所有销售产品的名称;第二种列表(Sales)包含每一种产品对应的销售量。

Listing A

Database Design

---------------

p_products table

----------------

productID int (number) not null

productname String (varchar) not null

p_sales table

-------------

saleID int (number) not null

productID int (number) not null

amount floatnot null

产品(Products)列表包含productID和productname两个域。销售(Sales)列表包含saleID, productID,以及总额。销售列表中的productID提供了这两个列表之间的关联。销售列表中的总额包含了每一次出售的现金数额,这些数额以浮点型数据出现。

表B中的getProducts()方法连接了两个数据库,并把所有的产品名称保存在数组中:

Listing B

////////////////////////////////////////////////////////////

//Get products from the database as a String array

////////////////////////////////////////////////////////////

public String[] getProducts()

{

String[] arr = new String[0];

Connection con;

Statement stmt;

ResultSet rs;

int count = 0;

String sql = "select * from p_products order by productID";

try

{

//Load Driver: Class.forName(driver);

//Connect to the database with the url

con = DriverManager.getConnection(dburl , dbuid , dbpwd);

stmt = con.createStatement();

//Get ResultSet

rs = stmt.executeQuery(sql);

//Count the records

while(rs.next())

{count++;}

//Create an array of the correct size

arr = new String[count];

//Get ResultSet (the portable way of using rs a second time)

rs = stmt.executeQuery(sql);

while(rs.next())

{

arr[rs.getInt("productID")] = rs.getString("productname");

}

stmt.close();

con.close();

}

catch (java.lang.Exception ex)

{

arr[0] = ex.toString();

}

return arr;

}

我设置以下的数据库规则:

1、ProductID在产品列表中最独特,也是最关键;

2、ProductID对于第一个记录的值为0;

3、所有之后的连续的记录都是累加的,所以第二个记录的productID为1,第三个记录的productID为2,以此类推。

这些数据库规则允许在product数组中存储数据,如下所示:

arr[rs.getInt("productID")] = rs.getString("productname");

一些数据库管理系统在缺省情况下就允许数据的自动累加或者自动排序。当你在设计数据库时,一定先查明你的数据库管理系统遵循哪些规则,比如自动累加,自动排序等。

获取总销售量

在多数情况下,销售列表中会有很多个记录,所以访问数据库的快捷性和高效性显得非常重要。现在我们只需要访问数据库中每一种产品的总额销售量。

表C中的getSales()方法与数据库连接并返回一个数组,这个数组包含每一种产品的总额出售量。

Listing C

////////////////////////////////////////////////////////////

//Get the sales totals from the database

////////////////////////////////////////////////////////////

public float[] getSales(int products)

{

float[] arr = new float[products];

Connection con;

Statement stmt;

ResultSet rs;

int count = 0;

String sql = "select productID, amount from p_sales";

try

{

//Load Driver:

Class.forName(driver);

//Connect to the database with the url

con = DriverManager.getConnection(dburl , dbuid , dbpwd);

stmt = con.createStatement();

//Get ResultSet

rs = stmt.executeQuery(sql);

while(rs.next())

{

int product = rs.getInt("productID");

//Check that the productID is valid

if (product >= 0 && product < products)

{

//Add to product total

arr[product] += rs.getFloat("amount");

count++;

}

}

stmt.close();

con.close();

}

catch (java.lang.Exception ex)

{

arr[0] = -1.0f;

}

return arr;

}

当getSales()遍历所有的记录后,它只存储的是每一种产品新的出售量:

int product = rs.getInt("productID");

arr[product] += rs.getFloat("amount");

pieColor对象

饼状图形上的每一种产品应该以不同的颜色显示。为了达到这一目的,我们建立一个pieColor对象(如表D)所示,这一对象包含有关颜色的数组:

Color pieColorArray[] = {new Color(210,60,60), new Color(60,210,60)…}

pieColor类定义了一个setNewColor()的方法,这一方法能够使curPieColor和索引递增,同时它可以检查索引不要超过边界范围,即采用的方法是:如果curPieColor过大即赋0值。

更有效的是,setNewColor()循环每一种颜色后,并在第一种颜色下执行以下的代码:

curPieColor++;

if(curPieColor >= pieColorArray.length)

{curPieColor = 0;}

||||||RenderingHints和antialiasing类

java.awt.RenderingHints类定义了很多方法以显示二维图形,包括alpha_interpolation, 抖动,以及antialiasing方法。RenderingHints有助于决定图形如何显示以及图形如何达到最佳处理。

为了能以平滑显示,可以使用antialiasing方法来处理饼状图形。Antialiasing是一种图形的平滑处理方法。其算法是选择一个特殊象素的颜色值并取代交叉处的象素,从而能够使线条交叉处得到平滑化。

图A说明了antialiasing方法的效果。可以看出使用antialiasing方法的饼状图形的线条交叉处变得很平滑。

图A

同时,还可以建立一个RenderingHints对象,并传递到Graphics2D setRenderingHints()方法,如下所示:

RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

g2d.setRenderingHints(renderHints);

制做可调整的边界

图A中的饼状图形有一边界,如何能改变边界的大小呢?可以先定义int border = 10,然后计算边界内面积的大小而实现:

Ellipse2D.Double elb = new Ellipse2D.Double(x_pie - border/2, y_pie - border/2, pieWidth + border, pieHeight + border);

x_pie和y_pie的值代表着包围在饼状图形的正方形的左上角。我们通过边界面积取一半(border/2)而得到饼状图形的中心。

圆弧(Arc)理论

从java.awt.Graphics 类继承而来的fillArc()方法提供了绘制饼状图形各个部分(或圆弧)的简单方法:

g2d.fillArc(x_position, y_position, width, height, startAngle, sweepAngle);

x_position,和y_position整数代表着要填充的圆弧的左上角的x,y的坐标,width和heigh整数代表其具体的尺寸。如果width和height的值相等,饼状图形将是一个圆。如果width和height不相等,那么饼状图形将是一个椭圆。

fillArc()方法决定基于sweepAngle整数值的圆弧的大小。如果sweepAngle值是正的,则圆弧是以反时针方向绘制,反之以顺时针绘制。

绘制圆弧

第一步,使用pieColor对象的getPieColor()方法获取最近饼状圆弧的颜色,并把它赋予当前的圆弧::

g2d.setColor(pc.getPieColor());

接着,通过不断循环sales[]数组并使其累加而获得总共的销售量:

salesTotal += sales[i];

使用总共销售量,可以计算出每一种产品销售情况占总共销售量的百分量:

float perc = (sales[i]/salesTotal);

我们计算sweepAngle即可给圆弧的每一部分分配度数:

int sweepAngle = (int)(perc * 360);

每一部分圆弧画完之后,startAngle即可根据当前的sweepAngle递增。这就确保当前的圆弧部分都是以上一圆弧为开始,从而建立一个完整的饼状图形。

显示图标

图标提供了显示饼状图形中各个部分最简洁的方式。一个图标的大小应该与饼状图形中的占有量相对应。

图B显示了一个完整饼状图形及其对应各个部分的图标,包括产品名称、销售总量、以及各个部分的占有量。

图B

总结

本文讲述了如何利用JSP绘制饼状图形的方法及算法,这些方法及算法简单而实用,开发人员可以充分地利用这些方法。

附:本文全部源代码

Listing E

<%@ page language="java" %>

<%@ page import="java.io.OutputStream" %>

<%@ page import="java.sql.*" %>

<%@ page import="java.awt.*" %>

<%@ page import="java.awt.geom.*" %>

<%@ page import="java.awt.image.BufferedImage" %>

<%@ page import="com.sun.image.codec.jpeg.*" %>

<%!

////////////////////////////////////////////////////////////

// PieColors class manages the colors used in the pie chart

////////////////////////////////////////////////////////////

class PieColors

{

Color pieColorArray[] = {

new Color(210,60,60), new Color(60,210,60), new Color(60,60,210),

new Color(120,60,120), new Color(60,120,210), new Color(210,120,60)

};

int curPieColor = 0;

public Color getPieColor()

{

return pieColorArray[curPieColor];

}

public void setNewColor()

{

curPieColor++;

if(curPieColor >= pieColorArray.length)

{curPieColor = 0;}

}

}

%>

<%! String driver = "com.mysql.jdbc.Driver"; String dburl = "jdbc:mysql://localhost/articles"; String dbuid = "myuid"; String dbpwd = "mypwd";

////////////////////////////////////////////////////////////

// Get the products from the database as a String array

////////////////////////////////////////////////////////////

public String[] getProducts()

{

String[] arr = new String[0];

Connection con;

Statement stmt;

ResultSet rs;

int count = 0;

String sql = "select * from p_products order by productID";

try

{

//Load Driver:

Class.forName(driver);

//Connect to the database with the url

con = DriverManager.getConnection(dburl , dbuid , dbpwd);

stmt = con.createStatement();

//Get ResultSet

rs = stmt.executeQuery(sql);

//Count the records

while(rs.next()){count++;

}

//Create an array of the correct size

arr = new String[count];

//Get ResultSet (the most portable way of using rs a second time)

rs = stmt.executeQuery(sql);

while(rs.next())

{

arr[rs.getInt("productID")] = rs.getString("productname");

}

stmt.close();

con.close();

}

catch (java.lang.Exception ex)

{arr[0] = ex.toString();}

return arr;

}

||||||////////////////////////////////////////////////////////////

//Get the sales totals from the database

////////////////////////////////////////////////////////////

public float[] getSales(int products)

{

float[] arr = new float[products];

Connection con;

Statement stmt;

ResultSet rs;

String sql = "select productID, amount from p_sales";

try {

//Load Driver:

Class.forName(driver);

//Connect to the database with the url

con = DriverManager.getConnection(dburl , dbuid , dbpwd);

stmt = con.createStatement();

//Get ResultSet

rs = stmt.executeQuery(sql);

while (rs.next()) { int product = rs.getInt("productID");

//Ch

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有