ro.nextreports.engine.chart.JFreeChartExporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nextreports-engine Show documentation
Show all versions of nextreports-engine Show documentation
NextReports Engine is a lightweight Java platform development library which
can be used to run NextReports inside your applications.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ro.nextreports.engine.chart;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
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.axis.NumberTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.AreaRenderer;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.Range;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.util.PublicCloneable;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.labels.XYItemLabelGenerator;
import ro.nextreports.engine.exporter.exception.NoDataFoundException;
import ro.nextreports.engine.exporter.util.function.AbstractGFunction;
import ro.nextreports.engine.exporter.util.function.FunctionFactory;
import ro.nextreports.engine.exporter.util.function.FunctionUtil;
import ro.nextreports.engine.exporter.util.function.GFunction;
import ro.nextreports.engine.i18n.I18nUtil;
import ro.nextreports.engine.queryexec.QueryException;
import ro.nextreports.engine.queryexec.QueryResult;
import ro.nextreports.engine.util.StringUtil;
import ro.nextreports.engine.util.chart.CylinderRenderer;
import ro.nextreports.engine.util.chart.Star;
public class JFreeChartExporter implements ChartExporter {
private QueryResult result;
private Chart chart;
private String chartImageName;
private Object lastXObjValue = null;
private boolean integerXValue = true;
private DefaultCategoryDataset barDataset;
private DefaultPieDataset pieDataset;
private DefaultCategoryDataset lineBarDataset;
private DefaultXYZDataset bubbleDataset;
private Map bubbleData = new LinkedHashMap();
private String path;
private int width;
private int height;
private Map parameterValues;
private final String DEFAULT_LEGEND_PREFIX = "_L_";
private static final int DEFAULT_WIDTH = 500;
private static final int DEFAULT_HEIGHT = 300;
private Map xValueSerie = new HashMap();
private float transparency = 0.7f;
private boolean isLineCombo = false;
private String language;
public JFreeChartExporter(Map parameterValues, QueryResult result, Chart chart, String language) {
this(parameterValues, result, chart, ".", DEFAULT_WIDTH, DEFAULT_HEIGHT, language);
}
public JFreeChartExporter(Map parameterValues, QueryResult result, Chart chart, String path, String language) {
this(parameterValues, result, chart, path, DEFAULT_WIDTH, DEFAULT_HEIGHT, language);
}
public JFreeChartExporter(Map parameterValues, QueryResult result, Chart chart, String path,
int width, int height, String language) {
this(parameterValues, result, chart, path, null, width, height, language);
}
public JFreeChartExporter(Map parameterValues, QueryResult result, Chart chart, String path,
String imageName, int width, int height, String language) {
if (width <= 0) {
width = DEFAULT_WIDTH;
}
if (height <= 0) {
height = DEFAULT_HEIGHT;
}
this.parameterValues = parameterValues;
this.result = result;
this.chart = chart;
this.path = path;
this.chartImageName = imageName;
this.width = width;
this.height = height;
this.language = language;
}
public boolean export() throws QueryException, NoDataFoundException {
testForData();
createImage();
return true;
}
private void testForData() throws QueryException, NoDataFoundException {
// for procedure call we do not know the row count (is -1)
if (result == null || result.getColumnCount() <= 0 || result.getRowCount() == 0) {
throw new NoDataFoundException();
}
}
private void createImage() throws QueryException {
byte type = chart.getType().getType();
JFreeChart jfreechart = null;
if (ChartType.LINE == type) {
jfreechart = createLineChart();
} else if (ChartType.BAR == type) {
jfreechart = createBarChart(false, false);
} else if (ChartType.BAR_COMBO == type) {
jfreechart = createBarChart(false, false, true);
} else if (ChartType.HORIZONTAL_BAR == type) {
jfreechart = createBarChart(true, false);
} else if (ChartType.STACKED_BAR == type) {
jfreechart = createBarChart(false, true);
} else if (ChartType.STACKED_BAR_COMBO == type) {
jfreechart = createBarChart(false, true, true);
} else if (ChartType.HORIZONTAL_STACKED_BAR == type) {
jfreechart = createBarChart(true, true);
} else if (ChartType.PIE == type) {
jfreechart = createPieChart();
} else if (ChartType.BUBBLE == type) {
jfreechart = createBubbleChart();
} else if (ChartType.AREA == type) {
jfreechart = createAreaChart();
}
try {
if ((chartImageName == null) || "".equals(chartImageName.trim())) {
chartImageName = "chart_" + System.currentTimeMillis() + ".jpg";
}
ChartUtilities.saveChartAsJPEG(new File(path + File.separator + chartImageName), jfreechart, width, height);
} catch (IOException e) {
System.err.println("Problem occurred creating chart.");
}
}
private JFreeChart createLineChart() throws QueryException {
XYSeriesCollection dataset = new XYSeriesCollection();
String chartTitle = replaceParameters(chart.getTitle().getTitle());
chartTitle = StringUtil.getI18nString(chartTitle, I18nUtil.getLanguageByName(chart, language));
Object[] charts = new Object[chart.getYColumns().size()];
List legends = chart.getYColumnsLegends();
boolean hasLegend = false;
for (int i = 0; i < charts.length; i++) {
String legend = "";
try {
legend = replaceParameters(legends.get(i));
legend = StringUtil.getI18nString(legend, I18nUtil.getLanguageByName(chart, language));
} catch (IndexOutOfBoundsException ex){
// no legend set
}
if ((legend != null) && !"".equals(legend.trim())) {
hasLegend = true;
}
XYSeries lineChart = new XYSeries(legend);
charts[i] = lineChart;
dataset.addSeries(lineChart);
}
String xLegend = StringUtil.getI18nString(replaceParameters(chart.getXLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
String yLegend = StringUtil.getI18nString(replaceParameters(chart.getYLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
JFreeChart jfreechart = ChartFactory.createXYLineChart(
chartTitle, // Title
replaceParameters(xLegend), // x-axis Label
replaceParameters(yLegend), // y-axis Label
dataset, // Dataset
PlotOrientation.VERTICAL, // Plot Orientation
true, // Show Legend
true, // Use tooltips
false // Configure chart to generate URLs?
);
// hide legend if necessary
if (!hasLegend) {
jfreechart.removeLegend();
}
// hide border
jfreechart.setBorderVisible(false);
// title
setTitle(jfreechart);
// charts colors & values
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
DecimalFormat decimalFormat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalFormat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalFormat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalFormat;
}
XYPlot plot = (XYPlot) jfreechart.getPlot();
for (int i = 0; i < charts.length; i++) {
plot.getRenderer().setSeriesPaint(i, chart.getForegrounds().get(i));
if (showValues) {
plot.getRenderer().setSeriesItemLabelsVisible(i, true);
plot.getRenderer().setSeriesItemLabelGenerator(i, new StandardXYItemLabelGenerator("{2}", decimalFormat, percentageFormat));
}
}
if (showValues) {
// increase a little bit the range axis to view all item label values over points
plot.getRangeAxis().setUpperMargin(0.2);
}
// grid axis visibility & colors
if ((chart.getXShowGrid() != null) && !chart.getXShowGrid()) {
plot.setDomainGridlinesVisible(false);
} else {
if (chart.getXGridColor() != null) {
plot.setDomainGridlinePaint(chart.getXGridColor());
} else {
plot.setDomainGridlinePaint(Color.BLACK);
}
}
if ((chart.getYShowGrid() != null) && !chart.getYShowGrid()) {
plot.setRangeGridlinesVisible(false);
} else {
if (chart.getYGridColor() != null) {
plot.setRangeGridlinePaint(chart.getYGridColor());
} else {
plot.setRangeGridlinePaint(Color.BLACK);
}
}
// chart background
plot.setBackgroundPaint(chart.getBackground());
// labels color
plot.getDomainAxis().setTickLabelPaint(chart.getXColor());
plot.getRangeAxis().setTickLabelPaint(chart.getYColor());
//legend color
plot.getDomainAxis().setLabelPaint(chart.getXLegend().getColor());
plot.getRangeAxis().setLabelPaint(chart.getYLegend().getColor());
// legend font
plot.getDomainAxis().setLabelFont(chart.getXLegend().getFont());
plot.getRangeAxis().setLabelFont(chart.getYLegend().getFont());
// hide labels
if ((chart.getXShowLabel() != null) && !chart.getXShowLabel()) {
plot.getDomainAxis().setTickLabelsVisible(false);
plot.getDomainAxis().setTickMarksVisible(false);
}
if ((chart.getYShowLabel() != null) && !chart.getYShowLabel()) {
plot.getRangeAxis().setTickLabelsVisible(false);
plot.getRangeAxis().setTickMarksVisible(false);
}
// label orientation
if (chart.getXorientation() == Chart.VERTICAL) {
plot.getDomainAxis().setVerticalTickLabels(true);
}
// labels fonts
plot.getDomainAxis().setTickLabelFont(chart.getXLabelFont());
plot.getRangeAxis().setTickLabelFont(chart.getYLabelFont());
// point style
Shape pointShape = null;
byte style = chart.getType().getStyle();
switch (style) {
case ChartType.STYLE_LINE_DOT_SOLID:
case ChartType.STYLE_LINE_DOT_HOLLOW:
pointShape = new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f);
break;
case ChartType.STYLE_LINE_DOT_ANCHOR: // triangle
GeneralPath s5 = new GeneralPath();
s5.moveTo(0.0f, -3.0f);
s5.lineTo(3.0f, 3.0f);
s5.lineTo(-3.0f, 3.0f);
s5.closePath();
pointShape = s5;
break;
case ChartType.STYLE_LINE_DOT_BOW:
GeneralPath s4 = new GeneralPath();
s4.moveTo(-3.0f, -3.0f);
s4.lineTo(3.0f, -3.0f);
s4.lineTo(-3.0f, 3.0f);
s4.lineTo(3.0f, 3.0f);
s4.closePath();
pointShape = s4;
break;
case ChartType.STYLE_LINE_DOT_STAR:
pointShape = new Star(-3.0f, 0f).getShape();
break;
default:
// no shape
break;
}
if (pointShape != null) {
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setUseFillPaint(true);
for (int i = 0; i < charts.length; i++) {
renderer.setSeriesShapesVisible(i, true);
if (style != ChartType.STYLE_LINE_DOT_SOLID) {
renderer.setSeriesFillPaint(i, chart.getBackground());
} else {
renderer.setSeriesFillPaint(i, chart.getForegrounds().get(i));
}
renderer.setSeriesShape(i, pointShape);
}
}
final HashMap formatValues = createChart(plot.getRangeAxis(), charts);
// in x axis does not contain number values , values are strings representing one unit
if (!integerXValue) {
((NumberAxis)plot.getDomainAxis()).setTickUnit(new NumberTickUnit(1));
((NumberAxis)plot.getDomainAxis()).setNumberFormatOverride(new DecimalFormat(){
@Override
public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
String s = formatValues.get(String.valueOf(Math.round(number)));
if (s == null) {
s = "";
}
return result.append(s);
}
});
}
return jfreechart;
}
private JFreeChart createBarChart(boolean horizontal, boolean stacked) throws QueryException {
return createBarChart(horizontal, stacked, false);
}
private JFreeChart createBarChart(boolean horizontal, boolean stacked, boolean isCombo) throws QueryException {
barDataset = new DefaultCategoryDataset();
String chartTitle = replaceParameters(chart.getTitle().getTitle());
chartTitle = StringUtil.getI18nString(chartTitle, I18nUtil.getLanguageByName(chart, language));
Object[] charts;
List legends;
Object[] lineCharts = null;
String lineLegend = null;
if (isCombo) {
lineCharts = new Object[1];
if (chart.getYColumnsLegends().size() < chart.getYColumns().size()) {
lineLegend = "";
} else {
lineLegend = chart.getYColumnsLegends().get(chart.getYColumns().size()-1);
}
charts = new Object[chart.getYColumns().size()-1];
legends = chart.getYColumnsLegends().subList(0, chart.getYColumns().size()-1);
} else {
charts = new Object[chart.getYColumns().size()];
legends = chart.getYColumnsLegends();
}
boolean hasLegend = false;
for (int i = 0; i < charts.length; i++) {
String legend = "";
try {
legend = replaceParameters(legends.get(i));
legend = StringUtil.getI18nString(legend, I18nUtil.getLanguageByName(chart, language));
} catch (IndexOutOfBoundsException ex){
// no legend set
}
// Important : must have default different legends used in barDataset.addValue
if ((legend == null) || "".equals(legend.trim())) {
legend = DEFAULT_LEGEND_PREFIX + String.valueOf(i+1);
} else {
hasLegend = true;
}
charts[i] = legend;
}
if (isCombo) {
String leg = "";
if (lineLegend != null) {
leg = replaceParameters(lineLegend);
}
lineCharts[0] = leg;
}
byte style = chart.getType().getStyle();
JFreeChart jfreechart;
String xLegend = StringUtil.getI18nString(replaceParameters(chart.getXLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
String yLegend = StringUtil.getI18nString(replaceParameters(chart.getYLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
PlotOrientation plotOrientation = horizontal ? PlotOrientation.HORIZONTAL : PlotOrientation.VERTICAL;
if (stacked) {
jfreechart = ChartFactory.createStackedBarChart(
chartTitle, // chart title
xLegend, // x-axis Label
yLegend, // y-axis Label
barDataset, // data
plotOrientation, // orientation
true, // include legend
true, // tooltips
false // URLs
);
} else {
switch (style) {
case ChartType.STYLE_BAR_PARALLELIPIPED:
case ChartType.STYLE_BAR_CYLINDER:
jfreechart = ChartFactory.createBarChart3D(
chartTitle, // chart title
xLegend, // x-axis Label
yLegend, // y-axis Label
barDataset, // data
plotOrientation, // orientation
true, // include legend
true, // tooltips
false // URLs
);
break;
default:
jfreechart = ChartFactory.createBarChart(
chartTitle, // chart title
xLegend, // x-axis Label
yLegend, // y-axis Label
barDataset, // data
plotOrientation, // orientation
true, // include legend
true, // tooltips
false // URLs
);
break;
}
}
if (style == ChartType.STYLE_BAR_CYLINDER) {
((CategoryPlot)jfreechart.getPlot()).setRenderer(new CylinderRenderer());
}
// hide legend if necessary
if (!hasLegend) {
jfreechart.removeLegend();
}
// hide border
jfreechart.setBorderVisible(false);
// title
setTitle(jfreechart);
// chart colors & values shown on bars
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
CategoryPlot plot = (CategoryPlot)jfreechart.getPlot();
plot.setForegroundAlpha(transparency);
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setDrawBarOutline(false);
DecimalFormat decimalformat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalformat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalformat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalformat;
}
for (int i = 0; i < charts.length; i++) {
renderer.setSeriesPaint(i, chart.getForegrounds().get(i));
if (showValues) {
renderer.setSeriesItemLabelsVisible(i, true);
renderer.setSeriesItemLabelGenerator(i, new StandardCategoryItemLabelGenerator("{2}", decimalformat, percentageFormat));
}
}
if (showValues) {
// increase a little bit the range axis to view all item label values over bars
plot.getRangeAxis().setUpperMargin(0.2);
}
// grid axis visibility & colors
if ((chart.getXShowGrid() != null) && !chart.getXShowGrid()) {
plot.setDomainGridlinesVisible(false);
} else {
if (chart.getXGridColor() != null) {
plot.setDomainGridlinePaint(chart.getXGridColor());
} else {
plot.setDomainGridlinePaint(Color.BLACK);
}
}
if ((chart.getYShowGrid() != null) && !chart.getYShowGrid()) {
plot.setRangeGridlinesVisible(false);
} else {
if (chart.getYGridColor() != null) {
plot.setRangeGridlinePaint(chart.getYGridColor());
} else {
plot.setRangeGridlinePaint(Color.BLACK);
}
}
// chart background
plot.setBackgroundPaint(chart.getBackground());
// labels color
plot.getDomainAxis().setTickLabelPaint(chart.getXColor());
plot.getRangeAxis().setTickLabelPaint(chart.getYColor());
// legend color
plot.getDomainAxis().setLabelPaint(chart.getXLegend().getColor());
plot.getRangeAxis().setLabelPaint(chart.getYLegend().getColor());
// legend font
plot.getDomainAxis().setLabelFont(chart.getXLegend().getFont());
plot.getRangeAxis().setLabelFont(chart.getYLegend().getFont());
// axis color
plot.getDomainAxis().setAxisLinePaint(chart.getxAxisColor());
plot.getRangeAxis().setAxisLinePaint(chart.getyAxisColor());
// hide labels
if ((chart.getXShowLabel() != null) && !chart.getXShowLabel()) {
plot.getDomainAxis().setTickLabelsVisible(false);
plot.getDomainAxis().setTickMarksVisible(false);
}
if ((chart.getYShowLabel() != null) && !chart.getYShowLabel()) {
plot.getRangeAxis().setTickLabelsVisible(false);
plot.getRangeAxis().setTickMarksVisible(false);
}
if (chart.getType().getStyle() == ChartType.STYLE_NORMAL) {
// no shadow
renderer.setShadowVisible(false);
// no gradient
renderer.setBarPainter(new StandardBarPainter());
}
// label orientation
CategoryAxis domainAxis = plot.getDomainAxis();
if (chart.getXorientation() == Chart.VERTICAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 2));
} else if (chart.getXorientation() == Chart.DIAGONAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 4));
} else if (chart.getXorientation() == Chart.HALF_DIAGONAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 8));
}
// labels fonts
domainAxis.setTickLabelFont(chart.getXLabelFont());
plot.getRangeAxis().setTickLabelFont(chart.getYLabelFont());
createChart(plot.getRangeAxis(), charts);
if (isCombo) {
addLineChartOverBar(jfreechart, lineCharts, lineLegend);
}
return jfreechart;
}
// see http://www.java2s.com/Code/Java/Chart/JFreeChartOverlaidBarChartDemo.htm
private JFreeChart addLineChartOverBar(JFreeChart jfreechart, Object[] lineCharts, String lineLegend) throws QueryException {
// first we read data for bar series, so we have to go back at the start of the result set
try {
result.getResultSet().beforeFirst();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
isLineCombo = true;
lineBarDataset = new DefaultCategoryDataset();
boolean hasLegend = false;
for (int i = 0; i < lineCharts.length; i++) {
String legend = "";
try {
legend = replaceParameters(lineLegend);
} catch (IndexOutOfBoundsException ex){
// no legend set
}
if ((legend != null) && !"".equals(legend.trim())) {
hasLegend = true;
}
lineCharts[i] = legend;
}
int index = chart.getYColumns().size()-1;
CategoryPlot plot = jfreechart.getCategoryPlot();
final LineAndShapeRenderer renderer2 = new LineAndShapeRenderer();
plot.setRenderer(1, renderer2);
renderer2.setSeriesPaint(0, chart.getForegrounds().get(index));
final ValueAxis axis2 = new NumberAxis("");
plot.setRangeAxis(1, axis2);
plot.setDataset(1, lineBarDataset);
plot.mapDatasetToRangeAxis(1, 1);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
DecimalFormat decimalFormat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalFormat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalFormat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalFormat;
}
if (showValues) {
renderer2.setSeriesItemLabelsVisible(0, true);
renderer2.setSeriesItemLabelGenerator(0, new StandardCategoryItemLabelGenerator("{2}", decimalFormat, percentageFormat));
// increase a little bit the range axis to view all item label values over points
plot.getRangeAxis(1).setUpperMargin(0.2);
}
final HashMap formatValues = createChart(chart.getYColumns().subList(index, index+1), plot.getRangeAxis(1), lineCharts);
isLineCombo = false;
return jfreechart;
}
private JFreeChart createAreaChart() throws QueryException {
barDataset = new DefaultCategoryDataset();
String chartTitle = replaceParameters(chart.getTitle().getTitle());
chartTitle = StringUtil.getI18nString(chartTitle, I18nUtil.getLanguageByName(chart, language));
Object[] charts = new Object[chart.getYColumns().size()];
List legends = chart.getYColumnsLegends();
boolean hasLegend = false;
for (int i = 0; i < charts.length; i++) {
String legend = "";
try {
legend = replaceParameters(legends.get(i));
legend = StringUtil.getI18nString(legend, I18nUtil.getLanguageByName(chart, language));
} catch (IndexOutOfBoundsException ex){
// no legend set
}
// Important : must have default different legends used in barDataset.addValue
if ((legend == null) || "".equals(legend.trim())) {
legend = DEFAULT_LEGEND_PREFIX + String.valueOf(i+1);
} else {
hasLegend = true;
}
charts[i] = legend;
}
String xLegend = StringUtil.getI18nString(replaceParameters(chart.getXLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
String yLegend = StringUtil.getI18nString(replaceParameters(chart.getYLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
byte style = chart.getType().getStyle();
JFreeChart jfreechart = ChartFactory.createAreaChart(
"Area Chart", // chart title
xLegend, // x-axis Label
yLegend, // y-axis Label
barDataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);
// hide legend if necessary
if (!hasLegend) {
jfreechart.removeLegend();
}
// hide border
jfreechart.setBorderVisible(false);
// title
setTitle(jfreechart);
// chart colors & values shown on bars
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
CategoryPlot plot = (CategoryPlot)jfreechart.getPlot();
plot.setForegroundAlpha(transparency);
AreaRenderer renderer = (AreaRenderer) plot.getRenderer();
DecimalFormat decimalformat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalformat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalformat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalformat;
}
for (int i = 0; i < charts.length; i++) {
renderer.setSeriesPaint(i, chart.getForegrounds().get(i));
if (showValues) {
renderer.setSeriesItemLabelsVisible(i, true);
renderer.setSeriesItemLabelGenerator(i, new StandardCategoryItemLabelGenerator("{2}", decimalformat, percentageFormat));
}
}
if (showValues) {
// increase a little bit the range axis to view all item label values over bars
plot.getRangeAxis().setUpperMargin(0.2);
}
// grid axis visibility & colors
if ((chart.getXShowGrid() != null) && !chart.getXShowGrid()) {
plot.setDomainGridlinesVisible(false);
} else {
if (chart.getXGridColor() != null) {
plot.setDomainGridlinePaint(chart.getXGridColor());
} else {
plot.setDomainGridlinePaint(Color.BLACK);
}
}
if ((chart.getYShowGrid() != null) && !chart.getYShowGrid()) {
plot.setRangeGridlinesVisible(false);
} else {
if (chart.getYGridColor() != null) {
plot.setRangeGridlinePaint(chart.getYGridColor());
} else {
plot.setRangeGridlinePaint(Color.BLACK);
}
}
// chart background
plot.setBackgroundPaint(chart.getBackground());
// labels color
plot.getDomainAxis().setTickLabelPaint(chart.getXColor());
plot.getRangeAxis().setTickLabelPaint(chart.getYColor());
// legend color
plot.getDomainAxis().setLabelPaint(chart.getXLegend().getColor());
plot.getRangeAxis().setLabelPaint(chart.getYLegend().getColor());
// legend font
plot.getDomainAxis().setLabelFont(chart.getXLegend().getFont());
plot.getRangeAxis().setLabelFont(chart.getYLegend().getFont());
// axis color
plot.getDomainAxis().setAxisLinePaint(chart.getxAxisColor());
plot.getRangeAxis().setAxisLinePaint(chart.getyAxisColor());
// hide labels
if ((chart.getXShowLabel() != null) && !chart.getXShowLabel()) {
plot.getDomainAxis().setTickLabelsVisible(false);
plot.getDomainAxis().setTickMarksVisible(false);
}
if ((chart.getYShowLabel() != null) && !chart.getYShowLabel()) {
plot.getRangeAxis().setTickLabelsVisible(false);
plot.getRangeAxis().setTickMarksVisible(false);
}
// label orientation
CategoryAxis domainAxis = plot.getDomainAxis();
if (chart.getXorientation() == Chart.VERTICAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 2));
} else if (chart.getXorientation() == Chart.DIAGONAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 4));
} else if (chart.getXorientation() == Chart.HALF_DIAGONAL) {
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 8));
}
// labels fonts
plot.getDomainAxis().setTickLabelFont(chart.getXLabelFont());
plot.getRangeAxis().setTickLabelFont(chart.getYLabelFont());
createChart(plot.getRangeAxis(), charts);
return jfreechart;
}
private JFreeChart createPieChart() throws QueryException {
pieDataset = new DefaultPieDataset();
String chartTitle = replaceParameters(chart.getTitle().getTitle());
chartTitle = StringUtil.getI18nString(chartTitle, I18nUtil.getLanguageByName(chart, language));
JFreeChart jfreechart = ChartFactory.createPieChart(
chartTitle,
pieDataset,
true,
true,
false);
// hide border
jfreechart.setBorderVisible(false);
// title
setTitle(jfreechart);
PiePlot plot = (PiePlot)jfreechart.getPlot();
plot.setForegroundAlpha(transparency);
// a start angle used to create similarities between flash chart and this jfreechart
plot.setStartAngle(330);
// legend label will contain the text and the value
plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0} = {1}"));
// no shadow
plot.setShadowXOffset(0);
plot.setShadowYOffset(0);
DecimalFormat decimalformat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalformat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalformat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalformat;
}
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
if (showValues) {
// label will contain also the percentage formatted with two decimals
plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} ({2})", decimalformat, percentageFormat));
}
// chart background
plot.setBackgroundPaint(chart.getBackground());
createChart(null, new Object[1]);
// after chart creation we can set slices colors
List keys = pieDataset.getKeys();
List colors = chart.getForegrounds();
for (int i = 0, size = colors.size(); i < keys.size(); i++) {
plot.setSectionPaint(keys.get(i), colors.get(i % size));
plot.setLabelFont(chart.getFont());
}
return jfreechart;
}
private JFreeChart createBubbleChart() throws QueryException {
bubbleDataset = new DefaultXYZDataset();
// x, y are inverted for jfree bubble chart!
// that's why we use minX & maxX values to compute Tu (tickUnit)
String chartTitle = replaceParameters(chart.getTitle().getTitle());
chartTitle = StringUtil.getI18nString(chartTitle, I18nUtil.getLanguageByName(chart, language));
String xLegend = StringUtil.getI18nString(replaceParameters(chart.getYLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
String yLegend = StringUtil.getI18nString(replaceParameters(chart.getXLegend().getTitle()), I18nUtil.getLanguageByName(chart, language));
JFreeChart jfreechart = ChartFactory.createBubbleChart(
chartTitle,
xLegend, // x-axis Label
yLegend, // y-axis Label
bubbleDataset,
PlotOrientation.HORIZONTAL,
true,
true,
false);
// hide border
jfreechart.setBorderVisible(false);
// title
setTitle(jfreechart);
boolean showValues = (chart.getShowYValuesOnChart() == null) ? false : chart.getShowYValuesOnChart();
XYPlot xyplot = (XYPlot) jfreechart.getPlot();
xyplot.setForegroundAlpha(transparency);
XYItemRenderer xyitemrenderer = xyplot.getRenderer();
DecimalFormat decimalformat;
DecimalFormat percentageFormat;
if (chart.getYTooltipPattern() == null) {
decimalformat = new DecimalFormat("#");
percentageFormat = new DecimalFormat("0.00%");
} else {
decimalformat = new DecimalFormat(chart.getYTooltipPattern());
percentageFormat = decimalformat;
}
if (showValues) {
// increase a little bit the range axis to view all item label values over bars
xyplot.getRangeAxis().setUpperMargin(0.2);
}
// grid axis visibility & colors
if ((chart.getXShowGrid() != null) && !chart.getXShowGrid()) {
xyplot.setDomainGridlinesVisible(false);
} else {
if (chart.getXGridColor() != null) {
xyplot.setDomainGridlinePaint(chart.getXGridColor());
} else {
xyplot.setDomainGridlinePaint(Color.BLACK);
}
}
if ((chart.getYShowGrid() != null) && !chart.getYShowGrid()) {
xyplot.setRangeGridlinesVisible(false);
} else {
if (chart.getYGridColor() != null) {
xyplot.setRangeGridlinePaint(chart.getYGridColor());
} else {
xyplot.setRangeGridlinePaint(Color.BLACK);
}
}
// chart background
xyplot.setBackgroundPaint(chart.getBackground());
// labels color
xyplot.getDomainAxis().setTickLabelPaint(chart.getXColor());
xyplot.getRangeAxis().setTickLabelPaint(chart.getYColor());
// legend color
xyplot.getDomainAxis().setLabelPaint(chart.getXLegend().getColor());
xyplot.getRangeAxis().setLabelPaint(chart.getYLegend().getColor());
// legend font
xyplot.getDomainAxis().setLabelFont(chart.getXLegend().getFont());
xyplot.getRangeAxis().setLabelFont(chart.getYLegend().getFont());
// axis color
xyplot.getDomainAxis().setAxisLinePaint(chart.getxAxisColor());
xyplot.getRangeAxis().setAxisLinePaint(chart.getyAxisColor());
// hide labels
if ((chart.getXShowLabel() != null) && !chart.getXShowLabel()) {
xyplot.getDomainAxis().setTickLabelsVisible(false);
xyplot.getDomainAxis().setTickMarksVisible(false);
}
if ((chart.getYShowLabel() != null) && !chart.getYShowLabel()) {
xyplot.getRangeAxis().setTickLabelsVisible(false);
xyplot.getRangeAxis().setTickMarksVisible(false);
}
// label orientation
ValueAxis domainAxis = xyplot.getDomainAxis();
if (chart.getXorientation() == Chart.VERTICAL) {
domainAxis.setLabelAngle(Math.PI / 2);
} else if (chart.getXorientation() == Chart.DIAGONAL) {
domainAxis.setLabelAngle(Math.PI / 4);
} else if (chart.getXorientation() == Chart.HALF_DIAGONAL) {
domainAxis.setLabelAngle(Math.PI / 8);
}
// labels fonts
xyplot.getDomainAxis().setTickLabelFont(chart.getXLabelFont());
xyplot.getRangeAxis().setTickLabelFont(chart.getYLabelFont());
createChart(xyplot.getRangeAxis(), new Object[4]);
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
double maxZ = Double.MIN_VALUE;
for (String serie : bubbleData.keySet()) {
XYZList xyzList = bubbleData.get(serie);
List yList = xyzList.getyList();
for (Number n : yList) {
minY = Math.min(minY, n.doubleValue());
maxY = Math.max(maxY, n.doubleValue());
}
List xList = xyzList.getxList();
for (Number n : xList) {
minX = Math.min(minX, n.doubleValue());
maxX = Math.max(maxX, n.doubleValue());
}
List zList = xyzList.getzList();
for (Number n : zList) {
maxZ = Math.max(maxZ, n.doubleValue());
}
}
double tu = Math.floor((maxX-minX)/5 +0.5d);
NumberTickUnit rUnit = new NumberTickUnit(tu);
((NumberAxis) xyplot.getRangeAxis()).setTickUnit(rUnit);
// make the bubble with text fit on X axis (which is shown vertically!)
xyplot.getDomainAxis().setUpperMargin(0.2);
xyplot.getDomainAxis().setLowerMargin(0.2);
for (String serie : bubbleData.keySet()) {
XYZList xyzList = bubbleData.get(serie);
double[][] data = { getDoubleArray(xyzList.getyList()), getDoubleArray(xyzList.getxList()), getZDoubleArray(xyzList.getzList(), tu, maxZ) };
bubbleDataset.addSeries(serie, data);
}
int series = bubbleData.keySet().size();
for (int i = 0; i < series; i++) {
xyitemrenderer.setSeriesPaint(i, chart.getForegrounds().get(i));
if (showValues) {
xyitemrenderer.setSeriesItemLabelsVisible(i, true);
xyitemrenderer.setSeriesItemLabelGenerator(i, new StandardXYItemLabelGenerator("{2}", decimalformat, percentageFormat));
}
}
// show labels on bubbles
xyitemrenderer.setBaseItemLabelsVisible(true);
xyitemrenderer.setBaseItemLabelGenerator(new LegendXYItemLabelGenerator());
return jfreechart;
}
public class LegendXYItemLabelGenerator extends StandardXYItemLabelGenerator implements XYItemLabelGenerator, Cloneable, PublicCloneable, Serializable {
public LegendXYItemLabelGenerator() {
super();
}
@Override
public String generateLabel(XYDataset dataset, int series, int item) {
String[] keys = new String[bubbleData.size()];
bubbleData.keySet().toArray(keys);
String legend = bubbleData.get(keys[series]).getLabels().get(item);
legend = StringUtil.getI18nString(legend, I18nUtil.getLanguageByName(chart, language));
return legend;
}
}
private void setTitle(JFreeChart jfreechart) {
TextTitle title = new TextTitle(StringUtil.getI18nString(replaceParameters(chart.getTitle().getTitle()), I18nUtil.getLanguageByName(chart, language)));
title.setFont(chart.getTitle().getFont());
title.setPaint(chart.getTitle().getColor());
if (chart.getTitle().getAlignment() == ChartTitle.LEFT_ALIGNMENT) {
title.setHorizontalAlignment(HorizontalAlignment.LEFT);
} else if (chart.getTitle().getAlignment() == ChartTitle.RIGHT_ALIGNMENT) {
title.setHorizontalAlignment(HorizontalAlignment.RIGHT);
} else {
title.setHorizontalAlignment(HorizontalAlignment.CENTER);
}
jfreechart.setTitle(title);
}
private HashMap createChart(ValueAxis rangeAxis, Object[] charts) throws QueryException {
return createChart(chart.getYColumns(), rangeAxis, charts);
}
private HashMap createChart(List yColumns, ValueAxis rangeAxis, Object[] charts) throws QueryException {
int row = 0;
Object previous = null;
String xColumn = chart.getXColumn();
String xPattern = chart.getXPattern();
String lastXValue = "";
HashMap formatValues = new HashMap();
Number min = Double.MAX_VALUE;
Number max = Double.MIN_VALUE;
int chartsNo = charts.length;
int[] index = new int[chartsNo];
GFunction[] functions = new GFunction[chartsNo];
for (int i = 0; i < chartsNo; i++) {
functions[i] = FunctionFactory.getFunction(chart.getYFunction());
index[i] = 1;
}
boolean isStacked = chart.getType().isStacked();
while (result.hasNext()) {
Object[] objects = new Object[chartsNo];
Number[] computedValues = new Number[chartsNo];
String currentCategory = null;
for (int i = 0; i < chartsNo; i++) {
if (yColumns.get(i) != null) {
objects[i] = result.nextValue(yColumns.get(i));
Number value = null;
String sv = null;
if (objects[i] instanceof Number) {
value = (Number) objects[i];
} else if (objects[i] != null){
if (ChartType.BUBBLE == chart.getType().getType()) {
sv = (String)objects[i];
}
value = 1;
integerXValue = false;
} else {
value = 0;
}
computedValues[i] = value;
if (sv != null) {
currentCategory = sv;
}
}
}
Object xValue = null;
if (row == 0) {
xValue = result.nextValue(xColumn);
lastXObjValue = xValue;
lastXValue = getStringValue(xColumn, xPattern);
} else {
xValue = previous;
}
Object newXValue = result.nextValue(xColumn);
boolean add = false;
int position = 0;
// no function : add the value
if (AbstractGFunction.NOOP.equals(functions[0].getName())) {
lastXValue = getStringValue(xColumn, xPattern);
add = true;
// compute function
} else {
boolean equals = FunctionUtil.parameterEquals(xValue, newXValue);
if (equals) {
for (int i = 0; i < chartsNo; i++) {
functions[i].compute(objects[i]);
}
} else {
for (int i = 0; i < chartsNo; i++) {
position = i;
add = true;
computedValues[i] = (Number) functions[i].getComputedValue();
functions[i].reset();
functions[i].compute(objects[i]);
}
}
}
if (add) {
Number n;
Number sum = 0;
if (xValue instanceof Number) {
n = (Number)newXValue;
} else {
integerXValue = false;
n = index[position]++;
}
if (chart.getType().isBubble()) {
XYZList xyzList = bubbleData.get(currentCategory);
if (xyzList == null) {
xyzList = new XYZList();
bubbleData.put(currentCategory, xyzList);
}
xyzList.getxList().add(computedValues[0]);
xyzList.getyList().add(computedValues[1]);
xyzList.getzList().add(computedValues[2]);
min = Math.min(min.doubleValue(), computedValues[0].doubleValue());
max = Math.max(max.doubleValue(), computedValues[0].doubleValue());
} else {
for (int i = 0; i < chartsNo; i++) {
addValue(charts[i], n, lastXValue, computedValues[i], formatValues);
if (!isStacked) {
min = Math.min(min.doubleValue(), computedValues[i].doubleValue());
max = Math.max(max.doubleValue(), computedValues[i].doubleValue());
} else {
sum = sum.doubleValue() + computedValues[i].doubleValue();
}
}
}
if ((chart.getStartingFromZero() != null) && chart.getStartingFromZero() && (min.intValue() > 0)) {
min = 0;
}
if (isStacked) {
min = 0;
max = Math.max(max.doubleValue(), sum.doubleValue());
}
lastXValue = getStringValue(xColumn, xPattern);
if (ChartType.BUBBLE == chart.getType().getType()) {
XYZList xyzList = bubbleData.get(currentCategory);
xyzList.getLabels().add(lastXValue);
}
}
row++;
previous = newXValue;
}
// last group
if (!AbstractGFunction.NOOP.equals(functions[0].getName())) {
Number n;
Number sum = 0;
if (lastXObjValue instanceof Number) {
n = (Number)lastXObjValue;
} else {
integerXValue = false;
n = index[chartsNo-1]++;
}
for (int i = 0; i < chartsNo; i++) {
Number value = (Number) functions[i].getComputedValue();
addValue(charts[i], n, lastXValue, value, formatValues);
if (!isStacked) {
min = Math.min(min.doubleValue(), value.doubleValue());
max = Math.max(max.doubleValue(), value.doubleValue());
} else {
sum = sum.doubleValue() + value.doubleValue();
}
}
if ((chart.getStartingFromZero() != null) && chart.getStartingFromZero() && (min.intValue() > 0)) {
min = 0;
}
if (isStacked) {
min = 0;
max = Math.max(max.doubleValue(), sum.doubleValue());
}
}
setAxisRange(rangeAxis, min, max);
return formatValues;
}
// take care if no function is set : every value is in a differnet category (we use an incremental integer : serie)
private void addValue(Object chartSerie, Number x, String lastXValue, Number y, HashMap formatValues) {
if (chart.getType().isLine()) {
((XYSeries)chartSerie).add(x, y);
} else if (isLineCombo) {
lineBarDataset.addValue(y, (String)chartSerie, lastXValue);
} else if (!chart.getType().isPie()) {
GFunction function = FunctionFactory.getFunction(chart.getYFunction());
if (!AbstractGFunction.NOOP.equals(function.getName())) {
barDataset.setValue(y, (String)chartSerie, lastXValue);
} else {
int serie = 0;
Integer i = xValueSerie.get(lastXValue);
if (i != null) {
serie = i+1;
xValueSerie.put(lastXValue, serie);
barDataset.setValue(y, (String)chartSerie, lastXValue + " (" + serie + ")");
} else {
barDataset.setValue(y, (String)chartSerie, lastXValue);
xValueSerie.put(lastXValue, 0);
}
}
} else if (chart.getType().isPie()) {
if (AbstractGFunction.NOOP.equals(chart.getYFunction())) {
int serie = 0;
Integer i = xValueSerie.get(lastXValue);
if (i != null) {
serie = i+1;
xValueSerie.put(lastXValue, serie);
pieDataset.setValue(lastXValue + " (" + serie + ")", y);
} else {
pieDataset.setValue(lastXValue, y);
xValueSerie.put(lastXValue, 0);
}
} else {
pieDataset.setValue(lastXValue, y);
}
}
formatValues.put(x.toString(), lastXValue);
}
private String getStringValue(String column, String pattern) throws QueryException {
Object xObject = result.nextValue(column);
lastXObjValue = xObject;
return StringUtil.getValueAsString(xObject, pattern);
}
public String getChartImageName() {
return chartImageName;
}
public String getChartImageAbsolutePath() {
File file = new File(path + File.separator+ chartImageName);
return file.getAbsolutePath();
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
// replace $P{...} parameters (used in title and x,y legends
private String replaceParameters(String text) {
if (text == null) {
return null;
}
for (String param : parameterValues.keySet()) {
text = StringUtil.replace(text, "\\$P\\{" + param + "\\}", StringUtil.getValueAsString(parameterValues.get(param), null,I18nUtil.getLanguageByName(chart, language)));
}
return text;
}
private void setAxisRange(ValueAxis rangeAxis, Number min, Number max) {
if (rangeAxis == null) {
return;
}
YRange yRange = new YRange(min, max);
yRange = yRange.update();
rangeAxis.setRange(new Range(yRange.getMin().doubleValue(), yRange.getMax().doubleValue()));
}
private double[] getDoubleArray(List list) {
double[] result = new double[list.size()];
for (int i=0, size=list.size(); i zList, double tu, double maxZ) {
double[] result = new double[zList.size()];
for (int i=0, size=zList.size(); i