diff artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java @ 7043:06a9a241faac generator-refactoring

Factor out annotation handling code
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 18 Sep 2013 17:12:13 +0200
parents 557cb3a3d772
children 726d998dce29
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java	Wed Sep 18 16:26:12 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java	Wed Sep 18 17:12:13 2013 +0200
@@ -21,12 +21,10 @@
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.dive4elements.river.collections.D4EArtifactCollection;
 import org.dive4elements.river.jfree.Bounds;
-import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
 import org.dive4elements.river.jfree.DoubleBounds;
 import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer;
 import org.dive4elements.river.jfree.RiverAnnotation;
 import org.dive4elements.river.jfree.StableXYDifferenceRenderer;
-import org.dive4elements.river.jfree.StickyAxisAnnotation;
 import org.dive4elements.river.jfree.Style;
 import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
 import org.dive4elements.river.jfree.StyledSeries;
@@ -60,8 +58,6 @@
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.LegendItem;
 import org.jfree.chart.LegendItemCollection;
-import org.jfree.chart.annotations.XYLineAnnotation;
-import org.jfree.chart.annotations.XYTextAnnotation;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
@@ -77,15 +73,9 @@
 import org.dive4elements.river.utils.Formatter;
 
 /**
- * The base class for chart creation. It should provide some basic things that
- * equal in all chart types.
+ * Implementation of the OutGenerator interface for charts.
+ * It should provide some basic things that equal in all chart types.
  *
- * Annotations are added as RiverAnnotations and come in mutliple basic forms:
- * TextAnnotations are labels somewhere in data space, StickyAnnotations are
- * labels of a slice or line in one data dimension (i.e. visualized as label
- * on a single axis).
- *
- * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public abstract class ChartGenerator2 implements OutGenerator {
 
@@ -99,7 +89,6 @@
     public static final int    DEFAULT_FONT_SIZE       = 12;
     public static final String DEFAULT_FONT_NAME       = "Tahoma";
 
-    protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f;
 
     public static final String XPATH_CHART_SIZE =
         "/art:action/art:attributes/art:size";
@@ -155,7 +144,6 @@
         datasets = new TreeMap<Integer, AxisDataset>();
     }
 
-
     /**
      * Adds annotations to list. The given annotation will be visible.
      */
