1 /* ================================================================
2 * Cewolf : Chart enabling Web Objects Framework
3 * ================================================================
5 * Project Info: http://cewolf.sourceforge.net
6 * Project Lead: Guido Laures (guido@laures.de);
8 * (C) Copyright 2002, by Guido Laures
10 * This library is free software; you can redistribute it and/or modify it under the terms
11 * of the GNU Lesser General Public License as published by the Free Software Foundation;
12 * either version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License along with this
19 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
23 package de.laures.cewolf.taglib;
25 import java.util.HashMap;
26 import java.util.List;
29 import org.jfree.chart.ChartFactory;
30 import org.jfree.chart.JFreeChart;
31 import org.jfree.chart.axis.CategoryAxis;
32 import org.jfree.chart.axis.DateAxis;
33 import org.jfree.chart.axis.NumberAxis;
34 import org.jfree.chart.axis.ValueAxis;
35 import org.jfree.chart.plot.CategoryPlot;
36 import org.jfree.chart.plot.CombinedDomainXYPlot;
37 import org.jfree.chart.plot.CombinedRangeXYPlot;
38 import org.jfree.chart.plot.MeterPlot;
39 import org.jfree.chart.plot.Plot;
40 import org.jfree.chart.plot.PlotOrientation;
41 import org.jfree.chart.plot.XYPlot;
42 import org.jfree.chart.renderer.category.CategoryItemRenderer;
43 import org.jfree.chart.renderer.xy.XYItemRenderer;
44 import org.jfree.data.category.CategoryDataset;
45 import org.jfree.data.category.IntervalCategoryDataset;
46 import org.jfree.data.general.Dataset;
47 import org.jfree.data.general.PieDataset;
48 import org.jfree.data.general.ValueDataset;
49 import org.jfree.data.xy.IntervalXYDataset;
50 import org.jfree.data.xy.OHLCDataset;
51 import org.jfree.data.xy.WindDataset;
52 import org.jfree.data.xy.XYDataset;
53 import org.jfree.data.xy.XYZDataset;
55 import de.laures.cewolf.ChartValidationException;
56 import de.laures.cewolf.DatasetProduceException;
59 * Chart factory creates Jfreechart instances. To add a new factory use the
61 * CewolfChartFactory.registerFactory(new CewolfChartFactory() {...});
65 * @author Guido Laures
67 public abstract class CewolfChartFactory implements ChartConstants, AxisConstants, LayoutConstants {
70 protected String chartType;
71 // map contains registered factories, (String) chartType->CewolfChartFactory mappings
72 private static Map factories = new HashMap();
74 /** Creates a new instance of ChartFactory */
75 protected CewolfChartFactory(String chartType) {
76 this.chartType = chartType;
80 * Callback when the chart instance to be created.
81 * @param title The title of chart
82 * @param xAxisLabel label on x axis
83 * @param yAxisLabel label on y axis
84 * @param data The dataset to create chart for
85 * @return The newly created JFreeChart instance
87 * @throws IncompatibleDatasetException If the incoming data is not compatible with this factory
89 public abstract JFreeChart getChartInstance(String title, String xAxisLabel, String yAxisLabel, Dataset data) throws IncompatibleDatasetException;
91 //////////////// static part ///////////////////////
94 * Register a new chart factory instance.
95 * @param factory The factory to register
97 public static void registerFactory(CewolfChartFactory factory) {
98 factories.put(factory.chartType, factory);
101 private static final int getChartTypeConstant(String type) {
102 final int res = ChartTypes.typeList.indexOf(type.toLowerCase());
104 throw new RuntimeException("unsupported chart type " + type);
109 private static final int getLayoutConstant(String layout) {
110 return LayoutTypes.typeList.indexOf(layout.toLowerCase());
114 // histogram chart type
115 registerFactory(new CewolfChartFactory("histogram") {
116 public JFreeChart getChartInstance(String title, String xAxisLabel, String yAxisLabel, Dataset data) throws IncompatibleDatasetException {
117 check(data, IntervalXYDataset.class, this.chartType);
118 return ChartFactory.createHistogram(title, xAxisLabel, yAxisLabel, (IntervalXYDataset) data, PlotOrientation.VERTICAL, true, false, false);
123 public static JFreeChart getChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, Dataset data) throws ChartValidationException {
124 // first check the dynamically registered chart types
125 CewolfChartFactory factory = (CewolfChartFactory) factories.get(chartType);
126 if (factory != null) {
127 // custom factory found, use it
128 return factory.getChartInstance(title, xAxisLabel, yAxisLabel, data);
131 switch (getChartTypeConstant(chartType)) {
133 check(data, XYDataset.class, chartType);
134 return ChartFactory.createXYLineChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, true, true);
136 check(data, PieDataset.class, chartType);
137 return ChartFactory.createPieChart(title, (PieDataset) data, true, true, true);
139 check(data, XYDataset.class, chartType);
140 return ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, false, false);
142 check(data, XYDataset.class, chartType);
143 return ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, false, false);
145 check(data, CategoryDataset.class, chartType);
146 return ChartFactory.createAreaChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
147 case HORIZONTAL_BAR :
148 check(data, CategoryDataset.class, chartType);
149 return ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
150 case HORIZONTAL_BAR_3D :
151 check(data, CategoryDataset.class, chartType);
152 return ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
154 check(data, CategoryDataset.class, chartType);
155 return ChartFactory.createLineChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
156 case STACKED_HORIZONTAL_BAR :
157 check(data, CategoryDataset.class, chartType);
158 return ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
159 case STACKED_VERTICAL_BAR :
160 check(data, CategoryDataset.class, chartType);
161 return ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
162 case STACKED_VERTICAL_BAR_3D :
163 check(data, CategoryDataset.class, chartType);
164 return ChartFactory.createStackedBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
166 check(data, CategoryDataset.class, chartType);
167 return ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
168 case VERTICAL_BAR_3D :
169 check(data, CategoryDataset.class, chartType);
170 return ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
172 check(data, XYDataset.class, chartType);
173 return ChartFactory.createTimeSeriesChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, true, false, false);
175 check(data, OHLCDataset.class, chartType);
176 return ChartFactory.createCandlestickChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
178 check(data, OHLCDataset.class, chartType);
179 return ChartFactory.createHighLowChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
181 check(data, IntervalCategoryDataset.class, chartType);
182 return ChartFactory.createGanttChart(title, xAxisLabel, yAxisLabel, (IntervalCategoryDataset) data, true, false, false);
184 check(data, WindDataset.class, chartType);
185 return ChartFactory.createWindPlot(title, xAxisLabel, yAxisLabel, (WindDataset) data, true, false, false);
187 // check(data, SignalsDataset.class, chartType);
188 // return ChartFactory.createSignalChart(title, xAxisLabel, yAxisLabel, (SignalsDataset) data, true);
189 case VERRTICAL_XY_BAR :
190 check(data, IntervalXYDataset.class, chartType);
191 return ChartFactory.createXYBarChart(title, xAxisLabel, true,yAxisLabel, (IntervalXYDataset) data, PlotOrientation.VERTICAL, true, false, false);
193 check(data, PieDataset.class, chartType);
194 return ChartFactory.createPieChart3D(title, (PieDataset) data, true, false, false);
196 check(data, ValueDataset.class, chartType);
197 MeterPlot plot = new MeterPlot((ValueDataset) data);
198 JFreeChart chart = new JFreeChart(title, plot);
201 check(data, CategoryDataset.class, chartType);
202 return ChartFactory.createStackedAreaChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
204 check(data, XYZDataset.class, chartType);
205 return ChartFactory.createBubbleChart(title, xAxisLabel, yAxisLabel, (XYZDataset) data, PlotOrientation.VERTICAL, true, false, false);
207 throw new UnsupportedChartTypeException(chartType + " is not supported.");
211 public static JFreeChart getOverlaidChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, int xAxisType, int yAxisType, List plotDefinitions)
212 throws ChartValidationException, DatasetProduceException {
213 final int chartTypeConst = getChartTypeConstant(chartType);
214 final AxisFactory axisFactory = AxisFactory.getInstance();
215 switch (chartTypeConst) {
217 ValueAxis domainAxis = (ValueAxis) axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
219 PlotDefinition mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
220 check((Dataset) mainPlotDef.getDataset(), XYDataset.class, chartType);
221 XYPlot plot = (XYPlot) mainPlotDef.getPlot(chartTypeConst);
222 plot.setDomainAxis(domainAxis);
223 plot.setRangeAxis((ValueAxis) axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
224 //plot.setRenderer(new StandardXYItemRenderer());
225 // add second and later datasets to main plot
226 for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
227 PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
228 check((Dataset) subPlotDef.getDataset(), XYDataset.class, chartType);
229 plot.setDataset(plotidx, (XYDataset)subPlotDef.getDataset());
231 int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
232 XYItemRenderer rend = (XYItemRenderer) PlotTypes.getRenderer(rendererIndex);
233 plot.setRenderer(plotidx, rend);
235 return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
236 case OVERLAY_CATEGORY ://added by lrh 2005-07-11
237 CategoryAxis domainAxis2 = (CategoryAxis)axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
239 mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
240 check((Dataset) mainPlotDef.getDataset(), CategoryDataset.class, chartType);
241 CategoryPlot plot2 = (CategoryPlot) mainPlotDef.getPlot(chartTypeConst);
242 plot2.setDomainAxis(domainAxis2);
243 plot2.setRangeAxis((ValueAxis)axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
244 //plot.setRenderer(new StandardXYItemRenderer());
245 // add second and later datasets to main plot
246 for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
247 PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
248 check((Dataset) subPlotDef.getDataset(), CategoryDataset.class, chartType);
249 plot2.setDataset(plotidx, (CategoryDataset)subPlotDef.getDataset());
251 int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
252 CategoryItemRenderer rend2 = (CategoryItemRenderer) PlotTypes.getRenderer(rendererIndex);
253 plot2.setRenderer(plotidx, rend2);
255 return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot2, true);
257 throw new UnsupportedChartTypeException(chartType + " is not supported.");
262 public static JFreeChart getCombinedChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, List plotDefinitions, String layout)
263 throws ChartValidationException, DatasetProduceException {
264 final int chartTypeConst = getChartTypeConstant(chartType);
265 switch (chartTypeConst) {
267 final int layoutConst = getLayoutConstant(layout);
269 switch (layoutConst) {
271 ValueAxis domainAxis = new DateAxis(xAxisLabel);
272 plot = new CombinedDomainXYPlot(domainAxis);
273 for (int i = 0; i < plotDefinitions.size(); i++) {
274 PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
275 check((Dataset) pd.getDataset(), XYDataset.class, chartType);
276 XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
277 temp.setRangeAxis(new NumberAxis(pd.getYaxislabel()));
278 ((CombinedDomainXYPlot) plot).add(temp);
280 return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
282 ValueAxis rangeAxis = new NumberAxis(yAxisLabel);
283 plot = new CombinedRangeXYPlot(rangeAxis);
284 for (int i = 0; i < plotDefinitions.size(); i++) {
285 PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
286 check((Dataset) pd.getDataset(), XYDataset.class, chartType);
287 XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
288 temp.setDomainAxis(new DateAxis(pd.getXaxislabel()));
289 ((CombinedRangeXYPlot) plot).add(temp);
291 return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
293 throw new AttributeValidationException(layout, " any value");
296 throw new UnsupportedChartTypeException(chartType);
301 * Helper to check if the given dataset is the expected type.
302 * @param data The dataset
303 * @param clazz Expected type (class)
304 * @param chartType The chart type string
305 * @throws IncompatibleDatasetException If not the expected class
307 public static void check(Dataset data, Class clazz, String chartType) throws IncompatibleDatasetException {
308 if (!clazz.isInstance(data)) {
309 throw new IncompatibleDatasetException("Charts of type " + chartType + " " + "need datasets of type " + clazz.getName());