|
鼠标点击饼图时,被点击的部分会移动出来。
代码:
package test;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Arc2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 绘制3D效果的饼图
*
* @author Biao
*/
@SuppressWarnings("serial")
public class Pies3D extends JPanel {
// 在饼图中显示的数据
private double[] data = { 10.72, 15.38, 3.74, 10.26, 6.56, 5.69, 10.72, 15.38, 6.15, 18.0 };
private Color[] defaultColors; // 预定义饼图的颜色
private Pie[] pies;
private int shadowDepth = 8;
int selectedIndex = -1; // 鼠标点击是选中的Arc, -1为没有选中
public Pies3D() {
initColors();
initPies(data, defaultColors, shadowDepth);
// 取得鼠标选中的饼图: arc
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
selectedIndex = -1;
for (int i = 0; i < pies.length; ++i) {
if (pies.getArc().contains(e.getX(), e.getY())) {
selectedIndex = i;
break;
}
}
repaint();
}
});
}
private void initColors() {
List colors = new ArrayList();
colors.add(getColorFromHex("#FF7321"));
colors.add(getColorFromHex("#169800"));
colors.add(getColorFromHex("#00E500"));
colors.add(getColorFromHex("#D0F15A"));
colors.add(getColorFromHex("#AA6A2D"));
colors.add(getColorFromHex("#BFDD89"));
colors.add(getColorFromHex("#E2FF55"));
colors.add(getColorFromHex("#D718A5"));
colors.add(getColorFromHex("#00DBFF"));
colors.add(getColorFromHex("#00FF00"));
defaultColors = colors.toArray(new Color[0]);
}
public void initPies(double[] data, Color[] colors, int shadowDepth) {
double sum = 0;
for (double d : data) {
sum += d;
}
// 初始化Pies
List< Arc2D> arcList = new ArrayList< Arc2D>();
List< Pie> pieList = new ArrayList< Pie>();
double arcAngle = 0;
int x = 50;
int y = 50;
int w = 380;
int h = (int) (w * 0.618);
int startAngle = 30;
int sumAngle = 0;
for (int i = 0; i < data.length; ++i) {
arcAngle = data * 360 / sum;
if (i + 1 == data.length && sumAngle < 360) {
arcAngle = 360 - sumAngle;
}
Arc2D.Double arc = new Arc2D.Double(x, y, w, h, startAngle, arcAngle, Arc2D.PIE);
arcList.add(arc);
Pie pie = new Pie(arc, colors[i % colors.length], shadowDepth, data);
pieList.add(pie);
sumAngle += arcAngle;
startAngle += arcAngle;
}
pies = pieList.toArray(new Pie[0]);
}
public static Color getColorFromHex(String hex) {
try {
return new Color(Integer.valueOf(hex.substring(1), 16));
} catch (Exception e) {
return Color.BLACK;
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
showPies(g2d);
}
private void showPies(Graphics2D g2d) {
int startIndex = 0; // 从第几个饼图开始绘制
int endIndex = pies.length; // 要画的饼图的数量.
// 一次性绘制完3D效果,然后再绘制饼图的效果比绘制饼图的同时绘制好
for (int i = startIndex; i < endIndex; ++i) {
if (i != selectedIndex) {
g2d.setColor(pies.getColor().darker());
g2d.fill(pies.getFrontWall());
}
}
// 第一个和最后一个要特殊处理
if (selectedIndex != startIndex) {
g2d.setColor(pies[startIndex].getColor().darker());
g2d.fill(pies[startIndex].getLeftWall());
}
if (selectedIndex != endIndex - 1) {
g2d.setColor(pies[endIndex - 1].getColor().darker());
g2d.fill(pies[endIndex - 1].getRightWall());
}
// 绘制选中的Arc前一个与后一个的墙
if (selectedIndex != -1) {
int previousIndex = selectedIndex > startIndex ? (selectedIndex - 1) : endIndex - 1;
int nextIndex = (selectedIndex + 1) >= endIndex ? startIndex : (selectedIndex + 1);
// 前一个画右墙
g2d.setColor(pies[previousIndex].getColor().darker());
g2d.fill(pies[previousIndex].getRightWall());
// 后一个画左墙
g2d.setColor(pies[nextIndex].getColor().darker());
g2d.fill(pies[nextIndex].getLeftWall());
}
FontMetrics metrics = g2d.getFontMetrics();
// 绘制饼图,把不需要的部分隐藏掉
for (int i = startIndex; i < endIndex; ++i) {
if (i != selectedIndex) {
Pie p = pies;
g2d.setColor(p.getColor());
g2d.fill(p.getArc());
String value = p.getValue() + "%";
int w = metrics.stringWidth(value) / 2;
g2d.setColor(Color.BLACK);
g2d.drawString(value, (int) (p.getLabelPosition().getX() - w),
(int) (p.getLabelPosition().getY()));
}
}
// 绘制被选中的饼图
if (selectedIndex != -1) {
Pie p = pies[selectedIndex].getSelectedPie();
g2d.setColor(p.getColor().darker());
g2d.fill(p.getFrontWall());
g2d.fill(p.getLeftWall());
g2d.fill(p.getRightWall());
g2d.setColor(p.getColor());
g2d.fill(p.getArc());
String value = p.getValue() + "%";
int w = metrics.stringWidth(value) / 2;
g2d.setColor(Color.BLACK);
g2d.drawString(value, (int) (p.getLabelPosition().getX() - w),
(int) (p.getLabelPosition().getY()));
}
}
private static void createGuiAndShow() {
JFrame frame = new JFrame("ie with 3D Effect");
frame.getContentPane().add(new Pies3D());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int sw = Toolkit.getDefaultToolkit().getScreenSize().width;
int sh = Toolkit.getDefaultToolkit().getScreenSize().height;
int w = 500;
int h = 400;
int x = (sw - w) / 2;
int y = (sh - h) / 2 - 40;
x = x > 0 ? x : 0;
y = y > 0 ? y : 0;
frame.setBounds(x, y, w, h);
frame.setVisible(true);
}
public static void main(String[] args) {
createGuiAndShow();
}
}
package test;
import java.awt.Color;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
class Pie {
private Arc2D arc;
private Area frontWall;
private Area leftWall;
private Area rightWall;
private Color color;
private int shadowDepth;
private Pie selectedPie;
private Point2D labelPosition;
private double shiftDis = 8; // 被选中的饼图在他的中线上移动的距离
private double value;
public Pie(Arc2D arc, Color color, int shadowDepth, double value) {
this.arc = arc;
this.color = color;
this.value = value;
this.shadowDepth = shadowDepth;
Arc2D arcBottom = new Arc2D.Double(arc.getX(), arc.getY() + shadowDepth, arc.getWidth(),
arc.getHeight() + 0, arc.getAngleStart(), arc.getAngleExtent(), Arc2D.CHORD);
Point2D[] topPs = getPointsOfArc(arc);
Point2D[] bottomPs = getPointsOfArc(arcBottom);
// Front wall
GeneralPath font = new GeneralPath();
font.moveTo(topPs[1].getX(), topPs[1].getY());
font.lineTo(topPs[2].getX(), topPs[2].getY());
font.lineTo(bottomPs[2].getX(), bottomPs[2].getY());
font.lineTo(bottomPs[1].getX(), bottomPs[1].getY());
font.closePath();
this.frontWall = new Area(arcBottom);
this.frontWall.add(new Area(font));
// Left wall
GeneralPath left = new GeneralPath();
left.moveTo(topPs[0].getX(), topPs[0].getY());
left.lineTo(topPs[1].getX(), topPs[1].getY());
left.lineTo(bottomPs[1].getX(), bottomPs[1].getY());
left.lineTo(topPs[0].getX(), topPs[0].getY());
left.closePath();
this.leftWall = new Area(left);
// Right wall
GeneralPath right = new GeneralPath();
right.moveTo(topPs[0].getX(), topPs[0].getY());
right.lineTo(topPs[2].getX(), topPs[2].getY());
right.lineTo(bottomPs[2].getX(), bottomPs[2].getY());
right.lineTo(topPs[0].getX(), topPs[0].getY());
right.closePath();
this.rightWall = new Area(right);
// Label position: 四分之三处
Point2D c = getArcCenter();
Point2D m = getChordCenter();
double x = ((m.getX() + c.getX()) / 2 + m.getX()) / 2;
double y = ((m.getY() + c.getY()) / 2 + m.getY()) / 2;
labelPosition = new Point2D.Double(x, y);
}
// 取得Arc上的三个点,在对Arc: center, left, right.
public static Point2D[] getPointsOfArc(Arc2D arc) {
Point2D[] points = new Point2D[3];
Point2D center = new Point2D.Double(arc.getCenterX(), arc.getCenterY());
Point2D left = new Point2D.Double(arc.getStartPoint().getX(), arc.getStartPoint().getY());
Point2D right = new Point2D.Double(arc.getEndPoint().getX(), arc.getEndPoint().getY());
points[0] = center;
points[1] = left;
points[2] = right;
return points;
}
public Pie getSelectedPie() {
if (selectedPie == null) {
selectedPie = createSeletecdPie();
}
return selectedPie;
}
private Pie createSeletecdPie() {
// 沿中线方向移动5个单位
Point2D[] ps = getPointsOfArc(arc);
Point2D c = ps[0];
Point2D m = new Point2D.Double((ps[1].getX() + ps[2].getX()) / 2,
(ps[1].getY() + ps[2].getY()) / 2);
double dis = Math.sqrt((m.getX() - c.getX()) * (m.getX() - c.getX())
+ (m.getY() - c.getY()) * (m.getY() - c.getY()));
double deltaX = shiftDis * (m.getX() - c.getX()) / dis;
double deltaY = shiftDis * (m.getY() - c.getY()) / dis;
Arc2D shiftArc = (Arc2D) arc.clone();
shiftArc
.setFrame(arc.getX() + deltaX, arc.getY() + deltaY, arc.getWidth(), arc.getHeight());
return new Pie(shiftArc, color, shadowDepth, value);
}
public Arc2D getArc() {
return arc;
}
public void setArc(Arc2D arc) {
this.arc = arc;
}
public Area getFrontWall() {
return frontWall;
}
public void setFrontWall(Area frontWall) {
this.frontWall = frontWall;
}
public Area getLeftWall() {
return leftWall;
}
public void setLeftWall(Area leftWall) {
this.leftWall = leftWall;
}
public Area getRightWall() {
return rightWall;
}
public void setRightWall(Area rightWall) {
this.rightWall = rightWall;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Point2D getLabelPosition() {
return labelPosition;
}
public void setLabelPosition(Point2D labelPosition) {
this.labelPosition = labelPosition;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public Point2D getChordCenter() {
Point2D[] ps = getPointsOfArc(arc);
Point2D m = new Point2D.Double((ps[1].getX() + ps[2].getX()) / 2,
(ps[1].getY() + ps[2].getY()) / 2);
return m;
}
public Point2D getArcCenter() {
Point2D[] ps = getPointsOfArc(arc);
return ps[0];
}
} |
|