@@ -164,313 +152,6 @@
     }
 
     /**
-     * Add a text and a line annotation.
-     * @param area convenience to determine positions in plot.
-     * @param theme (optional) theme document
-     */
-    protected void addStickyAnnotation(
-        StickyAxisAnnotation annotation,
-        XYPlot plot,
-        ChartArea area,
-        LineStyle lineStyle,
-        TextStyle textStyle,
-        ThemeDocument theme
-    ) {
-        // OPTIMIZE pre-calculate area-related values
-        final float TEXT_OFF = 0.03f;
-
-        XYLineAnnotation lineAnnotation = null;
-        XYTextAnnotation textAnnotation = null;
-
-        int rendererIndex = 0;
-
-        if (annotation.atX()) {
-            textAnnotation = new CollisionFreeXYTextAnnotation(
-                annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF));
-            // OPTIMIZE externalize the calculation involving PI.
-            //textAnnotation.setRotationAngle(270f*Math.PI/180f);
-            lineAnnotation = createGroundStickAnnotation(
-                area, annotation.getPos(), lineStyle);
-            textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT);
-            textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT);
-        }
-        else {
-            // Do the more complicated case where we stick to the Y-Axis.
-            // There is one nasty case (duration curves, where annotations
-            // might stick to the second y-axis).
-            // FIXME: Remove dependency to XYChartGenerator2 here
-            AxisDataset dataset = getAxisDataset(
-                new Integer(annotation.getAxisSymbol()));
-            if (dataset == null) {
-                logger.warn("Annotation should stick to unfindable y-axis: "
-                    + annotation.getAxisSymbol());
-                rendererIndex = 0;
-            }
-            else {
-                rendererIndex = dataset.getPlotAxisIndex();
-            }
-
-            // Stick to the "right" (opposed to left) Y-Axis.
-            if (rendererIndex != 0) {
-                // OPTIMIZE: Pass a different area to this function,
-                //           do the adding to renderer outside (let this
-                //           function return the annotations).
-                //           Note that this path is travelled rarely.
-                ChartArea area2 = new ChartArea(plot.getDomainAxis(), plot.getRangeAxis(rendererIndex));
-                textAnnotation = new CollisionFreeXYTextAnnotation(
-                    annotation.getText(), area2.ofRight(TEXT_OFF), annotation.getPos());
-                textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT);
-                textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT);
-                lineAnnotation = createRightStickAnnotation(
-                    area2, annotation.getPos(), lineStyle);
-                if (!Float.isNaN(annotation.getHitPoint()) && theme != null) {
-                    // New line annotation to hit curve.
-                    if (theme.parseShowVerticalLine()) {
-                        XYLineAnnotation hitLineAnnotation =
-                            createStickyLineAnnotation(
-                                StickyAxisAnnotation.SimpleAxis.X_AXIS,
-                                annotation.getHitPoint(), annotation.getPos(),// annotation.getHitPoint(),
-                                area2, lineStyle);
-                        plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation,
-                            org.jfree.ui.Layer.BACKGROUND);
-                    }
-                    if (theme.parseShowHorizontalLine()) {
-                        XYLineAnnotation lineBackAnnotation =
-                            createStickyLineAnnotation(
-                                StickyAxisAnnotation.SimpleAxis.Y_AXIS2,
-                                annotation.getPos(), annotation.getHitPoint(),
-                                area2, lineStyle);
-                        plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation,
-                            org.jfree.ui.Layer.BACKGROUND);
-                    }
-                }
-            }
-            else { // Stick to the left y-axis.
-                textAnnotation = new CollisionFreeXYTextAnnotation(
-                    annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos());
-                textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT);
-                textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT);
-                lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle);
-                if (!Float.isNaN(annotation.getHitPoint()) && theme != null) {
-                    // New line annotation to hit curve.
-                    if (theme.parseShowHorizontalLine()) {
-                        XYLineAnnotation hitLineAnnotation =
-                            createStickyLineAnnotation(
-                                StickyAxisAnnotation.SimpleAxis.Y_AXIS,
-                                annotation.getPos(), annotation.getHitPoint(),
-                                area, lineStyle);
-                        plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation,
-                            org.jfree.ui.Layer.BACKGROUND);
-                    }
-                    if (theme.parseShowVerticalLine()) {
-                        XYLineAnnotation lineBackAnnotation =
-                            createStickyLineAnnotation(
-                                StickyAxisAnnotation.SimpleAxis.X_AXIS,
-                                annotation.getHitPoint(), annotation.getPos(),
-                                area, lineStyle);
-                        plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation,
-                            org.jfree.ui.Layer.BACKGROUND);
-                    }
-                }
-            }
-        }
-
-        // Style the text.
-        if (textStyle != null) {
-            textStyle.apply(textAnnotation);
-        }
-
-        // Add the Annotations to renderer.
-        plot.getRenderer(rendererIndex).addAnnotation(textAnnotation,
-            org.jfree.ui.Layer.FOREGROUND);
-        plot.getRenderer(rendererIndex).addAnnotation(lineAnnotation,
-            org.jfree.ui.Layer.FOREGROUND);
-    }
-
-   /**
-     * Create annotation that sticks to "ground" (X) axis.
-     * @param area helper to calculate coordinates
-     * @param pos one-dimensional position (distance from axis)
-     * @param lineStyle the line style to use for the line.
-     */
-    protected static XYLineAnnotation createGroundStickAnnotation(
-        ChartArea area, float pos, LineStyle lineStyle
-    ) {
-        // Style the line.
-        if (lineStyle != null) {
-            return new XYLineAnnotation(
-                pos, area.atGround(),
-                pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET),
-                new BasicStroke(lineStyle.getWidth()),lineStyle.getColor());
-        }
-        else {
-            return new XYLineAnnotation(
-                pos, area.atGround(),
-                pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET));
-        }
-    }
-
-
-    /**
-     * Create annotation that sticks to the second Y axis ("right").
-     * @param area helper to calculate coordinates
-     * @param pos one-dimensional position (distance from axis)
-     * @param lineStyle the line style to use for the line.
-     */
-    protected static XYLineAnnotation createRightStickAnnotation(
-        ChartArea area, float pos, LineStyle lineStyle
-    ) {
-        // Style the line.
-        if (lineStyle != null) {
-            return new XYLineAnnotation(
-                area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos,
-                area.atRight(), pos,
-                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
-        }
-        else {
-            return new XYLineAnnotation(
-                area.atRight(), pos,
-                area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos);
-        }
-    }
-
-
-    /**
-     * Create annotation that sticks to the first Y axis ("left").
-     * @param area helper to calculate coordinates
-     * @param pos one-dimensional position (distance from axis)
-     * @param lineStyle the line style to use for the line.
-     */
-    protected static XYLineAnnotation createLeftStickAnnotation(
-        ChartArea area, float pos, LineStyle lineStyle
-    ) {
-        // Style the line.
-        if (lineStyle != null) {
-            return new XYLineAnnotation(
-                area.atLeft(), pos,
-                area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos,
-                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
-        }
-        else {
-            return new XYLineAnnotation(
-                area.atLeft(), pos,
-                area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos);
-        }
-    }
-
-
-    /**
-     * Create a line from a axis to a given point.
-     * @param axis   The "simple" axis.
-     * @param fromD1 from-location in first dimension.
-     * @param toD2   to-location in second dimension.
-     * @param area   helper to calculate offsets.
-     * @param lineStyle optional line style.
-     */
-    protected static XYLineAnnotation createStickyLineAnnotation(
-        StickyAxisAnnotation.SimpleAxis axis, float fromD1, float toD2,
-        ChartArea area, LineStyle lineStyle
-    ) {
-        double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d;
-        switch(axis) {
-            case X_AXIS:
-                anchorX1 = fromD1;
-                anchorX2 = fromD1;
-                anchorY1 = area.atGround();
-                anchorY2 = toD2;
-                break;
-            case Y_AXIS:
-                anchorX1 = area.atLeft();
-                anchorX2 = toD2;
-                anchorY1 = fromD1;
-                anchorY2 = fromD1;
-                break;
-            case Y_AXIS2:
-                anchorX1 = area.atRight();
-                anchorX2 = toD2;
-                anchorY1 = fromD1;
-                anchorY2 = fromD1;
-                break;
-        }
-        // Style the line.
-        if (lineStyle != null) {
-            return new XYLineAnnotation(
-                anchorX1, anchorY1,
-                anchorX2, anchorY2,
-                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
-        }
-        else {
-            return new XYLineAnnotation(
-                anchorX1, anchorY1,
-                anchorX2, anchorY2);
-        }
-    }
-
-    /**
-     * Add the annotations (Sticky, Text and hyk zones) stored
-     * in the annotations field.
-     * @param plot Plot to add annotations to.
-     */
-    protected void addAnnotationsToRenderer(XYPlot plot) {
-        logger.debug("addAnnotationsToRenderer");
-
-        if (annotations == null || annotations.isEmpty()) {
-            logger.debug("addAnnotationsToRenderer: no annotations.");
-            return;
-        }
-
-        // OPTMIMIZE: Pre-calculate positions
-        ChartArea area = new ChartArea(
-            plot.getDomainAxis(0).getRange(),
-            plot.getRangeAxis().getRange());
-
-        // Walk over all Annotation sets.
-        for (RiverAnnotation fa: annotations) {
-
-            // Access text styling, if any.
-            ThemeDocument theme = fa.getTheme();
-            TextStyle textStyle = null;
-            LineStyle lineStyle = null;
-
-            // Get Themeing information and add legend item.
-            if (theme != null) {
-                textStyle = theme.parseComplexTextStyle();
-                lineStyle = theme.parseComplexLineStyle();
-                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);
-                }
-            }
-
-            // The 'Sticky' Annotations (at axis, with line and text).
-            for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) {
-                addStickyAnnotation(
-                    sta, plot, area, lineStyle, textStyle, theme);
-            }
-
-            // 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);
-            }
-        }
-    }
-
-
-    /**
      * This method needs to be implemented by concrete subclasses to create new
      * instances of JFreeChart.
      *
@@ -585,40 +266,6 @@
         }
     }
 
-
-    /**
-     * Register annotations like MainValues for later plotting
-     *
-     * @param annotations list of annotations (data of facet).
-     * @param aandf   Artifact and the facet.
-     * @param theme   Theme document for given annotations.
-     * @param visible The visibility of the annotations.
-     */
-    public void doAnnotations(
-        RiverAnnotation annotations,
-        ArtifactAndFacet aandf,
-        ThemeDocument theme,
-        boolean visible
-    ){
-        logger.debug("doAnnotations");
-
-        // Add all annotations to our annotation pool.
-        annotations.setTheme(theme);
-        if (aandf != null) {
-            annotations.setLabel(aandf.getFacetDescription());
-        }
-        else {
-            logger.error(
-                "Art/Facet for Annotations is null. " +
-                "This should never happen!");
-        }
-
-        if (visible) {
-            addAnnotations(annotations);
-        }
-    }
-
-
     /**
      * Generate chart.
      */

http://dive4elements.wald.intevation.org