简体   繁体   中英

Get rid of jfreechart chartpanel unnecessary space

I am trying to get a JFreeChart ChartPanel to remove unwanted extra space between the edge of the panel and the graph itself.

To best illustrate, here's a SSCCE (with JFreeChart installed):

public static void main(String[] args) {
    JPanel panel = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();

    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridwidth = 1;
    gbc.gridheight = 1;
    gbc.weightx = 1;
    gbc.weighty = 1;
    gbc.gridy = 1;

    gbc.gridx = 1;
    panel.add(createChart("Sales", Chart_Type.DOLLARS, 100000, 115000), gbc);
    gbc.gridx = 2;
    panel.add(createChart("Quotes", Chart_Type.DOLLARS, 250000, 240000), gbc);
    gbc.gridx = 3;
    panel.add(createChart("Profits", Chart_Type.PERCENTAGE, 40.00, 38.00), gbc);

    JFrame frame = new JFrame();
    frame.add(panel);
    frame.setSize(800, 300);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

private static ChartPanel createChart(String title, Chart_Type type, double goal, double actual) {
    double maxValue = goal * 2;
    double yellowToGreenNum = goal;
    double redToYellowNum = goal * .75;
    DefaultValueDataset dataset = new DefaultValueDataset(actual);

    JFreeChart jfreechart = createChart(dataset, Math.max(actual, maxValue), redToYellowNum, yellowToGreenNum, title, type);
    ChartPanel chartPanel = new ChartPanel(jfreechart);
    chartPanel.setBorder(new LineBorder(Color.red));
    return chartPanel;
}

private static JFreeChart createChart(ValueDataset valuedataset, Number maxValue, Number redToYellowNum, Number yellowToGreenNum, String title, Chart_Type type) {
    MeterPlot meterplot = new MeterPlot(valuedataset);
    meterplot.setRange(new Range(0.0D, maxValue.doubleValue()));
    meterplot.addInterval(new MeterInterval(" Goal Not Met ",
            new Range(0.0D, redToYellowNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
            new Color(255, 0, 0, 128)));
    meterplot.addInterval(new MeterInterval(" Goal Almost Met ",
            new Range(redToYellowNum.doubleValue(), yellowToGreenNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
            new Color(255, 255, 0, 64)));
    meterplot.addInterval(new MeterInterval(" Goal Met ",
            new Range(yellowToGreenNum.doubleValue(), maxValue.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
            new Color(0, 255, 0, 64)));
    meterplot.setNeedlePaint(Color.darkGray);
    meterplot.setDialBackgroundPaint(Color.white);
    meterplot.setDialOutlinePaint(Color.gray);
    meterplot.setDialShape(DialShape.CHORD);
    meterplot.setMeterAngle(260);
    meterplot.setTickLabelsVisible(false);

    meterplot.setTickSize(maxValue.doubleValue() / 20);
    meterplot.setTickPaint(Color.lightGray);

    meterplot.setValuePaint(Color.black);
    meterplot.setValueFont(new Font("Dialog", Font.BOLD, 0));
    meterplot.setUnits("");
    if(type == Chart_Type.DOLLARS)
        meterplot.setTickLabelFormat(NumberFormat.getCurrencyInstance());
    else if(type == Chart_Type.PERCENTAGE)
        meterplot.setTickLabelFormat(NumberFormat.getPercentInstance());
    JFreeChart jfreechart = new JFreeChart(title,
            JFreeChart.DEFAULT_TITLE_FONT, meterplot, false);
    return jfreechart;
}

enum Chart_Type {
    DOLLARS,
    PERCENTAGE
}

If you resize the frame, you can see that you cannot make the edge of the graph go to the edge of the panel (the panels are outlined in red). Especially on the bottom - there is always a gap between the bottom the graph and the bottom of the panel.

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

Is there a way to make the graph fill the entire area? Is there a way to at least guarantee that it is touching one edge of the panel (ie, it is touching the top and bottom or the left and right) ??

For reference, without changing the plot, here's the result with the following settings:

  • Calling pack() on the enclosing frame.

  • Using a no-gap GridLayout .

  • Returning an equilateral preferred size.

  • setMeterAngle(360); .

  • setDrawBorder(true);

Resizing to a non-square aspect fills the narrower dimension.

图片

Addendum: As shown here , you can override the chart's draw() method. For improved resizing behavior in the variation below, the plot's draw() method is overridden to shift the area by a fraction of its height. A function based on getMeterAngle() may also be useful.

MeterPlot meterplot = new MeterPlot(valuedataset) {

    @Override
    public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
        double h = area.getHeight() * 6 / 5;
        area.setRect(area.getX(), area.getY(), area.getWidth(), h);
        super.draw(g2, area, anchor, parentState, info);
    }
};

图片

Updated code:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.PlotState;
import org.jfree.data.Range;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.general.ValueDataset;

//* @see https://stackoverflow.com/a/25416067/230513 */
public class Test {

    public static void main(String[] args) {
        JPanel panel = new JPanel(new GridLayout());
        panel.add(createChart("Sales", Chart_Type.DOLLARS, 100000, 115000));
        panel.add(createChart("Quotes", Chart_Type.DOLLARS, 250000, 240000));
        panel.add(createChart("Profits", Chart_Type.PERCENTAGE, 40.00, 38.00));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static ChartPanel createChart(String title, Chart_Type type, double goal, double actual) {
        double maxValue = goal * 2;
        double yellowToGreenNum = goal;
        double redToYellowNum = goal * .75;
        DefaultValueDataset dataset = new DefaultValueDataset(actual);

        JFreeChart jfreechart = createChart(dataset, Math.max(actual, maxValue), redToYellowNum, yellowToGreenNum, title, type);
        ChartPanel chartPanel = new ChartPanel(jfreechart) {

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 300);
            }
        };
        chartPanel.setBorder(new LineBorder(Color.red));
        return chartPanel;
    }

    private static JFreeChart createChart(ValueDataset valuedataset, Number maxValue, Number redToYellowNum, Number yellowToGreenNum, String title, Chart_Type type) {
        MeterPlot meterplot = new MeterPlot(valuedataset) {

            @Override
            public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
                double h = area.getHeight() * 6 / 5;
                area.setRect(area.getX(), area.getY(), area.getWidth(), h);
                super.draw(g2, area, anchor, parentState, info);
            }
        };
        meterplot.setRange(new Range(0.0D, maxValue.doubleValue()));
        meterplot.addInterval(new MeterInterval(" Goal Not Met ",
                new Range(0.0D, redToYellowNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
                new Color(255, 0, 0, 128)));
        meterplot.addInterval(new MeterInterval(" Goal Almost Met ",
                new Range(redToYellowNum.doubleValue(), yellowToGreenNum.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
                new Color(255, 255, 0, 64)));
        meterplot.addInterval(new MeterInterval(" Goal Met ",
                new Range(yellowToGreenNum.doubleValue(), maxValue.doubleValue()), Color.lightGray, new BasicStroke(2.0F),
                new Color(0, 255, 0, 64)));
        meterplot.setNeedlePaint(Color.darkGray);
        meterplot.setDialBackgroundPaint(Color.white);
        meterplot.setDialOutlinePaint(Color.gray);
        meterplot.setDialShape(DialShape.CHORD);
        meterplot.setMeterAngle(260);
        meterplot.setTickLabelsVisible(false);

        meterplot.setTickSize(maxValue.doubleValue() / 20);
        meterplot.setTickPaint(Color.lightGray);

        meterplot.setValuePaint(Color.black);
        meterplot.setValueFont(new Font("Dialog", Font.BOLD, 0));
        meterplot.setUnits("");
        if (type == Chart_Type.DOLLARS) {
            meterplot.setTickLabelFormat(NumberFormat.getCurrencyInstance());
        } else if (type == Chart_Type.PERCENTAGE) {
            meterplot.setTickLabelFormat(NumberFormat.getPercentInstance());
        }
        meterplot.setDrawBorder(true);
        meterplot.setDialShape(DialShape.CHORD);
        JFreeChart jfreechart = new JFreeChart(title,
                JFreeChart.DEFAULT_TITLE_FONT, meterplot, false);
        return jfreechart;
    }

    enum Chart_Type {

        DOLLARS,
        PERCENTAGE
    }
}

Thanks to trashgod's suggestion, I overrode the JFreeChart::draw() method to reduce the height of the Rectangle2D chartArea by 50 pixels (technically, I guess I added 50 pixels to the height? Not sure why it works that way):

code:

JFreeChart jfreechart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, meterplot, false) {
    @Override
    public void draw(Graphics2D g2, Rectangle2D chartArea, Point2D anchor, ChartRenderingInfo info) {
        chartArea.setRect(chartArea.getX(), chartArea.getY(), chartArea.getWidth(), chartArea.getHeight() + 50);
        super.draw(g2, chartArea, anchor, info);
    }
};

result: 在此处输入图片说明

So, thanks to trashgod for help pointing me in the right direction.

EDIT: I was, later, still running into some extra space on the left and right of the graphs. That was solved by this code: chartPanel.setMinimumDrawWidth(0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM