ingo@369: package de.intevation.flys.exports;
ingo@369:
ingo@419: import java.awt.BasicStroke;
ingo@369: import java.awt.Color;
ingo@419: import java.awt.Stroke;
ingo@369:
ingo@369: import java.io.IOException;
ingo@369:
ingo@369: import org.apache.log4j.Logger;
ingo@369:
ingo@369: import org.jfree.chart.ChartFactory;
ingo@369: import org.jfree.chart.JFreeChart;
ingo@369: import org.jfree.chart.axis.NumberAxis;
ingo@652: import org.jfree.chart.axis.ValueAxis;
ingo@369: import org.jfree.chart.plot.PlotOrientation;
ingo@369: import org.jfree.chart.plot.XYPlot;
ingo@652: import org.jfree.data.Range;
ingo@654: import org.jfree.data.xy.XYDataset;
ingo@654:
ingo@654: import org.jfree.ui.RectangleInsets;
ingo@369:
ingo@369: import de.intevation.flys.exports.ChartExportHelper;
ingo@369:
ingo@369:
ingo@369: /**
ingo@369: * An abstract base class for creating XY charts.
ingo@369: *
ingo@369: * @author Ingo Weinzierl
ingo@369: */
ingo@369: public abstract class XYChartGenerator extends ChartGenerator {
ingo@369:
ingo@369: /** The logger that is used in this generator.*/
ingo@654: private static Logger logger = Logger.getLogger(XYChartGenerator.class);
ingo@369:
ingo@369:
ingo@419: public static final Color DEFAULT_GRID_COLOR = Color.GRAY;
ingo@419: public static final float DEFAULT_GRID_LINE_WIDTH = 0.3f;
ingo@419:
ingo@419:
ingo@369: /**
ingo@369: * Returns the title of a chart.
ingo@369: *
ingo@369: * @return the title of a chart.
ingo@369: */
ingo@369: protected abstract String getChartTitle();
ingo@369:
ingo@369: /**
ingo@369: * Returns the X-Axis label of a chart.
ingo@369: *
ingo@369: * @return the X-Axis label of a chart.
ingo@369: */
ingo@369: protected abstract String getXAxisLabel();
ingo@369:
ingo@369: /**
ingo@369: * Returns the Y-Axis label of a chart.
ingo@369: *
ingo@369: * @return the Y-Axis label of a chart.
ingo@369: */
ingo@369: protected abstract String getYAxisLabel();
ingo@369:
ingo@369: /**
ingo@375: * This method is called to add all datasets of a concrete XYChartGenerator
ingo@375: * to the JFreeChart.
ingo@369: *
ingo@375: * @param chart The JFreeChart object.
ingo@369: */
ingo@375: protected abstract void addDatasets(JFreeChart chart);
ingo@369:
ingo@369:
ingo@369: public void generate()
ingo@369: throws IOException
ingo@369: {
ingo@369: logger.debug("XYChartGenerator.generate");
ingo@369:
ingo@653: JFreeChart chart = generateChart();
ingo@653:
ingo@653: int[] size = getSize();
ingo@653:
ingo@653: ChartExportHelper.exportImage(
ingo@653: out,
ingo@653: chart,
ingo@653: "png",
ingo@653: size[0], size[1]);
ingo@653: }
ingo@653:
ingo@653:
ingo@653: public JFreeChart generateChart() {
ingo@653: logger.debug("XYChartGenerator.generateChart");
ingo@653:
ingo@369: JFreeChart chart = ChartFactory.createXYLineChart(
ingo@369: getChartTitle(),
ingo@369: getXAxisLabel(),
ingo@369: getYAxisLabel(),
ingo@375: null,
ingo@369: PlotOrientation.VERTICAL,
ingo@369: true,
ingo@369: false,
ingo@369: false);
ingo@369:
ingo@369: chart.setBackgroundPaint(Color.WHITE);
ingo@369: chart.getPlot().setBackgroundPaint(Color.WHITE);
ingo@369:
ingo@419: XYPlot plot = (XYPlot) chart.getPlot();
ingo@419:
ingo@375: addDatasets(chart);
ingo@414: addSubtitles(chart);
ingo@419: adjustPlot(plot);
ingo@419: adjustAxes(plot);
ingo@652: zoom(plot);
ingo@652:
ingo@653: return chart;
ingo@369: }
ingo@369:
ingo@369:
ingo@653: /**
ingo@654: * This method zooms the plot to the specified ranges in the attribute
ingo@654: * document or to the ranges specified by the min/max values in the
ingo@654: * datasets. Note: We determine the range manually if no zoom ranges
ingo@654: * are given, because JFreeCharts auto-zoom adds a margin to the left and
ingo@654: * right of the data area.
ingo@653: *
ingo@653: * @param plot The XYPlot.
ingo@653: */
ingo@652: protected void zoom(XYPlot plot) {
ingo@652: logger.debug("Zoom to specified ranges.");
ingo@654:
ingo@654: Range[] ranges = null;
ingo@654:
ingo@654: boolean x = zoomX(plot);
ingo@654: if (!x) {
ingo@654: XYDataset dataset = plot.getDataset();
ingo@654:
ingo@654: ranges = getRangesForDataset(dataset);
ingo@654:
ingo@654: logger.debug("No x range specified. Set manually: " + ranges[0]);
ingo@654:
ingo@654: ValueAxis axis = plot.getDomainAxis();
ingo@654: axis.setRange(ranges[0]);
ingo@654: }
ingo@654:
ingo@654: boolean y = zoomY(plot);
ingo@654: if (!y) {
ingo@654: XYDataset dataset = plot.getDataset();
ingo@654:
ingo@654: if (ranges == null) {
ingo@654: ranges = getRangesForDataset(dataset);
ingo@654: }
ingo@654:
ingo@654: logger.debug("No y range specified. Set manually: " + ranges[1]);
ingo@654:
ingo@654: ValueAxis axis = plot.getRangeAxis();
ingo@654: axis.setRange(ranges[1]);
ingo@654: }
ingo@653: }
ingo@652:
ingo@653:
ingo@653: /**
ingo@653: * Zooms the x axis to the range specified in the attribute document.
ingo@653: *
ingo@653: * @param plot The XYPlot.
ingo@654: *
ingo@654: * @return true, if a zoom range was specified, otherwise false.
ingo@653: */
ingo@654: protected boolean zoomX(XYPlot plot) {
ingo@652: Range xrange = getDomainAxisRange();
ingo@652: if (xrange != null) {
ingo@652: ValueAxis xaxis = plot.getDomainAxis();
ingo@652: xaxis.setRange(xrange);
ingo@652:
ingo@652: logger.debug("Zoom chart to X: " + xrange);
ingo@654:
ingo@654: return true;
ingo@652: }
ingo@654:
ingo@654: return false;
ingo@653: }
ingo@652:
ingo@653:
ingo@653: /**
ingo@653: * Zooms the y axis to the range specified in the attribute document.
ingo@653: *
ingo@653: * @param plot The XYPlot.
ingo@654: *
ingo@654: * @return true, if a zoom range was specified, otherwise false.
ingo@653: */
ingo@654: protected boolean zoomY(XYPlot plot) {
ingo@652: Range yrange = getValueAxisRange();
ingo@652: if (yrange != null) {
ingo@652: ValueAxis yaxis = plot.getRangeAxis();
ingo@652: yaxis.setRange(yrange);
ingo@652:
ingo@652: logger.debug("Zoom chart to Y: " + yrange);
ingo@654:
ingo@654: return true;
ingo@652: }
ingo@654:
ingo@654: return false;
ingo@654: }
ingo@654:
ingo@654:
ingo@654: /**
ingo@654: * This method extracts the minimum and maximum values for x and y axes.
ingo@654: *
ingo@654: * @param dataset The dataset that should be observed.
ingo@654: *
ingo@654: * @return a Range[] as follows: [x-Range, y-Range].
ingo@654: */
ingo@654: protected Range[] getRangesForDataset(XYDataset dataset) {
ingo@654: double[] xr = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE };
ingo@654: double[] yr = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE };
ingo@654:
ingo@654: int sCount = dataset.getSeriesCount();
ingo@654:
ingo@654: for (int i = 0; i < sCount; i++) {
ingo@654: int iCount = dataset.getItemCount(i);
ingo@654:
ingo@654: for (int j = 0; j < iCount; j++) {
ingo@654: double x = dataset.getX(i, j).doubleValue();
ingo@654: double y = dataset.getY(i, j).doubleValue();
ingo@654:
ingo@654: xr[0] = xr[0] < x ? xr[0] : x;
ingo@654: xr[1] = xr[1] > x ? xr[1] : x;
ingo@654: yr[0] = yr[0] < y ? yr[0] : y;
ingo@654: yr[1] = yr[1] > y ? yr[1] : y;
ingo@654: }
ingo@654: }
ingo@654:
ingo@654: // this is only required, if there are no items in the dataset.
ingo@654: xr[0] = xr[0] < xr[1] ? xr[0] : xr[1];
ingo@654: xr[1] = xr[1] > xr[0] ? xr[1] : xr[0];
ingo@654: yr[0] = yr[0] < yr[1] ? yr[0] : yr[1];
ingo@654: yr[1] = yr[1] > yr[0] ? yr[1] : yr[0];
ingo@654:
ingo@654: return new Range[] {new Range(xr[0], xr[1]), new Range(yr[0], yr[1])};
ingo@652: }
ingo@652:
ingo@652:
ingo@369: /**
ingo@369: * Adjusts the axes of a plot.
ingo@369: *
ingo@369: * @param plot The XYPlot of the chart.
ingo@369: */
ingo@369: protected void adjustAxes(XYPlot plot) {
ingo@369: NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
ingo@369:
ingo@369: yAxis.setAutoRangeIncludesZero(false);
ingo@369: }
ingo@414:
ingo@414:
ingo@419: protected void adjustPlot(XYPlot plot) {
ingo@419: Stroke gridStroke = new BasicStroke(
ingo@419: DEFAULT_GRID_LINE_WIDTH,
ingo@419: BasicStroke.CAP_BUTT,
ingo@419: BasicStroke.JOIN_MITER,
ingo@419: 3.0f,
ingo@419: new float[] { 3.0f },
ingo@419: 0.0f);
ingo@419:
ingo@419: plot.setDomainGridlineStroke(gridStroke);
ingo@419: plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR);
ingo@419: plot.setDomainGridlinesVisible(true);
ingo@419:
ingo@419: plot.setRangeGridlineStroke(gridStroke);
ingo@419: plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR);
ingo@419: plot.setRangeGridlinesVisible(true);
ingo@654:
ingo@654: plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d));
ingo@419: }
ingo@419:
ingo@419:
ingo@414: protected void addSubtitles(JFreeChart chart) {
ingo@414: // override this method in subclasses that need subtitles
ingo@414: }
ingo@369: }
ingo@369: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :