diff artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java @ 9186:eec4df8165a1

Implemented 'ShowLineLabel' for area themes.
author gernotbelger
date Thu, 28 Jun 2018 10:47:04 +0200
parents 77eb4553245b
children 6b2496d71936
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java	Thu Jun 28 10:47:00 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java	Thu Jun 28 10:47:04 2018 +0200
@@ -122,6 +122,8 @@
 import org.jfree.chart.urls.XYURLGenerator;
 import org.jfree.data.xy.DefaultXYDataset;
 import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
 import org.jfree.io.SerialUtilities;
 import org.jfree.ui.RectangleEdge;
 import org.jfree.util.PaintUtilities;
@@ -176,6 +178,15 @@
 
     private final boolean drawOriginalSeries;
 
+    /** NumberFormat to use for area. */
+    private NumberFormat areaLabelNumberFormat;
+
+    private int areaCalculationMode;
+
+    private double positiveArea;
+
+    private double negativeArea;
+
     /** The color of the label showing the calculated area. */
     private Color labelColor;
 
@@ -185,21 +196,15 @@
     /** Font to draw label of calculated area with. */
     private Font labelFont;
 
+    /** Whether or not to draw a label that shows the title of the theme. */
+    private boolean drawTitleLabel = false;
+
+    /** Whether or not to draw a label that shows the area of the polygon. */
+    private boolean drawAreaLabel = false;
+
     /** Template to create i18ned label for area. */
     private String areaLabelTamplate;
 
-    /** NumberFormat to use for area. */
-    private NumberFormat areaLabelNumberFormat;
-
-    private int areaCalculationMode;
-
-    private double positiveArea;
-
-    private double negativeArea;
-
-    /** Whether or not to draw a label in the area. */
-    private boolean labelArea = true;
-
     /** Arithmetic centroid of drawn polygons. */
     private Point2D.Double centroid;
 
@@ -217,6 +222,12 @@
      */
     private final boolean roundXCoordinates;
 
+    /** Holds the minimal x value in screen coordinates, will updated during the draw operation */
+    private transient double minimumScreenX = Double.POSITIVE_INFINITY;
+
+    /** Holds the y value in screen coordinates at the minimum x value **/
+    private transient double minimumScreenX_Y = Double.POSITIVE_INFINITY;
+
     /**
      * Creates a new renderer with default attributes.
      */
@@ -270,8 +281,12 @@
         this.areaLabelNumberFormat = nf;
     }
 
-    public void setLabelArea(final boolean label) {
-        this.labelArea = label;
+    public void setShowAreaLabel(final boolean doDrawAreaLabel) {
+        this.drawAreaLabel = doDrawAreaLabel;
+    }
+
+    public void setShowTitleLabel(final boolean doDrawTitleLabel) {
+        this.drawTitleLabel = doDrawTitleLabel;
     }
 
     /** Set font to paint label with. */
@@ -811,6 +826,7 @@
     public void drawItem(final Graphics2D g2, final XYItemRendererState state, final Rectangle2D dataArea, final PlotRenderingInfo info, final XYPlot plot,
             final ValueAxis domainAxis, final ValueAxis rangeAxis, final XYDataset dataset, final int series, final int item,
             final CrosshairState crosshairState, final int pass) {
+
         switch (pass) {
         case 0:
             for (final XYDataset ds : splitByNaNs(dataset)) {
@@ -819,38 +835,7 @@
             break;
         case 1:
             drawItemPass1(g2, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState);
-        }
-
-        // Find geometric middle, calculate area and paint
-        // a string with it here.
-        if (pass == 1 && this.labelArea && this.areaLabelNumberFormat != null && this.areaLabelTamplate != null) {
-            double center_x = this.centroid.getX();
-            double center_y = this.centroid.getY();
-            center_x = domainAxis.valueToJava2D(center_x, dataArea, plot.getDomainAxisEdge());
-            center_y = rangeAxis.valueToJava2D(center_y, dataArea, plot.getRangeAxisEdge());
-
-            // Respect text-extend if text should appear really centered.
-
-            float area = 0f;
-            if (this.areaCalculationMode == CALCULATE_POSITIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA) {
-                area += Math.abs(this.positiveArea);
-            }
-            if (this.areaCalculationMode == CALCULATE_NEGATIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA) {
-                area += Math.abs(this.negativeArea);
-            }
-            if (area != 0f) {
-                final Color oldColor = g2.getColor();
-                final Font oldFont = g2.getFont();
-                g2.setFont(this.labelFont);
-                final String labelText = String.format(this.areaLabelTamplate, this.areaLabelNumberFormat.format(area));
-                if (this.labelBGColor != null) {
-                    EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText, (float) center_x, (float) center_y, this.labelBGColor);
-                }
-                g2.setColor(this.labelColor);
-                g2.drawString(labelText, (float) center_x, (float) center_y);
-                g2.setFont(oldFont);
-                g2.setColor(oldColor);
-            }
+            break;
         }
     }
 
@@ -884,21 +869,18 @@
             final ValueAxis x_domainAxis, final ValueAxis x_rangeAxis, final XYDataset x_dataset, final int x_series, final int x_item,
             final CrosshairState x_crosshairState) {
 
-        if (!((0 == x_series) && (0 == x_item))) {
+        if (x_series != 0 || x_item != 0)
             return;
-        }
 
         final boolean b_impliedZeroSubtrahend = (1 == x_dataset.getSeriesCount());
 
         // check if either series is a degenerate case (i.e. less than 2 points)
-        if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend)) {
+        if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend))
             return;
