java 饼图_Java:绘制有立体感的3D饼图2,鼠标可以选择饼图

该博客介绍了如何使用Java绘制具有3D立体效果的饼图,并实现了鼠标选择饼图的功能。通过`GeometryUtil`类进行几何计算,`Pie`类表示饼图组件,包括其各个部分的区域,而`Pie3DPainter`类用于在图形界面上绘制饼图并响应鼠标点击事件,展示3D饼图的交互效果。
摘要由CSDN通过智能技术生成

a4c26d1e5885305701be709a3d33442f.png

====================================GeometryUtil.java====================================

importjava.awt.geom.Point2D;

publicclassGeometryUtil

{

//

两点之间的距离

publicstaticdoubledistanceOfPoints(Point2D

p1, Point2D p2) {

doubledisX

= p2.getX() - p1.getX();

doubledisY

= p2.getY() - p1.getY();

doubledis

= Math.sqrt(disX * disX + disY * disY);

returndis;

}

//

两点的中点

publicstaticPoint2D

middlePoint(Point2D p1, Point2D p2) {

doublex

= (p1.getX() + p2.getX()) / 2;

doubley

= (p1.getY() + p2.getY()) / 2;

returnnewPoint2D.Double(x,

y);

}

//

在两点所在直线上,以从startPoint到endPoint为方向,离startPoint的距离disToStartPoint的点

publicstaticPoint2D

extentPoint(Point2D startPoint, Point2D endPoint,doubledisToStartPoint)

{

doubledisX

= endPoint.getX() - startPoint.getX();

doubledisY

= endPoint.getY() - startPoint.getY();

doubledis

= Math.sqrt(disX * disX + disY * disY);

doublesin

= (endPoint.getY() - startPoint.getY()) / dis;

doublecos

= (endPoint.getX() - startPoint.getX()) / dis;

doubledeltaX

= disToStartPoint * cos;

doubledeltaY

= disToStartPoint * sin;

returnnewPoint2D.Double(startPoint.getX()

+ deltaX, startPoint.getY() + deltaY);

}

}

====================================Pie.java====================================

importjava.awt.Color;

importjava.awt.geom.Arc2D;

importjava.awt.geom.Area;

importjava.awt.geom.GeneralPath;

importjava.awt.geom.Point2D;

classPie

{

privateArc2Darc;//

这里的弧并不是圆上的一弧,而是椭圆的一部分.

privateAreafrontSite;

privateArealeftSite;

privateArearightSite;

privateColorcolor;

privatePieselectedPie;

privatePoint2DarcMiddle;

privatePoint2DlabelPosition;

privatedoublevalue;

privateintshadowDepth;

privatedoubleselectedShiftDis;//

被选中的饼图在他的中线上移动的距离

publicPie(Arc2D

arc, Color color,doublevalue)

{

this(arc,

color, value, 10, 30);

}

publicPie(Arc2D

arc, Color color,doublevalue,intshadowDepth,doubleselectedShiftDis)

{

this.arc=

arc;

this.color=

color;

this.value=

value;

this.selectedShiftDis=

selectedShiftDis;

this.shadowDepth=

shadowDepth;

Arc2D arcBottom =newArc2D.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 site

GeneralPath font =newGeneralPath();

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.frontSite=newArea(arcBottom);

this.frontSite.add(newArea(font));

//

Left site

GeneralPath left =newGeneralPath();

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() +

3);

left.closePath();

this.leftSite=newArea(left);

//

Right site

GeneralPath right =newGeneralPath();

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() +

3);

right.closePath();

this.rightSite=newArea(right);

arcMiddle=

calculateArcMiddle();

//

Label position: 五分之四处

Point2D c = getPieCenter();

//

Point2D m = getChordMiddle();

Point2D m =arcMiddle;

doubledis

= GeometryUtil.distanceOfPoints(c, m) * 0.8;

labelPosition=

GeometryUtil.extentPoint(c, m, dis);

}

//

取得Arc上的三个点,在对Arc: center, left, right.

publicstaticPoint2D[]

getPointsOfArc(Arc2D arc) {

Point2D center =newPoint2D.Double(arc.getCenterX(),

arc.getCenterY());

Point2D left = arc.getStartPoint();

Point2D right = arc.getEndPoint();

Point2D[] points =newPoint2D[]

{ center, left, right };

returnpoints;

}

publicPie

getSelectedPie() {

if(selectedPie==null)

{

selectedPie=

createSeletecdPie();

}

returnselectedPie;

}

privatePie

createSeletecdPie() {

//

沿中线方向移动selectedShiftDis个单位

Point2D c = getPieCenter();

Point2D m = getChordMiddle();

Point2D p = GeometryUtil.extentPoint(c,

m,selectedShiftDis);

doubledeltaX

= p.getX() - c.getX();

doubledeltaY

= p.getY() - c.getY();

doublex

=arc.getX()

+ deltaX;

doubley

=arc.getY()

+ deltaY;

Arc2D shiftArc = (Arc2D)arc.clone();

shiftArc.setFrame(x, y,arc.getWidth(),arc.getHeight());

returnnewPie(shiftArc,color,value,shadowDepth,selectedShiftDis);

}

publicArc2D

getArc() {

returnarc;

}

publicArea

getFrontSite() {

returnfrontSite;

}

publicArea

getLeftSite() {

returnleftSite;

}

publicArea

getRightSite() {

returnrightSite;

}

publicColor

getColor() {

returncolor;

}

publicvoidsetColor(Color

color) {

this.color=

color;

}

publicPoint2D

getLabelPosition() {

returnlabelPosition;

}

publicvoidsetLabelPosition(Point2D

labelPosition) {

this.labelPosition=

labelPosition;

}

publicdoublegetValue()

{

returnvalue;

}

publicString

getLabel() {

returnvalue+"%";

}

//

弦的中心点

publicPoint2D

getChordMiddle() {

returnGeometryUtil.middlePoint(arc.getStartPoint(),arc.getEndPoint());

}

//

饼图的圆心

publicPoint2D

getPieCenter() {

returnnewPoint2D.Double(arc.getCenterX(),arc.getCenterY());

}

//

弧上的中心点

publicPoint2D

getArcMiddle() {

returnarcMiddle;

}

privatePoint2D

calculateArcMiddle() {

//

创建一个新的弧,其扩展角度为当前弧的一半

returnnewArc2D.Double(arc.getX(),arc.getY(),arc.getWidth(),arc.getHeight(),

arc.getAngleStart(),arc.getAngleExtent()

/ 2, Arc2D.PIE).getEndPoint();

}

}

====================================Pie3DPainter.java====================================

importjava.awt.Color;

importjava.awt.FontMetrics;

importjava.awt.Graphics;

importjava.awt.Graphics2D;

importjava.awt.RenderingHints;

importjava.awt.Toolkit;

importjava.awt.event.MouseAdapter;

importjava.awt.event.MouseEvent;

importjava.awt.geom.Arc2D;

importjava.util.ArrayList;

importjava.util.List;

importjavax.swing.JFrame;

importjavax.swing.JPanel;

@SuppressWarnings("serial")

publicclassPie3DPainterextendsJPanel

{

privatedouble[]data;//

在饼图中显示的数据

privateColor[]defaultColors;//

预定义饼图的颜色

privatePie[]pies;

privateintshadowDepth=

8;

privateintshiftAngle=

-30;

privateintselectedPieIndex=

-1;//

鼠标点击是选中的Arc, -1为没有选中

publicPie3DPainter()

{

data=newdouble[]

{ 20.72, 6.56, 3.74, 10.26, 15.38, 5.69, 10.72, 15.38, 6.15, 18.0

};

defaultColors=

createColors();

intx

= 50;

inty

= 50;

intw

= 380;

inth

= (int)

(w * 0.618);//

黄金分割

pies=

createPies(x, y, w, h,shadowDepth,shiftAngle,data,defaultColors);

//

取得鼠标选中的饼图的下标

addMouseListener(newMouseAdapter()

{

@Override

publicvoidmouseClicked(MouseEvent

e) {

selectedPieIndex=

-1;

for(inti

= 0; i <

class=Apple-converted-space> pies.length;

++i) {

if(pies[i].getArc().contains(e.getX(),

e.getY())) {

selectedPieIndex=

i;

break;

}

}

repaint();

}

});

}

privateColor[]

createColors() {

//

返回16进制的值颜色

List colors =newArrayList();

colors.add(Color.decode("#FF7321"));

colors.add(Color.decode("#169800"));

colors.add(Color.decode("#00E500"));

colors.add(Color.decode("#D0F15A"));

colors.add(Color.decode("#AA6A2D"));

colors.add(Color.decode("#BFDD89"));

colors.add(Color.decode("#E2FF55"));

colors.add(Color.decode("#D718A5"));

colors.add(Color.decode("#00DBFF"));

colors.add(Color.decode("#00FF00"));

returncolors.toArray(newColor[0]);

}

publicstaticPie[]

createPies(intx,

inty,

intw,

inth,

intshadowDepth,

doubleshiftAngle,

double[]

data,

Color[]

colors) {

doublesum

= 0;

for(doubled

: data) {

sum +=

d;

}

//

初始化Pies

doublearcAngle

= 0;

doublestartAngle

= shiftAngle;

Pie[] pies =newPie[data.length];

for(inti

= 0; i < data.length;

++i) {

arcAngle =

data[i] * 360 / sum;//

使用百分比计算角度

if(i

+ 1 == data.length)

{

arcAngle = 360 + shiftAngle -

startAngle;//

保证闭合

arcAngle = arcAngle > 0 ?

arcAngle : 0;

}

Arc2D.Double arc =newArc2D.Double(x,

y, w, h, startAngle, arcAngle, Arc2D.PIE);

pies[i]

=newPie(arc,

colors[i % colors.length],

data[i], shadowDepth, 30);

startAngle

+= arcAngle;

}

returnpies;

}

@Override

protectedvoidpaintComponent(Graphics

g) {

super.paintComponent(g);

Graphics2D g2d = (Graphics2D) g;

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

if(pies!=null)

{

drawPies(g2d,pies,selectedPieIndex);

}

}

privatevoiddrawPies(Graphics2D

g2d, Pie[] pies,intselectedIndex)

{

intstartIndex

= 0;//

从第几个饼图开始绘制

intendIndex

= pies.length;//

要画的饼图的数量.

booleanclosed

= (endIndex - startIndex == pies.length)

?true:false;

booleanselected

= (selectedIndex >= startIndex && selectedIndex <

endIndex) ?true:false;

FontMetrics metrics = g2d.getFontMetrics();

//

一次性绘制完3D效果,然后再绘制饼图的效果比绘制饼图的同时绘制好

for(inti

= startIndex; i < endIndex; ++i) {

if(i

!= selectedIndex) {

Pie p = pies[i];

g2d.setColor(p.getColor().darker());

g2d.fill(p.getFrontSite());

}

}

//

如果没有闭合时,且选中的不是第一块,则第一块画左面

if(!closed

&& selectedIndex != startIndex) {

g2d.setColor(pies[startIndex].getColor().darker());

g2d.fill(pies[startIndex].getLeftSite());

}

//

如果没有闭合时,且选中的不是最后一块,则最后一块画右面

if(!closed

&& selectedIndex + 1 != endIndex) {

g2d.setColor(pies[endIndex - 1].getColor().darker());

g2d.fill(pies[endIndex - 1].getRightSite());

}

//

有饼图被选中

if(selected)

{

intprevIndex

= selectedIndex > startIndex ? (selectedIndex - 1) : endIndex -

1;

intnextIndex

= (selectedIndex + 1) >= endIndex ? startIndex : (selectedIndex

+ 1);

//

前一个画右墙

g2d.setColor(pies[prevIndex].getColor().darker());

g2d.fill(pies[prevIndex].getRightSite());

//

后一个画左墙

g2d.setColor(pies[nextIndex].getColor().darker());

g2d.fill(pies[nextIndex].getLeftSite());

}

//

最后再绘制饼图的上面部分,把不需要的部分隐藏掉

for(inti

= startIndex; i < endIndex; ++i) {

if(i

!= selectedIndex) {

Pie p = pies[i];

g2d.setColor(p.getColor());

g2d.fill(p.getArc());

intsw

= metrics.stringWidth(p.getLabel()) / 2;

intsh

= (metrics.getAscent()) / 2;

intx

= (int)

(p.getLabelPosition().getX() - sw);

inty

= (int)

(p.getLabelPosition().getY() + sh);

g2d.setColor(Color.BLACK);

g2d.drawString(p.getLabel(),

x, y);

}

}

//

绘制被选中的饼图

if(selected)

{

Pie p =

pies[selectedIndex].getSelectedPie();

g2d.setColor(p.getColor().darker());

g2d.fill(p.getFrontSite());

g2d.fill(p.getLeftSite());

g2d.fill(p.getRightSite());

g2d.setColor(p.getColor());

g2d.fill(p.getArc());

intsw

= metrics.stringWidth(p.getLabel()) / 2;

intsh

= (metrics.getAscent()) / 2;

intx

= (int)

(p.getLabelPosition().getX() - sw);

inty

= (int)

(p.getLabelPosition().getY() + sh);

g2d.setColor(Color.BLACK);

g2d.drawString(p.getLabel(), x, y);

}

}

privatestaticvoidcreateGuiAndShow()

{

JFrame frame =newJFrame("Pie

with 3D Effect");

frame.getContentPane().add(newPie3DPainter());

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

intsw

= Toolkit.getDefaultToolkit().getScreenSize().width;

intsh

= Toolkit.getDefaultToolkit().getScreenSize().height;

intw

= 500;

inth

= 400;

intx

= (sw - w) / 2;

inty

= (sh - h) / 2 - 40;

x = x > 0 ? x : 0;

y = y > 0 ? y : 0;

frame.setBounds(x, y, w, h);

frame.setVisible(true);

}

publicstaticvoidmain(String[]

args) {

createGuiAndShow();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值