/* Copyright 2013 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package sim.util.media.chart; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; import java.io.*; import java.awt.image.*; import java.util.*; import java.text.Format.*; import sim.util.gui.*; import sim.util.gui.Utilities; import sim.util.*; import sim.display.*; import sim.util.media.*; // From JFreeChart import org.jfree.chart.*; import org.jfree.chart.axis.*; import org.jfree.chart.event.*; import org.jfree.chart.plot.*; import org.jfree.chart.labels.*; import org.jfree.chart.renderer.category.*; import org.jfree.data.general.*; import org.jfree.data.statistics.*; import org.jfree.chart.renderer.xy.*; import org.jfree.data.category.*; import org.jfree.chart.title.*; import org.jfree.ui.*; // from iText (www.lowagie.com/iText/) import com.lowagie.text.*; import com.lowagie.text.pdf.*; /* // looks like we'll have to move to these soon import com.itextpdf.text.*; import com.itextpdf.text.pdf.*; */ /** A ChartGenerator for Bar Charts. Similar enough to PieChartGenerator that it subclasses from it to share methods. */ public class BarChartGenerator extends PieChartGenerator { /** The global attributes domain axis field. */ PropertyField xLabel; /** The global attributes range axis field. */ PropertyField yLabel; /** Sets the name of the Y Axis label. */ public void setYAxisLabel(String val) { CategoryPlot xyplot = (CategoryPlot)(chart.getPlot()); xyplot.getRangeAxis().setLabel(val); xyplot.axisChanged(new AxisChangeEvent(xyplot.getRangeAxis())); yLabel.setValue(val); } /** Returns the name of the Y Axis label. */ public String getYAxisLabel() { return ((CategoryPlot)(chart.getPlot())).getRangeAxis().getLabel(); } /** Sets the name of the X Axis label. */ public void setXAxisLabel(String val) { CategoryPlot xyplot = (CategoryPlot)(chart.getPlot()); xyplot.getDomainAxis().setLabel(val); xyplot.axisChanged(new AxisChangeEvent(xyplot.getDomainAxis())); xLabel.setValue(val); } /** Returns the name of the X Axis label. */ public String getXAxisLabel() { return ((CategoryPlot)(chart.getPlot())).getDomainAxis().getLabel(); } BarRenderer barRenderer; StackedBarRenderer stackedBarRenderer; StackedBarRenderer percentageRenderer; BarRenderer getBarRenderer() { return barRenderer; } BarRenderer getStackedBarRenderer() { return stackedBarRenderer; } BarRenderer getPercentageRenderer() { return percentageRenderer; } void reviseRenderer(BarRenderer renderer) { renderer.setShadowVisible(false); renderer.setBarPainter(new StandardBarPainter()); renderer.setBaseOutlineStroke(new BasicStroke(2.0f)); renderer.setDrawBarOutline(true); renderer.setBaseItemLabelGenerator( new StandardCategoryItemLabelGenerator( "{0}", java.text.NumberFormat.getInstance())); // {0} is the row key, {1} is the column key, {2} is the value renderer.setBaseItemLabelsVisible(true); } protected void buildGlobalAttributes(LabelledList list) { // create the chart CategoryPlot plot = (CategoryPlot)(chart.getPlot()); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); plot.setDomainGridlinePaint(new Color(200,200,200)); plot.setRangeGridlinePaint(new Color(200,200,200)); // define the renderers barRenderer = new BarRenderer(); reviseRenderer(barRenderer); stackedBarRenderer = new StackedBarRenderer(false); reviseRenderer(stackedBarRenderer); percentageRenderer = new StackedBarRenderer(true); reviseRenderer(percentageRenderer); plot.setRenderer(barRenderer); xLabel = new PropertyField() { public String newValue(String newValue) { setXAxisLabel(newValue); getChartPanel().repaint(); return newValue; } }; xLabel.setValue(getXAxisLabel()); list.add(new JLabel("X Label"), xLabel); yLabel = new PropertyField() { public String newValue(String newValue) { setYAxisLabel(newValue); getChartPanel().repaint(); return newValue; } }; yLabel.setValue(getYAxisLabel()); list.add(new JLabel("Y Label"), yLabel); final JCheckBox gridlines = new JCheckBox(); gridlines.setSelected(false); ItemListener il = new ItemListener() { public void itemStateChanged(ItemEvent e) { hasgridlines = (e.getStateChange() == ItemEvent.SELECTED); updateGridLines(); } }; gridlines.addItemListener(il); list.add(new JLabel("Grid Lines"), gridlines); final JCheckBox labels = new JCheckBox(); labels.setSelected(true); il = new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { getBarRenderer().setBaseItemLabelsVisible(true); getStackedBarRenderer().setBaseItemLabelsVisible(true); getPercentageRenderer().setBaseItemLabelsVisible(true); } else { getBarRenderer().setBaseItemLabelsVisible(false); getStackedBarRenderer().setBaseItemLabelsVisible(false); getPercentageRenderer().setBaseItemLabelsVisible(false); } } }; labels.addItemListener(il); list.add(new JLabel("Labels"), labels); final JComboBox barType = new JComboBox(); barType.setEditable(false); barType.setModel(new DefaultComboBoxModel(new java.util.Vector(Arrays.asList( new String[] { "Separate", "Stacked", "Percentage" })))); barType.setSelectedIndex(0); barType.addActionListener(new ActionListener() { public void actionPerformed ( ActionEvent e ) { CategoryPlot plot = (CategoryPlot)(chart.getPlot()); int type = barType.getSelectedIndex(); if (type == 0) // separate { plot.setRenderer(getBarRenderer()); } else if (type == 1) // stacked { plot.setRenderer(getStackedBarRenderer()); } else // percentage { plot.setRenderer(getPercentageRenderer()); } } }); list.add(new JLabel("Bars"), barType); final JCheckBox horizontal = new JCheckBox(); horizontal.setSelected(false); il = new ItemListener() { public void itemStateChanged(ItemEvent e) { CategoryPlot plot = (CategoryPlot)(chart.getPlot()); if (e.getStateChange() == ItemEvent.SELECTED) { plot.setOrientation(PlotOrientation.HORIZONTAL); ishorizontal = true; } else { plot.setOrientation(PlotOrientation.VERTICAL); ishorizontal = false; } updateGridLines(); } }; horizontal.addItemListener(il); list.add(new JLabel("Horizontal"), horizontal); } boolean hasgridlines = false; boolean ishorizontal = false; void updateGridLines() { if (hasgridlines) { if (ishorizontal) { chart.getCategoryPlot().setRangeGridlinesVisible(true); chart.getCategoryPlot().setDomainGridlinesVisible(false); } else { chart.getCategoryPlot().setRangeGridlinesVisible(true); chart.getCategoryPlot().setDomainGridlinesVisible(false); } } else { chart.getCategoryPlot().setRangeGridlinesVisible(false); chart.getCategoryPlot().setDomainGridlinesVisible(false); } } public static final int MAXIMUM_BAR_CHART_ITEMS = 20; public Dataset getSeriesDataset() { return ((CategoryPlot)(chart.getPlot())).getDataset(); } public void setSeriesDataset(Dataset obj) { // here we will interrupt things if they're too big if (((CategoryDataset)obj).getRowCount() > MAXIMUM_BAR_CHART_ITEMS) { ((CategoryPlot)(chart.getPlot())).setDataset(emptyDataset); setInvalidChartTitle("[[ Dataset has too many items. ]]"); } else { ((CategoryPlot)(chart.getPlot())).setDataset((DefaultCategoryDataset)obj); if (invalidChartTitle != null) setInvalidChartTitle(null); } } protected PieChartSeriesAttributes buildNewAttributes(String name, SeriesChangeListener stopper) { return new BarChartSeriesAttributes(this, name, getSeriesCount(), stopper); } protected void buildChart() { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); chart = ChartFactory.createBarChart("Untitled Chart", "Category", "Value", dataset, PlotOrientation.VERTICAL, false, true, false); chart.setAntiAlias(true); //chartPanel = new ScrollableChartPanel(chart, true); chartPanel = buildChartPanel(chart); //chartHolder.getViewport().setView(chartPanel); setChartPanel(chartPanel); // this must come last because the chart must exist for us to set its dataset setSeriesDataset(dataset); } public BarChartGenerator() { // buildChart is called by super() first } }