-        }
 
         // check if series are disjoint (i.e. domain-spans do not overlap)
-        if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset)) {
+        if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset))
             return;
-        }
 
         // polygon definitions
         final List<Double> l_minuendXs = new LinkedList<>();
@@ -1268,6 +1250,66 @@
         createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis, x_rangeAxis, b_positive, l_polygonXs, l_polygonYs);
     }
 
+    private void drawItemPass1(final Graphics2D g2, final Rectangle2D dataArea, final PlotRenderingInfo info, final XYPlot plot, final ValueAxis domainAxis,
+            final ValueAxis rangeAxis, final XYDataset dataset, final int series, final int item, final CrosshairState crosshairState) {
+
+        doDrawItemPass1(g2, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState);
+
+        final int lastSeries = dataset.getSeriesCount() - 1;
+        final int lastItem = dataset.getItemCount(series) - 1;
+        if (series == lastSeries && item == lastItem) {
+            // draw labels: only once per theme!
+            drawAreaLabel(g2, dataArea, plot, domainAxis, rangeAxis);
+            drawTitleLabel(g2, dataArea, info.getOwner().getEntityCollection(), dataset);
+        }
+    }
+
+    private void drawAreaLabel(final Graphics2D g2, final Rectangle2D dataArea, final XYPlot plot, final ValueAxis domainAxis, final ValueAxis rangeAxis) {
+
+        if (!this.drawAreaLabel)
+            return;
+
+        if (this.areaLabelNumberFormat == null || this.areaLabelTamplate == null || this.centroid == null)
+            return;
+
+        // Respect text-extend if text should appear really centered.
+        float area = 0f;
+        if (this.areaCalculationMode == CALCULATE_POSITIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA)
+            area += Math.abs(this.positiveArea);
+        if (this.areaCalculationMode == CALCULATE_NEGATIVE_AREA || this.areaCalculationMode == CALCULATE_ALL_AREA)
+            area += Math.abs(this.negativeArea);
+
+        if (area != 0f) {
+
+            final String labelText = String.format(this.areaLabelTamplate, this.areaLabelNumberFormat.format(area));
+
+            final double center_x = this.centroid.getX();
+            final double center_y = this.centroid.getY();
+
+            final double screenX = domainAxis.valueToJava2D(center_x, dataArea, plot.getDomainAxisEdge());
+            final double screenY = rangeAxis.valueToJava2D(center_y, dataArea, plot.getRangeAxisEdge());
+
+            drawLabel(g2, labelText, screenX, screenY);
+        }
+    }
+
+    private void drawTitleLabel(final Graphics2D g2, final Rectangle2D dataArea, final EntityCollection entities, final XYDataset dataset) {
+
+        if (!this.drawTitleLabel)
+            return;
+
+        if (Double.isInfinite(this.minimumScreenX))
+            return;
+
+        if (dataset instanceof XYSeriesCollection) {
+            final XYSeries xYSeries = ((XYSeriesCollection) dataset).getSeries(0);
+            final String label = (xYSeries instanceof HasLabel) ? ((HasLabel) xYSeries).getLabel() : xYSeries.getKey().toString();
+
+            EnhancedLineAndShapeRenderer.drawLineLabel(g2, dataArea, entities, this.minimumScreenX, this.minimumScreenX_Y, this.labelFont, this.labelColor,
+                    this.labelBGColor != null, this.labelBGColor, label);
+        }
+    }
+
     /**
      * Draws the visual representation of a single data item, second pass. In
      * the second pass, the renderer draws the lines and shapes for the
@@ -1296,15 +1338,14 @@
      *            crosshair information for the plot
      *            (<code>null</code> permitted).
      */
-    private void drawItemPass1(final Graphics2D x_graphics, final Rectangle2D x_dataArea, final PlotRenderingInfo x_info, final XYPlot x_plot,
+    private void doDrawItemPass1(final Graphics2D x_graphics, final Rectangle2D x_dataArea, final PlotRenderingInfo x_info, final XYPlot x_plot,
             final ValueAxis x_domainAxis, final ValueAxis x_rangeAxis, final XYDataset x_dataset, final int x_series, final int x_item,
             final CrosshairState x_crosshairState) {
 
         Shape l_entityArea = null;
         EntityCollection l_entities = null;
-        if (null != x_info) {
+        if (x_info != null)
             l_entities = x_info.getOwner().getEntityCollection();
-        }
 
         final Paint l_seriesPaint = getItemPaint(x_series, x_item);
         final Stroke l_seriesStroke = getItemStroke(x_series, x_item);
@@ -1320,6 +1361,13 @@
         final double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea, l_domainAxisLocation);
         final double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea, l_rangeAxisLocation);
 
+        /* update minimumScreenX -> used to position title */
+        // REMARK: ignore points with y == 0.0 --> else the label sticks on the zero-line, becaue most area themes start at 0.0
+        if (l_x1 < this.minimumScreenX && Math.abs(l_y1) > 0.01) {
+            this.minimumScreenX = l_x1;
+            this.minimumScreenX_Y = l_y1;
+        }
+
         // These are the shapes of the series items.
         if (getShapesVisible()) {
             Shape l_shape = getItemShape(x_series, x_item);
@@ -1344,10 +1392,10 @@
         } // if (getShapesVisible())
 
         // add an entity for the item...
-        if (null != l_entities) {
-            if (null == l_entityArea) {
+        if (l_entities != null) {
+            if (l_entityArea == null)
                 l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2), 4, 4);
-            }
+
             String l_tip = null;
             final XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series, x_item);
             if (null != l_tipGenerator) {
@@ -1363,9 +1411,8 @@
         }
 
         // draw the item label if there is one...
-        if (isItemLabelVisible(x_series, x_item)) {
+        if (isItemLabelVisible(x_series, x_item))
             drawItemLabel(x_graphics, l_orientation, x_dataset, x_series, x_item, l_x1, l_y1, (l_y1 < 0.0));
-        }
 
         final int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis);
         final int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis);
@@ -1379,11 +1426,10 @@
         final double l_y2 = x_rangeAxis.valueToJava2D(x_dataset.getYValue(x_series, (x_item - 1)), x_dataArea, l_rangeAxisLocation);
 
         Line2D l_line = null;
-        if (PlotOrientation.HORIZONTAL == l_orientation) {
+        if (PlotOrientation.HORIZONTAL == l_orientation)
             l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2);
-        } else if (PlotOrientation.VERTICAL == l_orientation) {
+        else if (PlotOrientation.VERTICAL == l_orientation)
             l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2);
-        }
 
         if ((null != l_line) && l_line.intersects(x_dataArea)) {
             x_graphics.setPaint(getItemPaint(x_series, x_item));
@@ -1720,4 +1766,20 @@
         this.negativePaint = SerialUtilities.readPaint(stream);
         this.legendShape = SerialUtilities.readShape(stream);
     }
+
+    private void drawLabel(final Graphics2D g2, final String labelText, final double screenX, final double screenY) {
+
+        final Color oldColor = g2.getColor();
+        final Font oldFont = g2.getFont();
+
+        g2.setFont(this.labelFont);
+        if (this.labelBGColor != null)
+            EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText, (float) screenX, (float) screenY, this.labelBGColor);
+
+        g2.setColor(this.labelColor);
+        g2.drawString(labelText, (float) screenX, (float) screenY);
+
+        g2.setFont(oldFont);
+        g2.setColor(oldColor);
+    }
 }
\ No newline at end of file

http://dive4elements.wald.intevation.org