package com.cfinkel.reports.charts;
import com.cfinkel.reports.exceptions.BadDataForChartException;
import com.cfinkel.reports.wrappers.Output;
import com.cfinkel.reports.generatedbeans.OutputElement;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.apache.log4j.Logger;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
/**
* Created by IntelliJ IDEA.
* User: charles
* Date: Mar 18, 2006
* Time: 5:33:16 PM
* To change this template use File | Settings | File Templates.
*/
public class BarChartGenerator extends ChartGenerator{
private static final Logger log = Logger.getLogger(BarChartGenerator.class);
/**
*
* @param data
* @param session
* @param printWriter
* @return filename
*/
public static String generateBarChart(List data, Output output, HttpSession session, PrintWriter printWriter) throws BadDataForChartException {
OutputElement outputElement = output.getOutputElement();
// convert data:
DefaultCategoryDataset dataset = createDefaultCategoryDataSet(data);
boolean showLegend = shouldIShowLegend(data);
JFreeChart chart = ChartFactory.createBarChart(
outputElement.getName(), // chart title
"", // domain axis label
"", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // orientation
showLegend, // include legend
true, // tooltips?
false // URLs?
);
// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
// set the background color for the chart...
chart.setBackgroundPaint(Color.white);
// get a reference to the plot for further customisation...
CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.white);
// set the range axis to display integers only...
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// disable bar outlines...
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setDrawBarOutline(false);
renderer.setItemMargin(0);
// set up gradient paints for series...
GradientPaint gp0 = new GradientPaint(
0.0f, 0.0f, Color.blue,
0.0f, 0.0f, new Color(0, 0, 64)
);
GradientPaint gp1 = new GradientPaint(
0.0f, 0.0f, Color.green,
0.0f, 0.0f, new Color(0, 64, 0)
);
GradientPaint gp2 = new GradientPaint(
0.0f, 0.0f, Color.red,
0.0f, 0.0f, new Color(64, 0, 0)
);
renderer.setSeriesPaint(0, gp0);
renderer.setSeriesPaint(1, gp1);
renderer.setSeriesPaint(2, gp2);
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(
CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0)
);
// OPTIONAL CUSTOMISATION COMPLETED.
return writeImageMap(chart, outputElement, session, printWriter);
}
public static boolean shouldIShowLegend(List data) {
if (data == null || data.size() == 0) return false;
Map map = (Map)data.get(0);
return map.values().size() > 2;
}
private static DefaultCategoryDataset createDefaultCategoryDataSet(List data) throws BadDataForChartException {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (Object obj : data) {
Map result = (Map)obj;
if (result.values().size() < 2)
throw new BadDataForChartException("For chart, must have at least two columns of data," +
" with the first column having the categories and the other columns having the data ");
boolean weAreAtTheFirstColumn = true;
String dataName = "";
for (Object entryObj : result.entrySet()) {
Map.Entry entry = (Map.Entry)entryObj;
Object datum = entry.getValue();
String columnName = (String)entry.getKey();
if (weAreAtTheFirstColumn) {
if (!(datum instanceof String))
throw new BadDataForChartException("First column must be a string, isstead it's " + datum.getClass().toString());
dataName = (String)datum;
weAreAtTheFirstColumn = false;
} else {
if (! ((datum instanceof BigDecimal) || (datum instanceof BigInteger)) )
throw new BadDataForChartException("Data must be decimal or integer. Can't plot otherwise.");
// add the value to the dataset:
dataset.addValue((Number)datum,columnName,dataName);
}
}
}
return dataset;
}
}