changeset 1037:75cf1b11c97e

Improved CustomAnnotation rendering. flys-artifacts/trunk@2498 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Wed, 17 Aug 2011 12:32:26 +0000
parents e6aff80b59ff
children 4dcc635d6ca6
files flys-artifacts/ChangeLog flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
diffstat 2 files changed, 151 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Wed Aug 17 09:16:20 2011 +0000
+++ b/flys-artifacts/ChangeLog	Wed Aug 17 12:32:26 2011 +0000
@@ -1,4 +1,14 @@
-2011-08-16  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+2011-08-17  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Improved CustomAnnotations and rendering thereof, now including an
+	"axis mark" (little line at axis), also prepared possibility to put
+	annotations on Y-axis.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Improved CustomAnnotation to include marks on the axis and better spacing
+	  from it.
+
+2011-08-17  Felix Wolfsteller <felix.wolfsteller@intevation.de>
 
 	Implemented proof-of-concept collision-detection when drawing
 	CustomAnnotations (text only).
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Wed Aug 17 09:16:20 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Wed Aug 17 12:32:26 2011 +0000
@@ -8,6 +8,7 @@
 
 import java.awt.Shape;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.Line2D;
 
 import org.jfree.chart.annotations.XYLineAnnotation;
 import org.jfree.chart.annotations.XYTextAnnotation;
@@ -26,6 +27,7 @@
 import org.jfree.ui.RectangleEdge;
 import org.jfree.chart.plot.Plot;
 import org.jfree.chart.ChartRenderingInfo;
+import org.jfree.chart.util.LineUtilities;
 
 import org.w3c.dom.Document;
 
@@ -41,10 +43,25 @@
 import de.intevation.flys.model.Annotation;
 
 /**
- * Custom annotations class that is drawn only if no collisions with other
+ * Custom Annotations class that is drawn only if no collisions with other
  * already drawn CustomAnnotations in current plot are found.
+ * Draws a given text and a line to it from either axis.
  */
