Set Bar Chart column width size

喜夏-厌秋 提交于 2019-12-05 15:41:04

BarChart works on the basis that both barGap (gap between bars in the same category) and categoryGap (gap between bars in separate categories) can be set by the user, so for a given size of chart, the width of the bars is calculated internally every time a layout is requested.

To set a maximum width on every bar, we have to change either barGap or categoryGap accordingly. But we can do it programmatically, to respond to any change in the width of the chart.

Let's first calculate the bar width for an initial layout. According to BarChart.layoutPlotChildren():

double catSpace = xAxis.getCategorySpacing();
double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap());
double barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap();

In the example provided by the OP, given the default gap values (barGap=4, categoryGap=10), the resulting barWidth is 37.4.

Let's assume we want to set a limit of 40, and a minimum category gap of 10:

double maxBarWidth=40;
double minCategoryGap=10;

If the chart's width increases when the scene is resized, we could limit barWidth by increasing categoryGap:

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);

Note the do-while loop: as we modify categoryGap a new layout is performed and some initial values change. It takes usually two iterations to get the desired result.

We can repeat this operation as long as the chart's width keeps growing.

But if the chart's width starts decreasing, the gap between categories should be decreased too, while the bar width stays close to its maximum:

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);

Putting everything together, and listening to scene width changes:

    ...
    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);
        }
    });

Note that in the rest of the cases, barWidth will be calculated internally.

Further to José Pereda's answer. You can set the width of the chart according to your data set. Together with the BarGap and CategoryGap setters, you can fine tune the width of the bars through calculation or trial and error. For instance, I did the following to get thinner bars. I set the width of an empty graph to 30 (for the axis and label??) and then added 100px to max and min width for every round in the game of cribbage (up to a maximum of the gridpane width) thus restricting the free space in the graph for the bars to fill.

 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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!