ingo@297: package de.intevation.gnv.chart;
ingo@297: 
ingo@297: import java.awt.Color;
ingo@327: import java.awt.geom.Ellipse2D;
ingo@315: import java.text.NumberFormat;
ingo@297: import java.util.Collection;
ingo@297: import java.util.Iterator;
ingo@315: import java.util.Locale;
ingo@334: import java.util.Map;
ingo@297: 
ingo@297: import org.apache.log4j.Logger;
ingo@297: 
ingo@297: import org.jfree.chart.JFreeChart;
ingo@297: import org.jfree.chart.ChartFactory;
ingo@315: import org.jfree.chart.axis.Axis;
ingo@297: import org.jfree.chart.axis.NumberAxis;
ingo@297: import org.jfree.chart.axis.NumberTickUnit;
ingo@297: import org.jfree.chart.axis.AxisLocation;
ingo@297: import org.jfree.chart.plot.PlotOrientation;
ingo@297: import org.jfree.chart.plot.XYPlot;
ingo@327: import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
ingo@331: import org.jfree.chart.title.TextTitle;
ingo@364: import org.jfree.data.xy.XYDataset;
ingo@364: import org.jfree.data.Range;
ingo@297: import org.jfree.data.general.Series;
ingo@297: 
ingo@297: import de.intevation.gnv.geobackend.base.Result;
tim@335: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
ingo@297: 
ingo@333: 
ingo@297: /**
ingo@297:  * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
ingo@297:  */
ingo@297: public abstract class AbstractXYLineChart
ingo@297: extends               AbstractChart
ingo@297: {
ingo@364:     public static final double LOWER_MARGIN = 0.05D;
ingo@364:     public static final double UPPER_MARGIN = 0.05D;
ingo@364: 
ingo@327:     private static Logger log      = Logger.getLogger(AbstractXYLineChart.class);
ingo@297: 
ingo@297:     protected static Color[] COLOR = {
ingo@334:         Color.black, Color.red, Color.green, Color.blue, Color.yellow,
ingo@334:         Color.gray, Color.orange, Color.pink, Color.cyan
ingo@297:     };
ingo@297: 
ingo@334:     protected static int nextColor = 0;
ingo@334: 
ingo@297:     protected PlotOrientation PLOT_ORIENTATION = PlotOrientation.VERTICAL;
ingo@297: 
ingo@364:     /** Map to store datasets for each parameter */
ingo@334:     protected Map datasets;
ingo@334: 
ingo@364:     /** Map to store max ranges of each parameter (axis.setAutoRange(true)
ingo@364:      * doesn't seem to work */
ingo@364:     protected Map ranges;
ingo@364: 
ingo@297:     protected abstract void initData();
ingo@297:     protected abstract void addValue(Result row, Series series);
ingo@334:     protected abstract void addSeries(Series series, String label, int idx);
ingo@315:     protected abstract void localizeDomainAxis(Axis axis, Locale locale);
ingo@297:     protected abstract String createSeriesName(
ingo@297:         String breakPoint1,
ingo@297:         String breakPoint2,
ingo@297:         String breakPoint3
ingo@297:     );
ingo@297: 
ingo@297: 
ingo@297:     public JFreeChart generateChart() {
ingo@297:         log.debug("generate XYLineChart");
ingo@351:         nextColor = 0;
ingo@297: 
ingo@297:         if (chart != null)
ingo@297:             return chart;
ingo@297: 
ingo@333:         initChart();
ingo@333: 
ingo@333:         chart.addSubtitle(new TextTitle(labels.getSubtitle()));
ingo@333: 
ingo@333:         theme.apply(chart);
ingo@333:         initData();
ingo@333: 
ingo@344:         adjustPlot((XYPlot)chart.getPlot());
ingo@344: 
ingo@333:         return chart;
ingo@333:     }
ingo@333: 
ingo@333: 
ingo@333:     protected void initChart() {
ingo@297:         chart = ChartFactory.createXYLineChart(
ingo@297:             labels.getTitle(),
ingo@297:             labels.getDomainAxisLabel(),
ingo@297:             null,
ingo@297:             null,
ingo@297:             PLOT_ORIENTATION,
ingo@297:             true,
ingo@297:             false,
ingo@297:             false
ingo@297:         );
ingo@297:     }
ingo@297: 
ingo@297: 
ingo@297:     protected void prepareAxis(String seriesKey, int idx) {
ingo@297:         log.debug("prepare axis of xychart");
ingo@315: 
ingo@315:         XYPlot plot      = chart.getXYPlot();
ingo@315:         Axis xAxis       = plot.getDomainAxis();
ingo@315:         NumberAxis yAxis = new NumberAxis(seriesKey);
ingo@315: 
ingo@315:         localizeDomainAxis(xAxis, locale);
ingo@315:         localizeRangeAxis(yAxis, locale);
ingo@297: 
ingo@364:         // litte workarround to adjust the max range of axes.
ingo@364:         // NumberAxis.setAutoRange(true) doesn't seem to work properly.
ingo@364:         Range yRange     = (Range) ranges.get(seriesKey);
ingo@364:         yAxis.setRange(Range.expand(yRange, LOWER_MARGIN, UPPER_MARGIN));
ingo@364:         log.debug("Max Range of dataset is: " + yRange.toString());
ingo@364: 
ingo@297:         if (seriesKey.contains("richtung")) {
ingo@315:             yAxis.setTickUnit(new NumberTickUnit(30.0));
ingo@315:             yAxis.setUpperBound(360.0);
ingo@315:             yAxis.setLowerBound(0.0);
ingo@297:         }
ingo@297:         else {
ingo@315:             yAxis.setFixedDimension(10.0);
ingo@315:             yAxis.setAutoRangeIncludesZero(false);
ingo@297:         }
ingo@297: 
ingo@364:         plot.setRangeAxis(idx, yAxis);
ingo@364:         yAxis.configure();
ingo@364: 
ingo@297:         if (idx % 2 != 0)
ingo@297:             plot.setRangeAxisLocation(idx, AxisLocation.BOTTOM_OR_RIGHT);
ingo@297:         else
ingo@297:             plot.setRangeAxisLocation(idx, AxisLocation.BOTTOM_OR_LEFT);
ingo@506: 
ingo@506:         plot.mapDatasetToRangeAxis(idx, idx);
ingo@327:     }
ingo@297: 
ingo@327: 
ingo@327:     protected void adjustRenderer(
ingo@327:         int     idx,
ingo@334:         int     seriesCount,
ingo@327:         boolean renderLines,
ingo@327:         boolean renderShapes
ingo@327:     ) {
ingo@334:         log.debug("Adjust render of series");
ingo@327:         XYLineAndShapeRenderer renderer = null;
ingo@327:         XYPlot                 plot     = chart.getXYPlot();
ingo@327: 
ingo@327:         try {
ingo@327:             renderer = (XYLineAndShapeRenderer)((XYLineAndShapeRenderer)
ingo@327:                 (plot.getRenderer())).clone();
ingo@327:         }
ingo@327:         catch (CloneNotSupportedException cnse) {
ingo@327:             log.warn("Error while cloning renderer.", cnse);
ingo@327:             renderer = new XYLineAndShapeRenderer(renderLines, renderShapes);
ingo@327:             renderer.setBaseShape(new Ellipse2D.Double(-2,-2,4,4));
ingo@327:         }
ingo@327: 
ingo@334:         for (int i = 0; i < seriesCount; i++) {
ingo@334:             renderer.setSeriesShape(i, renderer.getSeriesShape(0));
ingo@334:             renderer.setSeriesPaint(i, COLOR[nextColor%COLOR.length]);
ingo@334:             renderer.setSeriesShapesVisible(i, renderShapes);
ingo@334:             renderer.setSeriesLinesVisible(i, renderLines);
ingo@334:             nextColor++;
ingo@334:         }
ingo@297:         plot.setRenderer(idx, renderer);
ingo@297:     }
ingo@297: 
ingo@297: 
ingo@344:     protected void adjustPlot(XYPlot plot) {
ingo@344:         if (plot.getRangeAxisCount() > 1)
ingo@344:             plot.setRangeGridlinesVisible(false);
ingo@344:     }
ingo@344: 
ingo@344: 
ingo@315:     protected void localizeRangeAxis(Axis axis, Locale locale) {
ingo@315:         if (locale == null)
ingo@315:             return;
ingo@315: 
ingo@315:         log.debug(
ingo@315:             "Set language of axis [" + axis.getLabel() + "] " +
ingo@315:             "to " + locale.toString()
ingo@315:         );
ingo@315: 
ingo@315:         NumberFormat format = NumberFormat.getInstance(locale);
ingo@315:         ((NumberAxis) axis).setNumberFormatOverride(format);
ingo@315:     }
ingo@315: 
ingo@315: 
ingo@364:     public Range getMaxRangeOfDataset(XYDataset dataset) {
ingo@364:         int    seriesCount = dataset.getSeriesCount();
ingo@364:         double upper       = Double.NEGATIVE_INFINITY;
ingo@364:         double lower       = Double.POSITIVE_INFINITY;
ingo@364: 
ingo@364:         for (int i = 0; i < seriesCount; i++) {
ingo@364:             int itemCount = dataset.getItemCount(i);
ingo@364: 
ingo@364:             for (int j = 0; j < itemCount; j++) {
ingo@364:                 Number num = dataset.getY(i, j);
ingo@364: 
ingo@364:                 if (num != null) {
ingo@364:                     double y = num.doubleValue();
ingo@364:                     lower    = y < lower ? y : lower;
ingo@364:                     upper    = y > upper ? y : upper;
ingo@364:                 }
ingo@364:             }
ingo@364:         }
ingo@364: 
ingo@364:         return new Range(lower, upper);
ingo@364:     }
ingo@364: 
ingo@364: 
ingo@364:     public Range getMaxRangeOfDatasetWithMargin(
ingo@364:         XYDataset dataset,
ingo@364:         double    percent
ingo@364:     ) {
ingo@364:         Range range   = getMaxRangeOfDataset(dataset);
ingo@364:         double length = range.getLength();
ingo@364:         double upper  = range.getUpperBound() + length /100 * percent;
ingo@364:         double lower  = range.getLowerBound() - length /100 * percent;
ingo@364: 
ingo@364:         return new Range(lower, upper);
ingo@364:     }
ingo@364: 
ingo@364: 
ingo@334:     protected String findParameter(String label) {
ingo@334:         Iterator iter = parameters.iterator();
ingo@334: 
ingo@334:         while (iter.hasNext()) {
ingo@334:             KeyValueDescibeData data = (KeyValueDescibeData) iter.next();
ingo@334:             String              key  = data.getValue();
ingo@334: 
ingo@334:             if (label.indexOf(key) > -1)
ingo@334:                 return key;
ingo@334:         }
ingo@334: 
ingo@334:         return label;
ingo@334:     }
ingo@334: 
ingo@334: 
ingo@297:     protected String findValueTitle(Collection values, String id) {
ingo@297:         log.debug("find description of dataset");
ingo@297: 
tim@307:         if (values != null){
tim@307:             Iterator it = values.iterator();
tim@307:             while (it.hasNext()) {
tim@307:                 KeyValueDescibeData data = (KeyValueDescibeData) it.next();
ingo@315: 
tim@307:                 if (id.equals(data.getKey()))
tim@307:                     return data.getValue();
tim@307:             }
ingo@297:         }
ingo@297:         return "";
ingo@297:     }
ingo@364: 
ingo@364: 
ingo@364:     protected void storeMaxRange(double value, String parameter) {
ingo@364:         Range  range     = null;
ingo@364: 
ingo@364:         range = ranges.containsKey(parameter)
ingo@364:             ? (Range) ranges.get(parameter)
ingo@364:             : new Range(value, value);
ingo@364: 
ingo@364:         double lower = range.getLowerBound();
ingo@364:         double upper = range.getUpperBound();
ingo@364: 
ingo@364:         lower = value < lower ? value : lower;
ingo@364:         upper = value > upper ? value : upper;
ingo@364: 
ingo@364:         ranges.put(parameter, new Range(lower, upper));
ingo@364:     }
ingo@297: }
ingo@315: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :