diff flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java @ 2633:894186b4c1d0

Issue 494. Add manual points with text annotations to time charts. flys-artifacts/trunk@4255 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Wed, 18 Apr 2012 07:14:48 +0000
parents d75b427da50a
children fa015cf5c0af
line wrap: on
line diff
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java	Tue Apr 17 13:55:50 2012 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java	Wed Apr 18 07:14:48 2012 +0000
@@ -2,28 +2,50 @@
 
 import java.awt.Color;
 import java.awt.Font;
+import java.awt.Paint;
+import java.awt.BasicStroke;
+import java.awt.Stroke;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Date;
+
+import org.json.JSONArray;
+import org.json.JSONException;
 
 import org.apache.log4j.Logger;
 
+import org.w3c.dom.Document;
+
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.LegendItemCollection;
 
 import org.jfree.data.Range;
 import org.jfree.data.time.TimeSeriesCollection;
 import org.jfree.data.general.Series;
 import org.jfree.data.xy.XYDataset;
+import org.jfree.data.general.SeriesException;
+import org.jfree.data.time.Day;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
 
 import de.intevation.flys.jfree.Bounds;
 import de.intevation.flys.jfree.DoubleBounds;
 import de.intevation.flys.jfree.TimeBounds;
+import de.intevation.flys.jfree.StyledTimeSeries;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
 
+import de.intevation.flys.utils.ThemeAccess;
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
@@ -122,6 +144,9 @@
     } // end of TimeseriesAxisDataset class
 
 
+    /** List of annotations to insert in plot. */
+    protected List<FLYSAnnotation> annotations;
+
 
     private static final Logger logger =
         Logger.getLogger(TimeseriesChartGenerator.class);
@@ -173,6 +198,8 @@
 
         adaptZoom(plot);
 
+        addAnnotationsToRenderer(plot);
+
         return chart;
     }
 
@@ -450,5 +477,230 @@
         xaxis.setLabelFont(labelFont);
         xaxis.setTickLabelFont(labelFont);
     }
+
+
+    /**
+     * Do Points out.
+     */
+    protected void doPoints(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible,
+        int        axisIndex
+    ) {
+        String seriesName = aandf.getFacetDescription();
+        TimeSeries series = new StyledTimeSeries(seriesName, theme);
+
+        // Add text annotations for single points.
+        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        HashMap<Day, String> names = new HashMap<Day, String>();
+
+        try {
+            JSONArray points = new JSONArray((String) o);
+            for (int i = 0; i < points.length(); i++) {
+                JSONArray array = points.getJSONArray(i);
+                double x    = array.getDouble(0);
+                double y    = array.getDouble(1);
+                String name = array.getString(2);
+                boolean act = array.getBoolean(3);
+                if (!act) {
+                    continue;
+                }
+                long l = (new Double(x)).longValue();
+                Date date = new Date(l);
+                Day day = new Day(date);
+                series.add(day, y, false);
+                names.put(day, name);
+            }
+        }
+        catch(JSONException e){
+            logger.error("Could not decode json.");
+        }
+
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+        tsc.addSeries(series);
+        // Add Annotations.
+        for (int i = 0; i < series.getItemCount(); i++) {
+            double x = tsc.getXValue(0, i);
+            double y = tsc.getYValue(0, i);
+            xy.add(new CollisionFreeXYTextAnnotation(
+                       names.get(series.getTimePeriod(i)), x, y));
+        }
+        FLYSAnnotation annotations =
+            new FLYSAnnotation(null, null, null, theme);
+        annotations.setTextAnnotations(xy);
+
+        // Do not generate second legend entry. (null was passed for the aand before).
+        doAnnotations(annotations, aandf, theme, visible);
+
+        addAxisDataset(tsc, axisIndex, visible);
+    }
+
+    /**
+     * Register annotations like MainValues for later plotting
+     *
+     * @param o     list of annotations (data of facet).
+     * @param facet The facet. This facet does NOT support any data objects. Use
+     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
+     * data.
+     * @param theme   Theme document for given annotations.
+     * @param visible The visibility of the annotations.
+     */
+    protected void doAnnotations(
+        FLYSAnnotation annotations,
+        ArtifactAndFacet aandf,
+        Document theme,
+        boolean visible
+    ){
+        // Running into trouble here.
+        logger.debug("doAnnotations");
+
+        // Add all annotations to our annotation pool.
+        annotations.setTheme(theme);
+        if (aandf != null) {
+            Facet facet = aandf.getFacet();
+            annotations.setLabel(aandf.getFacetDescription());
+        }
+        else {
+            logger.debug(
+                "Art/Facet for Annotations is null. " +
+                "This should never happen!");
+        }
+
+        addAnnotations(annotations, visible);
+    }
+
+
+
+    /**
+     * Adds annotations to list (if visible is true).
+     */
+    public void addAnnotations(FLYSAnnotation annotation, boolean visible) {
+        if (!visible) {
+            return;
+        }
+
+        if (annotations == null) {
+            annotations = new ArrayList<FLYSAnnotation>();
+        }
+
+        annotations.add(annotation);
+    }
+
+
+    /** Add annotations (Sticky, Text and hyk zones). */
+    public void addAnnotationsToRenderer(XYPlot plot) {
+        logger.debug("XYChartGenerator.addAnnotationsToRenderer");
+
+        if (annotations == null) {
+            logger.debug("XYChartGenerator.addBoxAnnotations: no annotations.");
+            return;
+        }
+
+        // Paints for the boxes/lines.
+        Stroke basicStroke = new BasicStroke(1.0f);
+
+        Paint linePaint = new Color(255,  0,0,60);
+        Paint fillPaint = new Color(0,  255,0,60);
+        Paint tranPaint = new Color(0,    0,0, 0);
+
+        // OPTMIMIZE: Pre-calculate positions
+        Area area = new Area(
+            plot.getDomainAxis(0).getRange(),
+            plot.getRangeAxis().getRange());
+
+        // Walk over all Annotation sets.
+        for (FLYSAnnotation fa: annotations) {
+
+            // Access text styling, if any.
+            Document theme = fa.getTheme();
+            ThemeAccess.TextStyle textStyle = null;
+            ThemeAccess.LineStyle lineStyle = null;
+
+            // Get Themeing information and add legend item.
+            if (theme != null) {
+                ThemeAccess themeAccess = new ThemeAccess(theme);
+                textStyle = themeAccess.parseTextStyle();
+                lineStyle = themeAccess.parseLineStyle();
+                if (fa.getLabel() != null) {
+                    LegendItemCollection lic = new LegendItemCollection();
+                    LegendItemCollection old = plot.getFixedLegendItems();
+                    lic.add(createLegendItem(theme, fa.getLabel()));
+                    // (Re-)Add prior legend entries.
+                    if (old != null) {
+                        old.addAll(lic);
+                    }
+                    else {
+                        old = lic;
+                    }
+                    plot.setFixedLegendItems(old);
+                }
+            }
+
+            // Other Text Annotations (e.g. labels of manual points).
+            for (XYTextAnnotation ta: fa.getTextAnnotations()) {
+                // Style the text.
+                if (textStyle != null) {
+                    textStyle.apply(ta);
+                }
+                ta.setY(area.above(0.05d, ta.getY()));
+                plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND);
+            }
+        }
+    }
+
+
+    /** Two Ranges that span a rectangular area. */
+    public static class Area {
+        protected Range xRange;
+        protected Range yRange;
+
+        public Area(Range rangeX, Range rangeY) {
+            this.xRange = rangeX;
+            this.yRange = rangeY;
+        }
+
+        public Area(ValueAxis axisX, ValueAxis axisY) {
+            this.xRange = axisX.getRange();
+            this.yRange = axisY.getRange();
+        }
+
+        public double ofLeft(double percent) {
+            return xRange.getLowerBound()
+                + xRange.getLength() * percent;
+        }
+
+        public double ofRight(double percent) {
+            return xRange.getUpperBound()
+                - xRange.getLength() * percent;
+        }
+
+        public double ofGround(double percent) {
+            return yRange.getLowerBound()
+                + yRange.getLength() * percent;
+        }
+
+        public double atTop() {
+            return yRange.getUpperBound();
+        }
+
+        public double atGround() {
+            return yRange.getLowerBound();
+        }
+
+        public double atRight() {
+            return xRange.getUpperBound();
+        }
+
+        public double atLeft() {
+            return xRange.getLowerBound();
+        }
+
+        public double above(double percent, double base) {
+            return base + yRange.getLength() * percent;
+        }
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org