-class CustomAnnotation extends XYTextAnnotation{
+class CustomAnnotation extends XYTextAnnotation {
+
+    /** Logger for this class. */    
+    private static Logger logger =
+        Logger.getLogger(CustomAnnotation.class);
+
+    /** Simplified view on axes. */
+    public static enum SimpleAxis {
+        X_AXIS, /** Usually "horizontal". */
+        Y_AXIS  /** Usually "vertical". */
+    }
+
+    /** Which axis to stick to. */
+    protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS;
+
 
     /**
      * Trivial constructor.
@@ -59,6 +76,86 @@
 
 
     /**
+     * Sets the "sticky axis" (whether to draw annotations at the
+     * X- or the Y-Axis.
+     *
+     * @param stickyAxis axis to stick to.
+     */
+    public void setStickyAxis(SimpleAxis stickyAxis) {
+        this.stickyAxis = stickyAxis;
+    }
+
+
+    /**
+     * Draws a small line at axis where this annotation resides.
+     *
+     * @param g2          the graphics device.
+     * @param dataArea    the data area.
+     * @param domainAxis  the domain axis.
+     * @param rangeAxis   the range axis.
+     * @param domainEdge  the domain edge.
+     * @param rangeEdge   the range edge.
+     * @param orientation the plot orientation.
+     */
+    protected void drawAxisMark(
+            java.awt.Graphics2D g2,
+            java.awt.geom.Rectangle2D dataArea,
+            ValueAxis domainAxis,
+            ValueAxis rangeAxis,
+            RectangleEdge domainEdge,
+            RectangleEdge rangeEdge,
+            PlotOrientation orientation) {
+        float j2DX1 = 0.0f;
+        float j2DX2 = 0.0f;
+        float j2DY1 = 0.0f;
+        float j2DY2 = 0.0f;
+        float x = (float) getX();
+        float y = (float) getY();
+        /* When dependent on X/Y-Axis and orientation, following
+           can be used as a base:
+        if (orientation == PlotOrientation.VERTICAL) {
+            j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea,
+                        domainEdge);
+            j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea,
+                        rangeEdge);
+            j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea,
+                        domainEdge);
+            j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea,
+                        rangeEdge);
+            }
+        else if (orientation == PlotOrientation.HORIZONTAL) {
+            j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea,
+                    domainEdge);
+            j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea,
+                    rangeEdge);
+            j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea,
+                    domainEdge);
+            j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea,
+                    rangeEdge);
+        }
+
+        g2.setPaint(this.paint);
+        g2.setStroke(this.stroke);
+        */
+        j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge);
+        j2DY2 = j2DY1 - 0.10f * (float)
+            (rangeAxis.getRange().getUpperBound() 
+             - rangeAxis.getRange().getLowerBound());
+        j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge);
+        j2DX2 = j2DX1;
+
+        Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
+
+        // line is clipped to avoid JRE bug 6574155, for more info
+        // see JFreeChart bug 2221495
+        boolean visible = LineUtilities.clipLine(line, dataArea);
+        if (visible) {
+            g2.draw(line);
+        }
+    }
+
+
+    /**
      * Draw the Annotiation if it does not collide with other already drawn
      * Annotations.
      *
@@ -85,16 +182,14 @@
         if (info == null)
             return;
 
-        // Calculate bounding box as in super.draw().
-        // TODO overwrite draw such that even if the annotation gets painted
-        // the bounding box has to be calculated only once.
+        // Calculate the bounding box.
         ChartRenderingInfo chartInfo = info.getOwner();
 
         PlotOrientation orientation = plot.getOrientation();
         RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
-        plot.getDomainAxisLocation(), orientation);
+            plot.getDomainAxisLocation(), orientation);
         RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
-        plot.getRangeAxisLocation(), orientation);
+            plot.getRangeAxisLocation(), orientation);
         float anchorX = (float) domainAxis.valueToJava2D(
             getX(), dataArea, domainEdge);
         float anchorY = (float) rangeAxis.valueToJava2D(
@@ -103,13 +198,17 @@
             float tempAnchor = anchorX;
             anchorX = anchorY;
             anchorY = tempAnchor;
-        }         
+        }
 
+        // Always draw the small line at axis.
+        drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge,
+                rangeEdge, orientation);
+
+        g2.setFont(getFont());
         Shape hotspot = TextUtilities.calculateRotatedStringBounds(
            getText(), g2, anchorX, anchorY, getTextAnchor(),
            getRotationAngle(), getRotationAnchor());
         Rectangle2D hotspotBox = hotspot.getBounds2D();
-
         // Check for collisions with other XYAnnotations.
         for (Iterator i = chartInfo.getEntityCollection().iterator();
                 i.hasNext(); ) {
@@ -124,10 +223,23 @@
             }
         }
 
-        // Set URL of current annotation. This will let super.draw() add
-        // the relevant info to the PlotRenderingInfo.
-        setURL("");
-        super.draw(g2, plot, dataArea, domainAxis, rangeAxis, rendererIndex, info);
+        // Actuall drawing.
+        if (getBackgroundPaint() != null) {
+        g2.setPaint(getBackgroundPaint());
+            g2.fill(hotspot);
+        }
+        g2.setPaint(getPaint());
+        TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY,
+                getTextAnchor(), getRotationAngle(), getRotationAnchor());
+        // Draw outline.
+        if (false) {
+            g2.setStroke(getOutlineStroke());
+            g2.setPaint(getOutlinePaint());
+            g2.draw(hotspot);
+        }
+
+        // Add info that we have drawn this Annotation.
+        addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL());
     }
 }
 
@@ -141,7 +253,7 @@
 extends      XYChartGenerator
 implements   FacetTypes
 {
-    /** The logger that is used in this generator.*/
+    /** The logger that is used in this generator. */
     private static Logger logger =
         Logger.getLogger(LongitudinalSectionGenerator.class);
 
@@ -238,15 +350,21 @@
     /**
      * Remove all annotations from plot and re-insert them at an approximately
      * okay position. The followed approach is naive but side-effect free.
+     *
+     * @param plot the plot.
+     * @param axis the value axis.
      */
     protected void redoAnnotations(XYPlot plot, ValueAxis axis) {
         plot.clearAnnotations();
+        // TODO Position calculation could/should be done in
+        // the CustomAnnotation-Implementation itself.
         ValueAxis yAxis = plot.getRangeAxis();
         float posY = 140.f;
         if (yAxis != null) {
             posY = (float) yAxis.getRange().getLowerBound();
-            // Lets add some (1%) space between Text and Axis .
-            posY += 0.1f * (yAxis.getRange().getUpperBound()
+            posYLess = posY;
+            // Add some (2%) space between Text and axis.
+            posY += 0.02f * (yAxis.getRange().getUpperBound()
                     - yAxis.getRange().getLowerBound());
         }
 
@@ -261,9 +379,6 @@
             ta.setRotationAnchor(TextAnchor.CENTER_LEFT);
             ta.setTextAnchor(TextAnchor.CENTER_LEFT);
             plot.getRenderer().addAnnotation(ta);
-            // TODO Merge XYLineAnnotation and CustomAnnotation.
-            XYLineAnnotation la = new XYLineAnnotation(posX, 0, posX, posY);
-            plot.getRenderer().addAnnotation(la);
         }
     }
 
@@ -332,6 +447,12 @@
     }
 
 
+    /**
+     * Register annotations available for the diagram.
+     *
+     * @param o     list of annotations (data of facet).
+     * @param theme ignored.
+     */
     protected void doAnnotationsOut(Object o, Document theme) {
         logger.debug("LongitudinalSectionGenerator.doAnnotationsOut");
         this.annotations = (List<Annotation>) o;

http://dive4elements.wald.intevation.org