數據可視化是現代應用的核心需求,3D立體餅圖以其直觀的視覺效果,成為數據展示的熱門選擇。本文將深度解析基於Java 2D/3D API實現逼真立體餅圖的完整方案,涵蓋數據處理、幾何計算、渲染管線、交互設計等全方位技術細節,並提供完整可運行的源碼示例。
立體餅圖本質是橢圓柱體的切片投影。橢圓參數方程:
x = centerX + a * cos(θ) y = centerY + b * sin(θ)
其中a、b為長短半軸,θ為參數角度。立體效果通過繪製多層橢圓偏移實現。
每個扇區對應一個Arc2D.PIE,關鍵參數:
startAngleextentAngle(數值比例 × 360°)Ellipse2D.Float(x, y, width, height)
// 輸入數據
double[] data = {100, 50, 113, 127, 299.234, 120, 93, 123, 127, 199, 157, 189};
// 計算總和
double sum = Arrays.stream(data).sum();
// 計算百分比
double[] percent = new double[data.length];
for (int i = 0; i < data.length; i++) {
percent[i] = data[i] / sum * 100;
}
// 計算角度
int[] angles = new int[data.length];
for (int i = 0; i < data.length; i++) {
angles[i] = (int) Math.round(data[i] / sum * 360);
}
// 透明度設置
int alpha = 200; // 0-255
Color[] colors = new Color[]{
new Color(0, 255, 0, alpha),
new Color(255, 255, 0, alpha),
new Color(255, 0, 0, alpha),
// ... 更多顏色
};
@Override
public void update(Graphics g) {
paint(g);
}
@Override
public void paint(Graphics g) {
// 雙緩衝
if (offScreenImage == null) {
offScreenImage = createImage(getWidth(), getHeight());
offScreenGraphics = offScreenImage.getGraphics();
}
paintBackground(offScreenGraphics);
paintChart(offScreenGraphics);
g.drawImage(offScreenImage, 0, 0, this);
}
private void paintBackground(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// 抗鋸齒
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 漸變背景
GradientPaint gradient = new GradientPaint(0, 0, Color.WHITE, 0, 400, new Color(162, 189, 230));
g2.setPaint(gradient);
g2.fill(new Rectangle2D.Double(0, 0, width, height));
// 標題背景
g2.setColor(new Color(147, 179, 225));
g2.fill3DRect(0, 0, width, 30, true);
}
private void paintChart(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 繪製立體底部陰影層
for (int t = 20; t >= 0; t--) {
int gray = t * 255 / 20;
g2.setColor(new Color(gray, gray, gray, 50));
g2.drawOval(ovalX, ovalY + t, longAxis, shortAxis);
}
// 繪製各扇區
int startAngle = 0;
for (int i = 0; i < data.length; i++) {
Arc2D pie = new Arc2D.Float(Arc2D.PIE);
pie.setFrame(ovalX, ovalY, longAxis, shortAxis);
pie.setAngleStart(startAngle);
pie.setAngleExtent(angles[i]);
// 填充扇區
g2.setColor(colors[i]);
g2.fill(pie);
// 繪製邊框
if (data[i] == maxValue || data[i] == minValue) {
g2.setColor(Color.WHITE);
} else {
g2.setColor(new Color(223, 223, 223, 150));
}
g2.draw(pie);
startAngle += angles[i];
}
}
private void paintLegend(Graphics2D g2) {
int x = legendX, y = legendY;
int blockSize = 15, gap = 5;
for (int i = 0; i < data.length; i++) {
// 顏色塊
g2.setColor(colors[i]);
g2.fill3DRect(x, y, blockSize, blockSize, true);
// 數值標籤
if (data[i] == maxValue || data[i] == minValue) {
g2.setColor(Color.RED);
} else {
g2.setColor(Color.WHITE);
}
g2.drawString(data[i] + " (" + percent[i] + "%)", x + blockSize + 5, y + blockSize - 2);
y += blockSize + 5;
}
}
public void init() {
// 雙緩衝初始化
offScreenImage = createImage(width, height);
offScreenGraphics = offScreenImage.getGraphics();
// 預計算數據
calculateData();
calculateCoordinates();
}
public void update(Graphics g) {
paint(g); // 避免默認清屏閃爍
}
public void paint(Graphics g) {
// 雙緩衝
paintBackground(offScreenGraphics);
paintChart(offScreenGraphics);
g.drawImage(offScreenImage, 0, 0, this);
}
<html>
<head>
<title>3D立體餅圖演示</title>
</head>
<body>
<applet code="PieChart3D.class" width="800" height="600">
<param name="data" value="100,50,113,127,299,120,93,123,127,199,157,189">
<param name="labels" value="A,B,C,D,E,F,G,H,I,J,K,L">
<param name="colors" value="00FF00,FFFF00,FF0000,FF8040,FF80FF,FF0080,E97C18,CC7773,599FE6,948CB3,800040,AEB5D0">
</applet>
</body>
| 庫 | 特點 | 許可證 |
|---|---|---|
| JFreeChart | 功能最全、社區活躍、支援多種圖表 | LGPL |
| XChart | 輕量、現代API、支援多種輸出格式 | Apache 2.0 |
| JavaFX Charts | 原生JavaFX支援、CSS樣式、動畫豐富 | BSD |
| ECharts Java | ECharts Java綁定、Web集成友好 | Apache 2.0 |
chart-project/ ├── src/ │ ├── main/java/com/example/chart/ │ │ ├── model/ # 數據模型 │ │ ├── render/ # 渲染引擎 │ │ ├── ui/ # UI組件 │ │ └── util/ # 工具類 │ └── resources/ │ └── colors.properties ├── test/ └── pom.xml