设置条形图列宽度大小

时间:2014-12-04 19:55:23

标签: javafx javafx-2 javafx-8

有没有办法设置JavaFX条形图列的宽度大小?

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

public class BarChartSample extends Application {
    final static String austria = "Austria";
    final static String brazil = "Brazil";
    final static String france = "France";
    final static String italy = "Italy";
    final static String usa = "USA";

    @Override public void start(Stage stage) {
        stage.setTitle("Bar Chart Sample");
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        final BarChart<String,Number> bc = 
            new BarChart<String,Number>(xAxis,yAxis);
        bc.setTitle("Country Summary");
        xAxis.setLabel("Country");       
        yAxis.setLabel("Value");

        XYChart.Series series1 = new XYChart.Series();
        series1.setName("2003");       
        series1.getData().add(new XYChart.Data(austria, 25601.34));
        series1.getData().add(new XYChart.Data(brazil, 20148.82));
        series1.getData().add(new XYChart.Data(france, 10000));
        series1.getData().add(new XYChart.Data(italy, 35407.15));
        series1.getData().add(new XYChart.Data(usa, 12000));      

        XYChart.Series series2 = new XYChart.Series();
        series2.setName("2004");
        series2.getData().add(new XYChart.Data(austria, 57401.85));
        series2.getData().add(new XYChart.Data(brazil, 41941.19));
        series2.getData().add(new XYChart.Data(france, 45263.37));
        series2.getData().add(new XYChart.Data(italy, 117320.16));
        series2.getData().add(new XYChart.Data(usa, 14845.27));  

        XYChart.Series series3 = new XYChart.Series();
        series3.setName("2005");
        series3.getData().add(new XYChart.Data(austria, 45000.65));
        series3.getData().add(new XYChart.Data(brazil, 44835.76));
        series3.getData().add(new XYChart.Data(france, 18722.18));
        series3.getData().add(new XYChart.Data(italy, 17557.31));
        series3.getData().add(new XYChart.Data(usa, 92633.68));  

        Scene scene  = new Scene(bc,800,600);
        bc.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

例如,有一种设置setBarGap大小的方法,但我找不到设置条形图列的最大宽度的方法。

有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:5)

BarChart的工作原理是barGap(同一类别中的条形间隙)和categoryGap(不同类别中的条形间隙)都可以由用户设置,因此对于给定大小的图表,每次请求布局时,都会在内部计算条形的宽度。

要在每个条上设置最大宽度,我们必须相应地更改barGapcategoryGap。但我们可以通过编程方式进行,以响应图表宽度的任何变化。

让我们首先计算初始布局的条宽。根据{{​​1}}:

BarChart.layoutPlotChildren()

在OP提供的示例中,给定默认间隙值(double catSpace = xAxis.getCategorySpacing(); double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap()); double barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap(); barGap=4),得到的categoryGap=10为37.4。

我们假设我们要设置40的限制,最小类别差距为10:

barWidth

如果在调整场景大小时图表的宽度增加,我们可以通过增加double maxBarWidth=40; double minCategoryGap=10; 来限制barWidth

categoryGap

注意do-while循环:当我们修改double barWidth=0; do{ double catSpace = xAxis.getCategorySpacing(); double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap()); barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap(); if(barWidth > maxBarWidth){ avilableBarSpace=(maxBarWidth + bc.getBarGap())* bc.getData().size(); bc.setCategoryGap(catSpace-avilableBarSpace-bc.getBarGap()); } } while(barWidth>maxBarWidth); 时,会执行新的布局并且一些初始值会发生变化。通常需要两次迭代才能获得所需的结果。

只要图表的宽度不断增长,我们就可以重复此操作。

但是如果图表的宽度开始减小,那么类别之间的差距也应该减小,而条形宽度保持接近其最大值:

categoryGap

将所有内容放在一起,并聆听场景宽度变化:

double barWidth=0;
do{
    double catSpace = xAxis.getCategorySpacing();
    double avilableBarSpace = catSpace - (minCategoryGap + bc.getBarGap());
    barWidth = Math.min(maxBarWidth, (avilableBarSpace / bc.getData().size()) - bc.getBarGap());
    avilableBarSpace=(barWidth + bc.getBarGap())* bc.getData().size();
    bc.setCategoryGap(catSpace-avilableBarSpace-bc.getBarGap());
} while(barWidth < maxBarWidth && bc.getCategoryGap()>minCategoryGap);

