看到别人写的3D饼图,模仿了一个

2011-01-01 08:44

看到别人写的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> 人发表回复,猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
      </span>
      <br><br><br>

JavaEye推荐