📄 linechart3dbean.java
字号:
// Fig. 9.2_02_01: LineChart3DBean.java
// 功能: 生成3D线段图的JavaBean
package chart;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.imageio.*;
public class LineChart3DBean extends HttpServlet
{
HttpServletResponse response;
static int width = 500, height = 400;
static int plotWidth = 400, plotHeight = 300;
private String xAxisLabel = "销售时间";
private String yAxisLabel = "销售量";
private String chartTitle = "线段图表Bean: 书籍月销售量统计图";
// 设定阴影的厚度
int thickness = 25;
// 设定夹角
int alpha = 45;
private Graphics2D g2d = null;
private BufferedImage image = null;
public LineChart3DBean()
{
// 默认构造器
}
public LineChart3DBean(HttpServletResponse response)
{
this.response = response;
this.initialize();
this.drawBackground();
this.drawTitle();
this.drawChart();
this.drawAxisLabel();
}
public void initialize()
{
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2d = image.createGraphics();
g2d.setColor(Color.white);
g2d.fillRect(0, 0, width, height);
}
// 绘制整个图表的背景
public void drawBackground()
{
// 阴影和图表之间的偏移量
int shadowOffset = 5;
g2d.setColor(Color.white);
g2d.fillRect(0, 0, width, height);
// 打开反锯齿功能,用于平滑处理相关背景
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制阴影,由灰色渐进圆角矩形组成
GradientPaint grayGP = new GradientPaint(0, 0, Color.GRAY, width, height,
new Color(218, 214, 212), false);
g2d.setPaint(grayGP);
RoundRectangle2D.Float bgRR = new RoundRectangle2D.Float(shadowOffset,
shadowOffset, width - shadowOffset, height - shadowOffset, 50, 50);
g2d.fill(bgRR);
// 绘制渐进蓝色圆角矩形背景
GradientPaint blueGP = new GradientPaint(0, 0, new Color(93, 117, 151), 0,
height, new Color(90, 114, 150), false);
g2d.setPaint(blueGP);
g2d.fillRoundRect(0, 0, width - shadowOffset, height - shadowOffset, 50, 50);
// 绘制深蓝色圆角矩形轮廓
BasicStroke bs = new BasicStroke(2.0f);
g2d.setStroke(bs);
g2d.setPaint(new Color(55, 71, 105));
g2d.drawRoundRect(0, 0, width - shadowOffset, height - shadowOffset, 50, 50);
// 绘制图表绘图区域背景的阴影效果
Rectangle2D.Float drawArea = new Rectangle2D.Float(83, 33, plotWidth,
plotHeight);
g2d.setPaint(new Color(27, 60, 105));
g2d.fill(drawArea);
// 填充图表绘图区域背景
GradientPaint plotGP = new GradientPaint(120, 60, new Color(215, 230, 252),
120, 300, Color.WHITE, false);
g2d.setPaint(plotGP);
drawArea = new Rectangle2D.Float(80, 30, plotWidth, plotHeight);
g2d.fill(drawArea);
// 描绘图表绘图区域的轮廓
bs = new BasicStroke(1.2f);
g2d.setStroke(bs);
g2d.setPaint(Color.BLACK);
g2d.draw(drawArea);
// 重新关闭反锯齿功能
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
}
// 绘制图表标题
public void drawTitle()
{
g2d.setFont(new Font("华文隶书", Font.PLAIN, 25));
int titleLength = g2d.getFontMetrics().stringWidth(chartTitle);
g2d.setColor(Color.WHITE);
g2d.drawString(chartTitle, (width - titleLength) / 2, 22);
}
// 绘制图表主体部分
public void drawChart()
{
// 获得当前的AffineTransform对象
AffineTransform old = g2d.getTransform();
g2d.translate(80, 30);
// 创建虚线笔划
float[]dashes = { 3.f };
BasicStroke bs = new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 10, dashes, 0);
g2d.setStroke(bs);
g2d.setFont(new Font("Courier New", Font.PLAIN, 12));
String str = "2004-";
int stringLength = 0, stringHeight = 0;
// 横轴上刻度值的数量
int xTickCounter = 12;
// 图表绘制区和纵轴之间的空白
int plotMargin = 10;
// 横轴上刻度值的长度
int hSpace = (plotWidth - 2 * plotMargin) / (xTickCounter - 1);
stringHeight = g2d.getFontMetrics().getAscent();
for (int i = 0; i < xTickCounter; i++)
{
// 绘制垂直方向虚线
g2d.setColor(new Color(103, 115, 133));
g2d.drawLine(plotMargin + i * hSpace, 0, plotMargin + i * hSpace,
plotHeight);
// 绘制横轴上刻度值的说明文字
str += i + 1;
stringLength = g2d.getFontMetrics().stringWidth(str);
g2d.setColor(Color.YELLOW);
if (i % 2 == 0)
{
g2d.drawString(str, plotMargin + i * hSpace - stringLength / 2,
plotHeight + stringHeight + 5);
}
str = "2004-";
}
str = "";
// 纵轴上刻度值的数量
int vTickCounter = 10;
// 纵轴上刻度值之间的空白
int vSpace = plotHeight / vTickCounter;
for (int i = 0; i < vTickCounter; i++)
{
// 绘制水平方向虚线
g2d.setColor(new Color(103, 115, 133));
g2d.drawLine(0, i * vSpace, plotWidth, i * vSpace);
// 绘制纵轴上刻度值的说明文字
str += plotHeight - i * vSpace;
stringLength = g2d.getFontMetrics().stringWidth(str);
g2d.setColor(Color.YELLOW);
g2d.drawString(str, - 5-stringLength, i * vSpace + stringHeight / 2);
str = "";
}
String[] bookTitle =
{
"Java类书籍", "C#类书籍"
};
Color[] bookColor =
{
Color.RED, Color.ORANGE
};
int[] sales = new int[xTickCounter];
int[] month = new int[xTickCounter];
g2d.setFont(new Font("Courier New", Font.PLAIN, 12));
for (int i = 0; i < bookTitle.length; i++)
{
// 初始化绘制数据
int bookSales = 0;
for (int j = 0; j < sales.length; j++)
{
sales[j] = plotHeight - (65+(int)(Math.random() * 220));
month[j] = plotMargin + j * hSpace;
}
// 重新设置笔划
g2d.setStroke(new BasicStroke(5.0f));
g2d.setColor(bookColor[i]);
// 绘制阴影
drawLineShadow(month, sales, thickness, alpha, bookColor[i], g2d);
// 绘制月销售量折线
g2d.drawPolyline(month, sales, sales.length);
}
// 恢复以前的AffineTransform对象
g2d.setTransform(old);
// 绘制坐标轴图例
drawLegend(bookTitle, bookColor);
}
// 绘制图例
public void drawLegend(String[]legendItems, Color[]color)
{
g2d.setStroke(new BasicStroke());
g2d.setFont(new Font("宋体", Font.PLAIN, 12));
g2d.setPaint(Color.WHITE);
int itemHeight = g2d.getFontMetrics().getAscent();
int itemWidth[] = new int[legendItems.length];
// 图例的长度
int legendWidth = 20;
for (int i = 0; i < legendItems.length; i++)
{
itemWidth[i] = g2d.getFontMetrics().stringWidth(legendItems[i]);
if (i != legendItems.length - 1)
{
legendWidth += itemWidth[i] + 20;
}
else
{
legendWidth += itemWidth[i] + 15;
}
}
g2d.fillRect((width - legendWidth) / 2, height - 25, legendWidth,
itemHeight + 5);
g2d.setColor(Color.BLACK);
g2d.drawRect((width - legendWidth) / 2, height - 25, legendWidth,
itemHeight + 5);
int itemAnchor = (width - legendWidth) / 2+10;
g2d.setColor(Color.BLACK);
for (int i = 0; i < legendItems.length; i++)
{
g2d.setColor(color[i]);
g2d.fillRect(itemAnchor, height - 20, 10, 10);
g2d.setColor(Color.BLACK);
g2d.drawString(legendItems[i], itemAnchor + 15, height - 12);
itemAnchor += itemWidth[i] + 20;
}
}
// 绘制坐标轴标题
public void drawAxisLabel()
{
g2d.setFont(new Font("楷体_GB2312", Font.BOLD, 18));
g2d.setPaint(new Color(255, 224, 193));
int labelHeight = g2d.getFontMetrics().getAscent();
int labelLength = g2d.getFontMetrics().stringWidth(yAxisLabel);
// 获得当前的AffineTransform对象
AffineTransform old = g2d.getTransform();
g2d.translate(40, (height + labelLength) / 2);
g2d.rotate( - Math.PI / 2);
g2d.drawString(yAxisLabel, 0, 0);
// 恢复以前的AffineTransform对象
g2d.setTransform(old);
labelLength = g2d.getFontMetrics().stringWidth(xAxisLabel);
g2d.drawString(xAxisLabel, (width - labelLength) / 2, 365);
}
// 绘制阴影
public void drawLineShadow(int xPoint[], int yPoint[], int thickness, int
alpha, Color color, Graphics2D g2d)
{
int shadowX[] = new int[xPoint.length];
int shadowY[] = new int[yPoint.length];
for (int i = thickness; i >= 0; i--)
{
if (i == thickness || i == 0)
{
g2d.setStroke(new BasicStroke(2.0f));
g2d.setColor(color.darker());
}
else
{
g2d.setStroke(new BasicStroke(4.0f));
g2d.setColor(color);
}
for (int j = 0; j < xPoint.length; j++)
{
shadowX[j] = xPoint[j] + getOffsetX(alpha, i);
shadowY[j] = yPoint[j] - getOffsetY(alpha, i);
}
g2d.drawPolyline(shadowX, shadowY, shadowX.length);
}
}
// 计算offsetX的值
public int getOffsetX(int alpha, int thickness)
{
return (int)(Math.cos(alpha * Math.PI / 180) * thickness + 0.5);
}
// 计算offsetY的值
public int getOffsetY(int alpha, int thickness)
{
return (int)(Math.sin(alpha * Math.PI / 180) * thickness + 0.5);
}
public void getChart()
{
// 部署图形环境
g2d.dispose();
// 输出图像到WEB页面
try
{
this.response.reset();
this.response.setContentType("image/png");
OutputStream sos = response.getOutputStream();
ImageIO.write(image, "PNG", sos);
sos.close();
}
catch (Exception e)
{
System.out.println("图表输出错误!");
}
}
}
/**************************************************************************
* (C) Copyright 2004-2005 by Jingkui Zhong(钟京馗) and Huan Tang(唐桓). *
* All Rights Reserved. *
* *
* DISCLAIMER: The authors of this code have used their *
* best efforts in preparing the code. These efforts include the *
* development, research, and testing of the theories and programs *
* to determine their effectiveness. The authors and publisher make *
* no warranty of any kind, expressed or implied, with regard to these *
* programs or to the documentation contained in these codes. The authors *
* shall not be liable in any event for incidental or consequential *
* damages in connection with, or arising out of, the furnishing, *
* performance, or use of these programs. *
**************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -