功能说明:
1、当鼠标移入饼图块时,该块位置发生偏移。
2、鼠标离开后,该块回复到原来位置。
先看效果图:
实现技巧: 1、计算鼠标所在块的偏移角度。 从上图中可以看出:在javafx中,第一个数据块的位置从0开始,按逆时针方向一次排列。 因此数据块的偏移角度为,它之前所有数据块的角度之和,再加上本身所占角度的一半。
2、数据块角度的计算。 可以根据数据块所占数据的百分比计算对应的角度。 参考以下代码:
private static double calcAngle(PieChart.Data d) { double total = 0; for (PieChart.Data tmp : d.getChart().getData()) { total += tmp.getPieValue(); } return 360 * (d.getPieValue() / total); }
3、注意y坐标的计算,由于fx的y轴和直角坐标系相反,所以移动y坐标要取反。
全部源码:
public class PieChartSample extends Application {
@Override
public void start(Stage primaryStage) {
BorderPane p = new BorderPane();
ObservableList pieChartData = FXCollections
.observableArrayList(new PieChart.Data("Austria", 8_430_558),
new PieChart.Data("Swiss", 7_701_900),
new PieChart.Data("Germany", 81_882_342),
new PieChart.Data("France", 62_793_432),
new PieChart.Data("Spain", 46_661_950),
new PieChart.Data("Italy", 60_245_846));
PieChart chart = new PieChart(pieChartData);
// chart.setStyle("-fx-pie-label-visible: false");
for (PieChart.Data d : pieChartData) {
d.getNode().setOnMouseEntered(new MouseHoverAnimation(d, chart));
d.getNode().setOnMouseExited(new MouseExitAnimation());
}
chart.setClockwise(false);
p.setCenter(chart);
Scene s = new Scene(p);
primaryStage.setScene(s);
primaryStage.setWidth(600);
primaryStage.setHeight(600);
primaryStage.setTitle("动态饼图");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
static class MouseHoverAnimation implements EventHandler {
static final Duration ANIMATION_DURATION = new Duration(500);
static final double ANIMATION_DISTANCE = 0.15;
private double cos;
private double sin;
private PieChart chart;
public MouseHoverAnimation(PieChart.Data d, PieChart chart) {
this.chart = chart;
double start = 0;
double angle = calcAngle(d);
for (PieChart.Data tmp : chart.getData()) {
if (tmp == d) {
break;
}
start += calcAngle(tmp);
}
cos = Math.cos(Math.toRadians(start + angle / 2));
sin = Math.sin(Math.toRadians(start + angle / 2));
}
@Override
public void handle(MouseEvent arg0) {
Node n = (Node) arg0.getSource();
double minX = Double.MAX_VALUE;
double maxX = Double.MAX_VALUE * -1;
for (PieChart.Data d : chart.getData()) {
minX = Math
.min(minX, d.getNode().getBoundsInParent().getMinX());
maxX = Math
.max(maxX, d.getNode().getBoundsInParent().getMaxX());
}
double radius = maxX - minX;
System.out.println("cos:" + cos);
System.out.println("sin" + sin);
TranslateTransitionBuilder.create()
.toX((radius * ANIMATION_DISTANCE) * cos)
.toY((radius * ANIMATION_DISTANCE) * (-sin))
.duration(ANIMATION_DURATION).node(n).build().play();
}
private static double calcAngle(PieChart.Data d) {
double total = 0;
for (PieChart.Data tmp : d.getChart().getData()) {
total += tmp.getPieValue();
}
return 360 * (d.getPieValue() / total);
}
}
static class MouseExitAnimation implements EventHandler {
@Override
public void handle(MouseEvent event) {
TranslateTransitionBuilder.create().toX(0).toY(0)
.duration(new Duration(500)).node((Node) event.getSource())
.build().play();
}
}
}
<script type="text/javascript" id="gdt-72058698036477044|discuz_22913820_001"> var TencentGDT = TencentGDT || []; TencentGDT.push(['72058698036477044|discuz_22913820_001',960,90,'graphic']); (function() { var doc=document, h=doc.getElementsByTagName('head')[0], s=doc.createElement('script'); s.async=true; s.src='http://qzs.qq.com/qzone/biz/res/q.js'; h && h.insertBefore(s,h.firstChild)})(); </script>