diff flys-artifacts/src/main/java/de/intevation/flys/exports/LegendProcessor.java @ 3183:05c84d65988a

Extracted legenditemaggregation from xychartgenerator. flys-artifacts/trunk@4798 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Tue, 26 Jun 2012 12:48:26 +0000
parents
children 89dc2db3a202
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LegendProcessor.java	Tue Jun 26 12:48:26 2012 +0000
@@ -0,0 +1,148 @@
+package de.intevation.flys.exports;
+
+import java.awt.geom.Line2D;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.plot.XYPlot;
+
+
+/** Class to process Plots legends. */
+public abstract class LegendProcessor {
+
+    /** (Empty) shape for aggregated Legend Items. */
+    private static final Line2D.Double SPACE = new Line2D.Double(0,0,0,0);
+ 
+
+    /** Prevent instantiations. */
+    private LegendProcessor() {
+    }
+
+
+    /**
+     * Create a hash from a legenditem.
+     * This hash can then be used to merge legend items labels.
+     * @return hash for given legenditem to identify mergeables.
+     */
+    protected static String legendItemHash(LegendItem li) {
+        // TODO Do proper implementation. Ensure that only mergable sets are created.
+        // getFillPaint()
+        // getFillPaintTransformer()
+        // getLabel()
+        // getLine()
+        // getLinePaint()
+        // getLineStroke()
+        // getOutminePaint()
+        // getOutlineStroke()
+        // Shape getShape()
+        // String getToolTipText()
+        // String getURLText()
+        // boolean isLineVisible()
+        // boolean isShapeFilled()
+        // boolean isShapeOutlineVisible()
+        // boolean isShapeVisible()
+        String hash = li.getLinePaint().toString();
+        String label = li.getLabel();
+        if (label.startsWith("W (") || label.startsWith("W(")) {
+            hash += "-W-";
+        }
+        else if (label.startsWith("Q(") || label.startsWith("Q (")) {
+            hash += "-Q-";
+        }
+
+        // WQ.java holds example of using regex Matcher/Pattern.
+
+        return hash;
+    }
+
+
+    /**
+     * Create new legend entries, dependent on settings.
+     * @param plot The plot for which to modify the legend.
+     * @param threshold How many items are needed for aggregation to
+     *        be triggered?
+     */
+    public static void aggregateLegendEntries(XYPlot plot, int threshold) {
+        LegendItemCollection old = plot.getLegendItems();
+        // Find "similar" entries if aggregation is enabled.
+
+        int maxListSize = 0;
+        int AGGR_THRESHOLD = threshold;
+
+        if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0){
+            return;
+        }
+
+        HashMap<String, List<LegendItem>> entries = new LinkedHashMap<String, List<LegendItem>>();
+        for (Iterator i = old.iterator(); i.hasNext();) {
+            LegendItem item = (LegendItem) i.next();
+            String hash = legendItemHash(item);
+            List<LegendItem> itemList = entries.get(hash);
+            if (itemList == null) {
+                itemList = new ArrayList<LegendItem>();
+            }
+            itemList.add(item);
+
+            if (itemList.size() > maxListSize) {
+                maxListSize = itemList.size();
+            }
+
+            entries.put(legendItemHash(item), itemList);
+        }
+
+        if (maxListSize < AGGR_THRESHOLD) {
+            // No need to do anything.
+            return;
+        }
+
+        // Run over collected entries, merge their names and create new
+        // entry if needed.
+        LegendItemCollection newLegend = new LegendItemCollection();
+        for (Map.Entry<String, List<LegendItem>> cursor: entries.entrySet()) {
+            List<LegendItem> itemList = cursor.getValue();
+            if (itemList.size() >= AGGR_THRESHOLD) {
+                // Now do merging.
+                LegendItem item = (LegendItem) itemList.get(0);
+                // Unfortunately we cannot clone and just setDescription, as this
+                // method was added in JFreeChart 1.0.14 (we are at .13).
+
+                // Remove the shapes of all but the first items,
+                // to prevent "overfill" of legenditemblock.
+                for (int i = 0; i < itemList.size(); i++) {
+                    if (i != 0) {
+                        LegendItem litem = itemList.get(i);
+
+                        // Make shape and line really small.
+                        LegendItem merged = new LegendItem(
+                            "," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(),
+                            litem.getURLText(), false, SPACE,
+                            false, litem.getFillPaint(), false,
+                            litem.getOutlinePaint(), litem.getOutlineStroke(), false,
+                            SPACE, litem.getLineStroke(), litem.getLinePaint());
+                        newLegend.add(merged);
+                    }
+                    else {
+                        newLegend.add(itemList.get(i));
+                    }
+                }
+            }
+            else {
+                // Do not merge entries.
+                for (LegendItem li: itemList) {
+                    newLegend.add(li);
+                }
+            }
+        }
+
+        plot.setFixedLegendItems (newLegend);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org