001: /* ================================================================
002: * Cewolf : Chart enabling Web Objects Framework
003: * ================================================================
004: *
005: * Project Info: http://cewolf.sourceforge.net
006: * Project Lead: Guido Laures (guido@laures.de);
007: *
008: * (C) Copyright 2002, by Guido Laures
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package de.laures.cewolf.taglib;
024:
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028:
029: import org.jfree.chart.ChartFactory;
030: import org.jfree.chart.JFreeChart;
031: import org.jfree.chart.axis.CategoryAxis;
032: import org.jfree.chart.axis.DateAxis;
033: import org.jfree.chart.axis.NumberAxis;
034: import org.jfree.chart.axis.ValueAxis;
035: import org.jfree.chart.plot.CategoryPlot;
036: import org.jfree.chart.plot.CombinedDomainXYPlot;
037: import org.jfree.chart.plot.CombinedRangeXYPlot;
038: import org.jfree.chart.plot.MeterPlot;
039: import org.jfree.chart.plot.Plot;
040: import org.jfree.chart.plot.PlotOrientation;
041: import org.jfree.chart.plot.XYPlot;
042: import org.jfree.chart.renderer.category.CategoryItemRenderer;
043: import org.jfree.chart.renderer.xy.XYItemRenderer;
044: import org.jfree.data.category.CategoryDataset;
045: import org.jfree.data.category.IntervalCategoryDataset;
046: import org.jfree.data.general.Dataset;
047: import org.jfree.data.general.PieDataset;
048: import org.jfree.data.general.ValueDataset;
049: import org.jfree.data.xy.IntervalXYDataset;
050: import org.jfree.data.xy.OHLCDataset;
051: import org.jfree.data.xy.WindDataset;
052: import org.jfree.data.xy.XYDataset;
053: import org.jfree.data.xy.XYZDataset;
054:
055: import de.laures.cewolf.ChartValidationException;
056: import de.laures.cewolf.DatasetProduceException;
057:
058: /**
059: * Chart factory creates Jfreechart instances. To add a new factory use the
060: * <code>
061: * CewolfChartFactory.registerFactory(new CewolfChartFactory() {...});
062: * </code>
063: * method.
064: *
065: * @author Guido Laures
066: */
067: public abstract class CewolfChartFactory implements ChartConstants,
068: AxisConstants, LayoutConstants {
069:
070: // chart type string
071: protected String chartType;
072: // map contains registered factories, (String) chartType->CewolfChartFactory mappings
073: private static Map factories = new HashMap();
074:
075: /** Creates a new instance of ChartFactory */
076: protected CewolfChartFactory(String chartType) {
077: this .chartType = chartType;
078: }
079:
080: /**
081: * Callback when the chart instance to be created.
082: * @param title The title of chart
083: * @param xAxisLabel label on x axis
084: * @param yAxisLabel label on y axis
085: * @param data The dataset to create chart for
086: * @return The newly created JFreeChart instance
087: *
088: * @throws IncompatibleDatasetException If the incoming data is not compatible with this factory
089: */
090: public abstract JFreeChart getChartInstance(String title,
091: String xAxisLabel, String yAxisLabel, Dataset data)
092: throws IncompatibleDatasetException;
093:
094: //////////////// static part ///////////////////////
095:
096: /**
097: * Register a new chart factory instance.
098: * @param factory The factory to register
099: */
100: public static void registerFactory(CewolfChartFactory factory) {
101: factories.put(factory.chartType, factory);
102: }
103:
104: private static final int getChartTypeConstant(String type) {
105: final int res = ChartTypes.typeList.indexOf(type.toLowerCase());
106: if (res < 0) {
107: throw new RuntimeException("unsupported chart type " + type);
108: }
109: return res;
110: }
111:
112: private static final int getLayoutConstant(String layout) {
113: return LayoutTypes.typeList.indexOf(layout.toLowerCase());
114: }
115:
116: static {
117: // histogram chart type
118: registerFactory(new CewolfChartFactory("histogram") {
119: public JFreeChart getChartInstance(String title,
120: String xAxisLabel, String yAxisLabel, Dataset data)
121: throws IncompatibleDatasetException {
122: check(data, IntervalXYDataset.class, this .chartType);
123: return ChartFactory.createHistogram(title, xAxisLabel,
124: yAxisLabel, (IntervalXYDataset) data,
125: PlotOrientation.VERTICAL, true, false, false);
126: }
127: });
128: }
129:
130: public static JFreeChart getChartInstance(String chartType,
131: String title, String xAxisLabel, String yAxisLabel,
132: Dataset data) throws ChartValidationException {
133: // first check the dynamically registered chart types
134: CewolfChartFactory factory = (CewolfChartFactory) factories
135: .get(chartType);
136: if (factory != null) {
137: // custom factory found, use it
138: return factory.getChartInstance(title, xAxisLabel,
139: yAxisLabel, data);
140: }
141:
142: switch (getChartTypeConstant(chartType)) {
143: case XY:
144: check(data, XYDataset.class, chartType);
145: return ChartFactory.createXYLineChart(title, xAxisLabel,
146: yAxisLabel, (XYDataset) data,
147: PlotOrientation.VERTICAL, true, true, true);
148: case PIE:
149: check(data, PieDataset.class, chartType);
150: return ChartFactory.createPieChart(title,
151: (PieDataset) data, true, true, true);
152: case AREA_XY:
153: check(data, XYDataset.class, chartType);
154: return ChartFactory.createXYAreaChart(title, xAxisLabel,
155: yAxisLabel, (XYDataset) data,
156: PlotOrientation.VERTICAL, true, false, false);
157: case SCATTER:
158: check(data, XYDataset.class, chartType);
159: return ChartFactory.createScatterPlot(title, xAxisLabel,
160: yAxisLabel, (XYDataset) data,
161: PlotOrientation.VERTICAL, true, false, false);
162: case AREA:
163: check(data, CategoryDataset.class, chartType);
164: return ChartFactory.createAreaChart(title, xAxisLabel,
165: yAxisLabel, (CategoryDataset) data,
166: PlotOrientation.VERTICAL, true, false, false);
167: case HORIZONTAL_BAR:
168: check(data, CategoryDataset.class, chartType);
169: return ChartFactory.createBarChart(title, xAxisLabel,
170: yAxisLabel, (CategoryDataset) data,
171: PlotOrientation.HORIZONTAL, true, false, false);
172: case HORIZONTAL_BAR_3D:
173: check(data, CategoryDataset.class, chartType);
174: return ChartFactory.createBarChart3D(title, xAxisLabel,
175: yAxisLabel, (CategoryDataset) data,
176: PlotOrientation.HORIZONTAL, true, false, false);
177: case LINE:
178: check(data, CategoryDataset.class, chartType);
179: return ChartFactory.createLineChart(title, xAxisLabel,
180: yAxisLabel, (CategoryDataset) data,
181: PlotOrientation.VERTICAL, true, false, false);
182: case STACKED_HORIZONTAL_BAR:
183: check(data, CategoryDataset.class, chartType);
184: return ChartFactory.createStackedBarChart(title,
185: xAxisLabel, yAxisLabel, (CategoryDataset) data,
186: PlotOrientation.HORIZONTAL, true, false, false);
187: case STACKED_VERTICAL_BAR:
188: check(data, CategoryDataset.class, chartType);
189: return ChartFactory.createStackedBarChart(title,
190: xAxisLabel, yAxisLabel, (CategoryDataset) data,
191: PlotOrientation.VERTICAL, true, false, false);
192: case STACKED_VERTICAL_BAR_3D:
193: check(data, CategoryDataset.class, chartType);
194: return ChartFactory.createStackedBarChart3D(title,
195: xAxisLabel, yAxisLabel, (CategoryDataset) data,
196: PlotOrientation.VERTICAL, true, false, false);
197: case VERTICAL_BAR:
198: check(data, CategoryDataset.class, chartType);
199: return ChartFactory.createBarChart(title, xAxisLabel,
200: yAxisLabel, (CategoryDataset) data,
201: PlotOrientation.VERTICAL, true, false, false);
202: case VERTICAL_BAR_3D:
203: check(data, CategoryDataset.class, chartType);
204: return ChartFactory.createBarChart3D(title, xAxisLabel,
205: yAxisLabel, (CategoryDataset) data,
206: PlotOrientation.VERTICAL, true, false, false);
207: case TIME_SERIES:
208: check(data, XYDataset.class, chartType);
209: return ChartFactory.createTimeSeriesChart(title,
210: xAxisLabel, yAxisLabel, (XYDataset) data, true,
211: false, false);
212: case CANDLE_STICK:
213: check(data, OHLCDataset.class, chartType);
214: return ChartFactory.createCandlestickChart(title,
215: xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
216: case HIGH_LOW:
217: check(data, OHLCDataset.class, chartType);
218: return ChartFactory.createHighLowChart(title, xAxisLabel,
219: yAxisLabel, (OHLCDataset) data, true);
220: case GANTT:
221: check(data, IntervalCategoryDataset.class, chartType);
222: return ChartFactory.createGanttChart(title, xAxisLabel,
223: yAxisLabel, (IntervalCategoryDataset) data, true,
224: false, false);
225: case WIND:
226: check(data, WindDataset.class, chartType);
227: return ChartFactory.createWindPlot(title, xAxisLabel,
228: yAxisLabel, (WindDataset) data, true, false, false);
229: //case SIGNAL :
230: // check(data, SignalsDataset.class, chartType);
231: // return ChartFactory.createSignalChart(title, xAxisLabel, yAxisLabel, (SignalsDataset) data, true);
232: case VERRTICAL_XY_BAR:
233: check(data, IntervalXYDataset.class, chartType);
234: return ChartFactory.createXYBarChart(title, xAxisLabel,
235: true, yAxisLabel, (IntervalXYDataset) data,
236: PlotOrientation.VERTICAL, true, false, false);
237: case PIE_3D:
238: check(data, PieDataset.class, chartType);
239: return ChartFactory.createPieChart3D(title,
240: (PieDataset) data, true, false, false);
241: case METER:
242: check(data, ValueDataset.class, chartType);
243: MeterPlot plot = new MeterPlot((ValueDataset) data);
244: JFreeChart chart = new JFreeChart(title, plot);
245: return chart;
246: case STACKED_AREA:
247: check(data, CategoryDataset.class, chartType);
248: return ChartFactory.createStackedAreaChart(title,
249: xAxisLabel, yAxisLabel, (CategoryDataset) data,
250: PlotOrientation.VERTICAL, true, false, false);
251: case BUBBLE:
252: check(data, XYZDataset.class, chartType);
253: return ChartFactory.createBubbleChart(title, xAxisLabel,
254: yAxisLabel, (XYZDataset) data,
255: PlotOrientation.VERTICAL, true, false, false);
256: default:
257: throw new UnsupportedChartTypeException(chartType
258: + " is not supported.");
259: }
260: }
261:
262: public static JFreeChart getOverlaidChartInstance(String chartType,
263: String title, String xAxisLabel, String yAxisLabel,
264: int xAxisType, int yAxisType, List plotDefinitions)
265: throws ChartValidationException, DatasetProduceException {
266: final int chartTypeConst = getChartTypeConstant(chartType);
267: final AxisFactory axisFactory = AxisFactory.getInstance();
268: switch (chartTypeConst) {
269: case OVERLAY_XY:
270: ValueAxis domainAxis = (ValueAxis) axisFactory.createAxis(
271: ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
272: // get main plot
273: PlotDefinition mainPlotDef = (PlotDefinition) plotDefinitions
274: .get(0);
275: check((Dataset) mainPlotDef.getDataset(), XYDataset.class,
276: chartType);
277: XYPlot plot = (XYPlot) mainPlotDef.getPlot(chartTypeConst);
278: plot.setDomainAxis(domainAxis);
279: plot.setRangeAxis((ValueAxis) axisFactory.createAxis(
280: ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
281: //plot.setRenderer(new StandardXYItemRenderer());
282: // add second and later datasets to main plot
283: for (int plotidx = 1; plotidx < plotDefinitions.size(); plotidx++) {
284: PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions
285: .get(plotidx);
286: check((Dataset) subPlotDef.getDataset(),
287: XYDataset.class, chartType);
288: plot.setDataset(plotidx, (XYDataset) subPlotDef
289: .getDataset());
290:
291: int rendererIndex = PlotTypes
292: .getRendererIndex(subPlotDef.getType());
293: XYItemRenderer rend = (XYItemRenderer) PlotTypes
294: .getRenderer(rendererIndex);
295: plot.setRenderer(plotidx, rend);
296: }
297: return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
298: plot, true);
299: case OVERLAY_CATEGORY://added by lrh 2005-07-11
300: CategoryAxis domainAxis2 = (CategoryAxis) axisFactory
301: .createAxis(ORIENTATION_HORIZONTAL, xAxisType,
302: xAxisLabel);
303: // get main plot
304: mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
305: check((Dataset) mainPlotDef.getDataset(),
306: CategoryDataset.class, chartType);
307: CategoryPlot plot2 = (CategoryPlot) mainPlotDef
308: .getPlot(chartTypeConst);
309: plot2.setDomainAxis(domainAxis2);
310: plot2.setRangeAxis((ValueAxis) axisFactory.createAxis(
311: ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
312: //plot.setRenderer(new StandardXYItemRenderer());
313: // add second and later datasets to main plot
314: for (int plotidx = 1; plotidx < plotDefinitions.size(); plotidx++) {
315: PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions
316: .get(plotidx);
317: check((Dataset) subPlotDef.getDataset(),
318: CategoryDataset.class, chartType);
319: plot2.setDataset(plotidx, (CategoryDataset) subPlotDef
320: .getDataset());
321:
322: int rendererIndex = PlotTypes
323: .getRendererIndex(subPlotDef.getType());
324: CategoryItemRenderer rend2 = (CategoryItemRenderer) PlotTypes
325: .getRenderer(rendererIndex);
326: plot2.setRenderer(plotidx, rend2);
327: }
328: return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
329: plot2, true);
330: default:
331: throw new UnsupportedChartTypeException(chartType
332: + " is not supported.");
333: }
334: }
335:
336: // [tb]
337: public static JFreeChart getCombinedChartInstance(String chartType,
338: String title, String xAxisLabel, String yAxisLabel,
339: List plotDefinitions, String layout)
340: throws ChartValidationException, DatasetProduceException {
341: final int chartTypeConst = getChartTypeConstant(chartType);
342: switch (chartTypeConst) {
343: case COMBINED_XY:
344: final int layoutConst = getLayoutConstant(layout);
345: Plot plot = null;
346: switch (layoutConst) {
347: case DOMAIN:
348: ValueAxis domainAxis = new DateAxis(xAxisLabel);
349: plot = new CombinedDomainXYPlot(domainAxis);
350: for (int i = 0; i < plotDefinitions.size(); i++) {
351: PlotDefinition pd = (PlotDefinition) plotDefinitions
352: .get(i);
353: check((Dataset) pd.getDataset(), XYDataset.class,
354: chartType);
355: XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
356: temp
357: .setRangeAxis(new NumberAxis(pd
358: .getYaxislabel()));
359: ((CombinedDomainXYPlot) plot).add(temp);
360: }
361: return new JFreeChart(title,
362: JFreeChart.DEFAULT_TITLE_FONT, plot, true);
363: case RANGE:
364: ValueAxis rangeAxis = new NumberAxis(yAxisLabel);
365: plot = new CombinedRangeXYPlot(rangeAxis);
366: for (int i = 0; i < plotDefinitions.size(); i++) {
367: PlotDefinition pd = (PlotDefinition) plotDefinitions
368: .get(i);
369: check((Dataset) pd.getDataset(), XYDataset.class,
370: chartType);
371: XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
372: temp
373: .setDomainAxis(new DateAxis(pd
374: .getXaxislabel()));
375: ((CombinedRangeXYPlot) plot).add(temp);
376: }
377: return new JFreeChart(title,
378: JFreeChart.DEFAULT_TITLE_FONT, plot, true);
379: default:
380: throw new AttributeValidationException(layout,
381: " any value");
382: }
383: default:
384: throw new UnsupportedChartTypeException(chartType);
385: }
386: }
387:
388: /**
389: * Helper to check if the given dataset is the expected type.
390: * @param data The dataset
391: * @param clazz Expected type (class)
392: * @param chartType The chart type string
393: * @throws IncompatibleDatasetException If not the expected class
394: */
395: public static void check(Dataset data, Class clazz, String chartType)
396: throws IncompatibleDatasetException {
397: if (!clazz.isInstance(data)) {
398: throw new IncompatibleDatasetException("Charts of type "
399: + chartType + " " + "need datasets of type "
400: + clazz.getName());
401: }
402: }
403:
404: }
|