1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/java/cewolf-1.0/src/main/java/de/laures/cewolf/taglib/CewolfChartFactory.java Sat Feb 28 21:31:02 2009 +0100
1.3 @@ -0,0 +1,313 @@
1.4 +/* ================================================================
1.5 + * Cewolf : Chart enabling Web Objects Framework
1.6 + * ================================================================
1.7 + *
1.8 + * Project Info: http://cewolf.sourceforge.net
1.9 + * Project Lead: Guido Laures (guido@laures.de);
1.10 + *
1.11 + * (C) Copyright 2002, by Guido Laures
1.12 + *
1.13 + * This library is free software; you can redistribute it and/or modify it under the terms
1.14 + * of the GNU Lesser General Public License as published by the Free Software Foundation;
1.15 + * either version 2.1 of the License, or (at your option) any later version.
1.16 + *
1.17 + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
1.18 + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1.19 + * See the GNU Lesser General Public License for more details.
1.20 + *
1.21 + * You should have received a copy of the GNU Lesser General Public License along with this
1.22 + * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1.23 + * Boston, MA 02111-1307, USA.
1.24 + */
1.25 +
1.26 +package de.laures.cewolf.taglib;
1.27 +
1.28 +import java.util.HashMap;
1.29 +import java.util.List;
1.30 +import java.util.Map;
1.31 +
1.32 +import org.jfree.chart.ChartFactory;
1.33 +import org.jfree.chart.JFreeChart;
1.34 +import org.jfree.chart.axis.CategoryAxis;
1.35 +import org.jfree.chart.axis.DateAxis;
1.36 +import org.jfree.chart.axis.NumberAxis;
1.37 +import org.jfree.chart.axis.ValueAxis;
1.38 +import org.jfree.chart.plot.CategoryPlot;
1.39 +import org.jfree.chart.plot.CombinedDomainXYPlot;
1.40 +import org.jfree.chart.plot.CombinedRangeXYPlot;
1.41 +import org.jfree.chart.plot.MeterPlot;
1.42 +import org.jfree.chart.plot.Plot;
1.43 +import org.jfree.chart.plot.PlotOrientation;
1.44 +import org.jfree.chart.plot.XYPlot;
1.45 +import org.jfree.chart.renderer.category.CategoryItemRenderer;
1.46 +import org.jfree.chart.renderer.xy.XYItemRenderer;
1.47 +import org.jfree.data.category.CategoryDataset;
1.48 +import org.jfree.data.category.IntervalCategoryDataset;
1.49 +import org.jfree.data.general.Dataset;
1.50 +import org.jfree.data.general.PieDataset;
1.51 +import org.jfree.data.general.ValueDataset;
1.52 +import org.jfree.data.xy.IntervalXYDataset;
1.53 +import org.jfree.data.xy.OHLCDataset;
1.54 +import org.jfree.data.xy.WindDataset;
1.55 +import org.jfree.data.xy.XYDataset;
1.56 +import org.jfree.data.xy.XYZDataset;
1.57 +
1.58 +import de.laures.cewolf.ChartValidationException;
1.59 +import de.laures.cewolf.DatasetProduceException;
1.60 +
1.61 +/**
1.62 + * Chart factory creates Jfreechart instances. To add a new factory use the
1.63 + * <code>
1.64 + * CewolfChartFactory.registerFactory(new CewolfChartFactory() {...});
1.65 + * </code>
1.66 + * method.
1.67 + *
1.68 + * @author Guido Laures
1.69 + */
1.70 +public abstract class CewolfChartFactory implements ChartConstants, AxisConstants, LayoutConstants {
1.71 +
1.72 + // chart type string
1.73 + protected String chartType;
1.74 + // map contains registered factories, (String) chartType->CewolfChartFactory mappings
1.75 + private static Map factories = new HashMap();
1.76 +
1.77 + /** Creates a new instance of ChartFactory */
1.78 + protected CewolfChartFactory(String chartType) {
1.79 + this.chartType = chartType;
1.80 + }
1.81 +
1.82 + /**
1.83 + * Callback when the chart instance to be created.
1.84 + * @param title The title of chart
1.85 + * @param xAxisLabel label on x axis
1.86 + * @param yAxisLabel label on y axis
1.87 + * @param data The dataset to create chart for
1.88 + * @return The newly created JFreeChart instance
1.89 + *
1.90 + * @throws IncompatibleDatasetException If the incoming data is not compatible with this factory
1.91 + */
1.92 + public abstract JFreeChart getChartInstance(String title, String xAxisLabel, String yAxisLabel, Dataset data) throws IncompatibleDatasetException;
1.93 +
1.94 + //////////////// static part ///////////////////////
1.95 +
1.96 + /**
1.97 + * Register a new chart factory instance.
1.98 + * @param factory The factory to register
1.99 + */
1.100 + public static void registerFactory(CewolfChartFactory factory) {
1.101 + factories.put(factory.chartType, factory);
1.102 + }
1.103 +
1.104 + private static final int getChartTypeConstant(String type) {
1.105 + final int res = ChartTypes.typeList.indexOf(type.toLowerCase());
1.106 + if (res < 0) {
1.107 + throw new RuntimeException("unsupported chart type " + type);
1.108 + }
1.109 + return res;
1.110 + }
1.111 +
1.112 + private static final int getLayoutConstant(String layout) {
1.113 + return LayoutTypes.typeList.indexOf(layout.toLowerCase());
1.114 + }
1.115 +
1.116 + static {
1.117 + // histogram chart type
1.118 + registerFactory(new CewolfChartFactory("histogram") {
1.119 + public JFreeChart getChartInstance(String title, String xAxisLabel, String yAxisLabel, Dataset data) throws IncompatibleDatasetException {
1.120 + check(data, IntervalXYDataset.class, this.chartType);
1.121 + return ChartFactory.createHistogram(title, xAxisLabel, yAxisLabel, (IntervalXYDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.122 + }
1.123 + });
1.124 + }
1.125 +
1.126 + public static JFreeChart getChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, Dataset data) throws ChartValidationException {
1.127 + // first check the dynamically registered chart types
1.128 + CewolfChartFactory factory = (CewolfChartFactory) factories.get(chartType);
1.129 + if (factory != null) {
1.130 + // custom factory found, use it
1.131 + return factory.getChartInstance(title, xAxisLabel, yAxisLabel, data);
1.132 + }
1.133 +
1.134 + switch (getChartTypeConstant(chartType)) {
1.135 + case XY :
1.136 + check(data, XYDataset.class, chartType);
1.137 + return ChartFactory.createXYLineChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, true, true);
1.138 + case PIE :
1.139 + check(data, PieDataset.class, chartType);
1.140 + return ChartFactory.createPieChart(title, (PieDataset) data, true, true, true);
1.141 + case AREA_XY :
1.142 + check(data, XYDataset.class, chartType);
1.143 + return ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.144 + case SCATTER :
1.145 + check(data, XYDataset.class, chartType);
1.146 + return ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, (XYDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.147 + case AREA :
1.148 + check(data, CategoryDataset.class, chartType);
1.149 + return ChartFactory.createAreaChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.150 + case HORIZONTAL_BAR :
1.151 + check(data, CategoryDataset.class, chartType);
1.152 + return ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
1.153 + case HORIZONTAL_BAR_3D :
1.154 + check(data, CategoryDataset.class, chartType);
1.155 + return ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
1.156 + case LINE :
1.157 + check(data, CategoryDataset.class, chartType);
1.158 + return ChartFactory.createLineChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.159 + case STACKED_HORIZONTAL_BAR :
1.160 + check(data, CategoryDataset.class, chartType);
1.161 + return ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.HORIZONTAL, true, false, false);
1.162 + case STACKED_VERTICAL_BAR :
1.163 + check(data, CategoryDataset.class, chartType);
1.164 + return ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.165 + case STACKED_VERTICAL_BAR_3D :
1.166 + check(data, CategoryDataset.class, chartType);
1.167 + return ChartFactory.createStackedBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.168 + case VERTICAL_BAR :
1.169 + check(data, CategoryDataset.class, chartType);
1.170 + return ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.171 + case VERTICAL_BAR_3D :
1.172 + check(data, CategoryDataset.class, chartType);
1.173 + return ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.174 + case TIME_SERIES :
1.175 + check(data, XYDataset.class, chartType);
1.176 + return ChartFactory.createTimeSeriesChart(title, xAxisLabel, yAxisLabel, (XYDataset) data, true, false, false);
1.177 + case CANDLE_STICK :
1.178 + check(data, OHLCDataset.class, chartType);
1.179 + return ChartFactory.createCandlestickChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
1.180 + case HIGH_LOW :
1.181 + check(data, OHLCDataset.class, chartType);
1.182 + return ChartFactory.createHighLowChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
1.183 + case GANTT :
1.184 + check(data, IntervalCategoryDataset.class, chartType);
1.185 + return ChartFactory.createGanttChart(title, xAxisLabel, yAxisLabel, (IntervalCategoryDataset) data, true, false, false);
1.186 + case WIND :
1.187 + check(data, WindDataset.class, chartType);
1.188 + return ChartFactory.createWindPlot(title, xAxisLabel, yAxisLabel, (WindDataset) data, true, false, false);
1.189 + //case SIGNAL :
1.190 + // check(data, SignalsDataset.class, chartType);
1.191 + // return ChartFactory.createSignalChart(title, xAxisLabel, yAxisLabel, (SignalsDataset) data, true);
1.192 + case VERRTICAL_XY_BAR :
1.193 + check(data, IntervalXYDataset.class, chartType);
1.194 + return ChartFactory.createXYBarChart(title, xAxisLabel, true,yAxisLabel, (IntervalXYDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.195 + case PIE_3D :
1.196 + check(data, PieDataset.class, chartType);
1.197 + return ChartFactory.createPieChart3D(title, (PieDataset) data, true, false, false);
1.198 + case METER :
1.199 + check(data, ValueDataset.class, chartType);
1.200 + MeterPlot plot = new MeterPlot((ValueDataset) data);
1.201 + JFreeChart chart = new JFreeChart(title, plot);
1.202 + return chart;
1.203 + case STACKED_AREA :
1.204 + check(data, CategoryDataset.class, chartType);
1.205 + return ChartFactory.createStackedAreaChart(title, xAxisLabel, yAxisLabel, (CategoryDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.206 + case BUBBLE :
1.207 + check(data, XYZDataset.class, chartType);
1.208 + return ChartFactory.createBubbleChart(title, xAxisLabel, yAxisLabel, (XYZDataset) data, PlotOrientation.VERTICAL, true, false, false);
1.209 + default :
1.210 + throw new UnsupportedChartTypeException(chartType + " is not supported.");
1.211 + }
1.212 + }
1.213 +
1.214 + public static JFreeChart getOverlaidChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, int xAxisType, int yAxisType, List plotDefinitions)
1.215 + throws ChartValidationException, DatasetProduceException {
1.216 + final int chartTypeConst = getChartTypeConstant(chartType);
1.217 + final AxisFactory axisFactory = AxisFactory.getInstance();
1.218 + switch (chartTypeConst) {
1.219 + case OVERLAY_XY :
1.220 + ValueAxis domainAxis = (ValueAxis) axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
1.221 + // get main plot
1.222 + PlotDefinition mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
1.223 + check((Dataset) mainPlotDef.getDataset(), XYDataset.class, chartType);
1.224 + XYPlot plot = (XYPlot) mainPlotDef.getPlot(chartTypeConst);
1.225 + plot.setDomainAxis(domainAxis);
1.226 + plot.setRangeAxis((ValueAxis) axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
1.227 + //plot.setRenderer(new StandardXYItemRenderer());
1.228 + // add second and later datasets to main plot
1.229 + for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
1.230 + PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
1.231 + check((Dataset) subPlotDef.getDataset(), XYDataset.class, chartType);
1.232 + plot.setDataset(plotidx, (XYDataset)subPlotDef.getDataset());
1.233 +
1.234 + int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
1.235 + XYItemRenderer rend = (XYItemRenderer) PlotTypes.getRenderer(rendererIndex);
1.236 + plot.setRenderer(plotidx, rend);
1.237 + }
1.238 + return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
1.239 + case OVERLAY_CATEGORY ://added by lrh 2005-07-11
1.240 + CategoryAxis domainAxis2 = (CategoryAxis)axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
1.241 + // get main plot
1.242 + mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
1.243 + check((Dataset) mainPlotDef.getDataset(), CategoryDataset.class, chartType);
1.244 + CategoryPlot plot2 = (CategoryPlot) mainPlotDef.getPlot(chartTypeConst);
1.245 + plot2.setDomainAxis(domainAxis2);
1.246 + plot2.setRangeAxis((ValueAxis)axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel));
1.247 + //plot.setRenderer(new StandardXYItemRenderer());
1.248 + // add second and later datasets to main plot
1.249 + for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
1.250 + PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
1.251 + check((Dataset) subPlotDef.getDataset(), CategoryDataset.class, chartType);
1.252 + plot2.setDataset(plotidx, (CategoryDataset)subPlotDef.getDataset());
1.253 +
1.254 + int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
1.255 + CategoryItemRenderer rend2 = (CategoryItemRenderer) PlotTypes.getRenderer(rendererIndex);
1.256 + plot2.setRenderer(plotidx, rend2);
1.257 + }
1.258 + return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot2, true);
1.259 + default :
1.260 + throw new UnsupportedChartTypeException(chartType + " is not supported.");
1.261 + }
1.262 + }
1.263 +
1.264 + // [tb]
1.265 + public static JFreeChart getCombinedChartInstance(String chartType, String title, String xAxisLabel, String yAxisLabel, List plotDefinitions, String layout)
1.266 + throws ChartValidationException, DatasetProduceException {
1.267 + final int chartTypeConst = getChartTypeConstant(chartType);
1.268 + switch (chartTypeConst) {
1.269 + case COMBINED_XY :
1.270 + final int layoutConst = getLayoutConstant(layout);
1.271 + Plot plot = null;
1.272 + switch (layoutConst) {
1.273 + case DOMAIN :
1.274 + ValueAxis domainAxis = new DateAxis(xAxisLabel);
1.275 + plot = new CombinedDomainXYPlot(domainAxis);
1.276 + for (int i = 0; i < plotDefinitions.size(); i++) {
1.277 + PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
1.278 + check((Dataset) pd.getDataset(), XYDataset.class, chartType);
1.279 + XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
1.280 + temp.setRangeAxis(new NumberAxis(pd.getYaxislabel()));
1.281 + ((CombinedDomainXYPlot) plot).add(temp);
1.282 + }
1.283 + return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
1.284 + case RANGE :
1.285 + ValueAxis rangeAxis = new NumberAxis(yAxisLabel);
1.286 + plot = new CombinedRangeXYPlot(rangeAxis);
1.287 + for (int i = 0; i < plotDefinitions.size(); i++) {
1.288 + PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
1.289 + check((Dataset) pd.getDataset(), XYDataset.class, chartType);
1.290 + XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
1.291 + temp.setDomainAxis(new DateAxis(pd.getXaxislabel()));
1.292 + ((CombinedRangeXYPlot) plot).add(temp);
1.293 + }
1.294 + return new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
1.295 + default :
1.296 + throw new AttributeValidationException(layout, " any value");
1.297 + }
1.298 + default :
1.299 + throw new UnsupportedChartTypeException(chartType);
1.300 + }
1.301 + }
1.302 +
1.303 + /**
1.304 + * Helper to check if the given dataset is the expected type.
1.305 + * @param data The dataset
1.306 + * @param clazz Expected type (class)
1.307 + * @param chartType The chart type string
1.308 + * @throws IncompatibleDatasetException If not the expected class
1.309 + */
1.310 + public static void check(Dataset data, Class clazz, String chartType) throws IncompatibleDatasetException {
1.311 + if (!clazz.isInstance(data)) {
1.312 + throw new IncompatibleDatasetException("Charts of type " + chartType + " " + "need datasets of type " + clazz.getName());
1.313 + }
1.314 + }
1.315 +
1.316 +}