看到别人写的3D饼图,模仿了一个
by
at 2011-01-01 00:44:15
original http://www.javaeye.com/topic/857245
鼠标点击饼图时,被点击的部分会移动出来。
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[i].getArc().contains(e.getX(), e.getY())) { selectedIndex = i; break; } } repaint(); } }); } private void initColors() { List<Color> colors = new ArrayList<Color>(); 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[i] * 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[i]); 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[i].getColor().darker()); g2d.fill(pies[i].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[i]; 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("Pie 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]; }}
<br><br>
作者: <a href="http://jorneyr.javaeye.com">jorneyR</a>
<br>
声明: 本文系JavaEye网站发布的原创文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!
<br><br>
<span style="color:red">
<a href="http://www.javaeye.com/topic/857245" style="color:red">已有 <strong>4</strong> 人发表回复,猛击->><strong>这里</strong><<-参与讨论</a>
</span>
<br><br><br>
JavaEye推荐