请注意,在其他情况下, ... Scene scene = new Scene(bc,800,600); bc.getData().addAll(series1, series2, series3); stage.setScene(scene); stage.show(); double maxBarWidth=40; double minCategoryGap=10; scene.widthProperty().addListener((obs,n,n1)->{ if(bc.getData().size()==0) return; if(n!=null && (n1.doubleValue()>n.doubleValue())){ double barWidth=0; do{ double catSpace = xAxis.getCategorySpacing(); double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap()); barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap(); if (barWidth >maxBarWidth){ avilableBarSpace=(maxBarWidth + bc.getBarGap())* bc.getData().size(); bc.setCategoryGap(catSpace-avilableBarSpace-bc.getBarGap()); } } while(barWidth>maxBarWidth); } if(n!=null && (n1.doubleValue()<n.doubleValue()) && bc.getCategoryGap()>minCategoryGap){ double barWidth=0; do{ double catSpace = xAxis.getCategorySpacing(); double avilableBarSpace = catSpace - (minCategoryGap + bc.getBarGap()); barWidth = Math.min(maxBarWidth, (avilableBarSpace / bc.getData().size()) - bc.getBarGap()); avilableBarSpace=(barWidth + bc.getBarGap())* bc.getData().size(); bc.setCategoryGap(catSpace-avilableBarSpace-bc.getBarGap()); } while(barWidth < maxBarWidth && bc.getCategoryGap()>minCategoryGap); } }); 将在内部计算。

答案 1 :(得分:1)

继JoséPereda的回答之后。您可以根据数据集设置图表的宽度。与BarGap和CategoryGap设置器一起,您可以通过计算或反复试验来微调条的宽度。例如,我做了以下以获得更薄的条。我将空图的宽度设置为30(对于轴和标签??)然后为cribbage游戏中的每一轮添加100px到最大和最小宽度(最大为网格窗格宽度)从而限制了自由图表中的空格用于填充条形图。

 Pane barchart1 = new Pane;
 CategoryAxis xAxis = new CategoryAxis();
 NumberAxis yAxis = new NumberAxis(0,25,1);
 BarChart<String, Number> bc1 =
        new BarChart<String, Number>(xAxis, yAxis);
    // create Player chart
    bc1.setTitle(G.getPlayerName(0));
    bc1.setTitle(null);
    xAxis1.setLabel("Round");
    yAxis1.setLabel("Points");
    XYChart.Series series1 = new XYChart.Series();
    series1.setName("Pegging");
    XYChart.Series series3 = new XYChart.Series();
    series3.setName("Hand");
    XYChart.Series series5 = new XYChart.Series();
    series5.setName("Box");

    for (int i = 0; i < G.getRoundsSize(); i++) {
        series1.getData().add(new XYChart.Data(Integer.toString(i + 1), G.getRound(i).getPlayerRoundData(0).getPegPoints()));
        series3.getData().add(new XYChart.Data(Integer.toString(i + 1), G.getRound(i).getPlayerRoundData(0).getHandPoints()));
        series5.getData().add(new XYChart.Data(Integer.toString(i + 1), G.getRound(i).getPlayerRoundData(0).getBoxPoints()));
    }
    bc1.getData(). addAll(series1, series3, series5);
    bc1.setBarGap(0);
    bc1.setCategoryGap(1.0);
    bc1.setMaxHeight(180);
    bc1.setMinHeight(180);
    if(G.getRoundsSize() < 8){
        int wid = ((G.getRoundsSize() * 100) + 30);
        bc1.setMaxWidth(wid);
        bc1.setMinWidth(wid);
    } else {
        bc1.setMaxWidth(830);
        bc1.setMinWidth(830);
    }
    barchart1.getChildren().add(bc1);

答案 2 :(得分:0)

不幸的是,您不能简单地在Javafx BarChart中设置条形宽度。您只能设置类别CategoryGap和类别BarGap的条形之间的距离。

由于类别数(categoryAxis.getCategories().size()),每个类别的条形图(barChart.getData().size())和轴的可用空间(categoryAxis.getLayoutBounds().getWidth())是已知的,因此CategoryGapBarGap可以简单地计算出来。

重要提示:如果调整了图表大小,则需要重新计算。

public static void setBarWidth(BarChart<?, ?> barChart, CategoryAxis categoryAxis, 
                               double barWidth, double availableSpace) {
    int dataSeriesCount = barChart.getData().size();
    int categoriesCount = categoryAxis.getCategories().size();

    if (dataSeriesCount <= 1) {
        barChart.setBarGap(0d);
    } else {
        barChart.setBarGap(5d);
    }

    double barWidthSum = barWidth * (categoriesCount * dataSeriesCount);
    double barGapSum = barChart.getBarGap() * (dataSeriesCount - 1);
    double categorySpacing = (availableSpace - barWidthSum - barGapSum) / categoriesCount;
    barChart.setCategoryGap(categorySpacing);
}