Neither chart.getWidth() nor left-align to title working

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
jstrieb
Posts: 6
Joined: Tue Jul 12, 2016 3:49 pm
antibot: No, of course not.

Neither chart.getWidth() nor left-align to title working

Post by jstrieb » Thu Jul 21, 2016 2:52 pm

Cross posted here

I am trying to left-align a JFreeChart subtitle to a centered title such that the main title is centered in the ChartFrame but the subtitle is aligned to the left margin of the title. The only way I could think to do this was to set the title and subtitle to have a HorizontalAlignment.LEFT. Then I'd have the program manually set the left padding of the title such that it was centered, and then set the subtitle padding to match that of the title, thereby lining them up to the same left-margin which is calculated to line the title up to the center of the frame like this:

Code: Select all

// Make the chart
JFreeChart chart = ChartFactory.createTimeSeriesChart(title, "Time (Hour)", "Vehicles Parked", dataset, true, true, false);

ChartFrame frame = new ChartFrame("Chart", chart);
frame.pack();
frame.setVisible(true);

chart.getTitle().setHorizontalAlignment(HorizontalAlignment.LEFT);
chart.getTitle().setPadding(0, (frame.getWidth()/2)-(chart.getTitle().getWidth()/2), 0, 0);

TextTitle subtitle1 = new TextTitle(
        "This is a test subtitle in which I would like\nthe subtitle to be lined up to the title", // text
        chart.getTitle().getFont().deriveFont(chart.getTitle().getFont().getSize() * 0.6f), // font (shrunk title)
        chart.getTitle().getPaint(), // paint
        RectangleEdge.TOP, // position
        HorizontalAlignment.LEFT, //chart2.getTitle().DEFAULT_HORIZONTAL_ALIGNMENT, // horizontal alignment
        VerticalAlignment.BOTTOM, // vertical alignment
        chart.getTitle().getPadding() // padding
);
chart.addSubtitle(subtitle1);
In trying to do this, the chart.getTitle().getWidth() method is returning 0.0 every time, and I can't figure out why. I have tried casting chart.getTitle() to an AbstractBlock but that makes no difference. I believe it has something to do with the fact that in the JavaDoc for the getWidth() method in the AbstractBlock class, it mentions it will return the width if it knows it in advance, which apparently it doesn't.

I want to know how to get the chart title to correctly return its width, whether by using the getWidth() function or not. I would also like to know if there is a better way to align elements of a chart to each other as opposed to the sides of the ChartFrame rather than adjusting their padding.
Last edited by jstrieb on Thu Jul 28, 2016 10:08 pm, edited 1 time in total.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Neither chart.getWidth() nor left-align to title working

Post by paradoxoff » Thu Jul 21, 2016 5:18 pm

AFAIKS, neither the width and height of a Title nor the bounds are set during the rendering of a chart, if the chart is directly added to a JFreeChart.
Try the following:
- Create a BlockContainer with a ColumnArrangment.
- Add the two Titles to the BlockContainer.
- Use the BlockContainer to create a CompositeTitle.
- Set the position of the CompositeTitle to RectangleEdge.TOP, and the VerticalAlignment to VerticalAlignment.CENTER.
- Add the CompositeTitle to the chart.

The CompositeTitle should be placed on the chart that the widest Title is centered, and both titles should be left aligned.

jstrieb
Posts: 6
Joined: Tue Jul 12, 2016 3:49 pm
antibot: No, of course not.

Re: Neither chart.getWidth() nor left-align to title working

Post by jstrieb » Mon Jul 25, 2016 2:36 pm

paradoxoff wrote: - Create a BlockContainer with a ColumnArrangment.
- Add the two Titles to the BlockContainer.
- Use the BlockContainer to create a CompositeTitle.
- Set the position of the CompositeTitle to RectangleEdge.TOP, and the VerticalAlignment to VerticalAlignment.CENTER.
- Add the CompositeTitle to the chart.
This worked well for me, except that I had to pad the subtitle with two spaces so that it was better aligned to the title. In any case, thank you for your help.

jstrieb
Posts: 6
Joined: Tue Jul 12, 2016 3:49 pm
antibot: No, of course not.

Re: Neither chart.getWidth() nor left-align to title working

Post by jstrieb » Thu Jul 28, 2016 10:07 pm

In a test-case this solution worked, however in practice it does not work because the ability for titles to have line wrapping seems to disappear when I implement the BlockContainer/CompositeTitle solution. Thoughts on how I can have this, except with a BlockContainer that has line-wrapping for the title and subtitles?

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Neither chart.getWidth() nor left-align to title working

Post by paradoxoff » Sat Aug 06, 2016 9:51 am

You are dealing here with one of the most complex topics in JFreeChart (at least IMHO). See this old thread for a similar problem.
The root cause of the behaviour that you are seeing is the following: a ColumnArrangement explicitly assumes that it only has to keep an eye on the total height of the blocks that it arranges and only needs to wrap to the next column if the maximum available height is reached. It is never considered that the width of a block might by an issue, but instead, it is assumed that the available width will always be sufficient. In reality, however, there are always constraints that need to be taken into account.
In my local JFreeChart installation, I have modified the arrangement classes, and I do not observe the behaviour that you do. Unfortunately, the changes are too fundamental to be readily applied to JFreeChart.
Here is a quick fix that might even work:
- Write a new class that extends ColumnArrangement class.
- Create a new method Size2D arrangeRN(BlockContainer container, Graphics2D g2, RectangleConstraint constraint). This method is very similar to arrangeNN of the existing ColumnArrangement class. The frist two lines have been added, and the line sizes = block.arrange(g2, localRC) has been changed.

Code: Select all

    protected Size2D arrangeRN(BlockContainer container, Graphics2D g2, RectangleConstraint rc) {
        Range widthRange = rc.getWidthRange();
        RectangleConstraint localRC = RectangleConstraint.NONE.toRangeWidth(widthRange);
        double y = 0.0;
        double height = 0.0;
        double maxWidth = 0.0;
        List blocks = container.getBlocks();
        int blockCount = blocks.size();
        if (blockCount > 0) {
            Size2D[] sizes = new Size2D[blocks.size()];
            for (int i = 0; i < blocks.size(); i++) {
                Block block = (Block) blocks.get(i);
                sizes[i] = block.arrange(g2, localRC);
                height = height + sizes[i].getHeight();
                maxWidth = Math.max(sizes[i].width, maxWidth);
                block.setBounds(
                    new Rectangle2D.Double(
                        0.0, y, sizes[i].width, sizes[i].height
                    )
                );
                y = y + sizes[i].height + this.verticalGap;
            }
            if (blockCount > 1) {
                height = height + this.verticalGap * (blockCount - 1);   
            }
            if (this.horizontalAlignment != HorizontalAlignment.LEFT) {
                for (int i = 0; i < blocks.size(); i++) {
                    //Block b = (Block) blocks.get(i);
                    if (this.horizontalAlignment 
                            == HorizontalAlignment.CENTER) {
                        //TODO: shift block right by half
                    }
                    else if (this.horizontalAlignment 
                            == HorizontalAlignment.RIGHT) {
                        //TODO: shift block over to right
                    }
                }            
            }
        }
        return new Size2D(maxWidth, height);
    }

- Override arrangeRR and change the line

Code: Select all

Size2D s1 = arrangeNN(container, g2);
to

Code: Select all

Size2D s1 = arrangeRN(container, g2, constraint);

Locked