Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java @ 9555:ef5754ba5573
Implemented legend aggregation based on type of themes.
Added theme-editor style configuration for aggregated legend entries.
Only configured themes get aggregated.
author | gernotbelger |
---|---|
date | Tue, 23 Oct 2018 16:26:48 +0200 |
parents | d8e753d0fdb9 |
children | 6b2496d71936 |
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde * Software engineering by Intevation GmbH * * This file is Free Software under the GNU AGPL (>=v3) * and comes with ABSOLUTELY NO WARRANTY! Check out the * documentation coming with Dive4Elements River for details. */ package org.dive4elements.river.jfree; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Paint; import java.awt.Stroke; import java.awt.TexturePaint; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import org.apache.log4j.Logger; import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.exports.LegendAggregator; import org.dive4elements.river.java2d.ShapeUtils; import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; import org.jfree.chart.LegendItem; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeriesCollection; /** * One or more dataseries to draw a polygon (either "open up/downwards", or * the area between two curves), a theme-document and further display options. * The theme-document will later "style" the graphical representation. * The display options can be used to control the z-order and the axis of the * dataset. */ // FIXME: bad abstraction: the only purpose of this derivation is to apply specific styles. This should rather be solved // similar to the XYSTyle. public class StyledAreaSeriesCollection extends XYSeriesCollection implements StyledXYDataset { private static final long serialVersionUID = 5274940965666948237L; private static final Logger log = Logger.getLogger(StyledAreaSeriesCollection.class); /** Mode, how to draw/which areas to fill. */ public enum FILL_MODE { UNDER, ABOVE, BETWEEN } /** MODE in use. */ private FILL_MODE mode; /** Theme-document with attributes about actual visual representation. */ private final ThemeDocument theme; /** * A 'type' that allows to categorize themes by it. Tyically this is simply the facet-name of the originating * {@link Facet}. */ private final String themeType; /** * @param theme * the theme-document. * @param string */ public StyledAreaSeriesCollection(final String themeType, final ThemeDocument theme) { this.themeType = themeType; this.theme = theme; this.mode = FILL_MODE.BETWEEN; } public String getThemeType() { return this.themeType; } /** Gets the Fill mode. */ private FILL_MODE getMode() { return this.mode; } /** Sets the Fill mode. */ public void setMode(final FILL_MODE fMode) { this.mode = fMode; } @Override public void applyTheme(final CallMeta callMeta, final XYPlot plot, final LegendAggregator legendBuilder, final int datasetIndex) { log.debug("Registering an 'area'renderer at idx: " + datasetIndex); final StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer(); if (getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { dRenderer.setPositivePaint(createTransparentPaint()); } plot.setRenderer(datasetIndex, dRenderer); applyTheme(dRenderer); // i18n dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(callMeta, 2, 4)); dRenderer.setAreaLabelTemplate(Resources.getMsg(callMeta, "area.label.template", "Area=%sm2")); final LegendItem legendItem = dRenderer.getLegendItem(datasetIndex, 0); if (legendItem != null) { legendBuilder.addLegendItem(this.themeType, legendItem); } else { log.warn("Could not get LegengItem for renderer: " + datasetIndex + ", series-idx " + 0); } } /** * Returns a transparently textured paint. * * @return a transparently textured paint. */ private static Paint createTransparentPaint() { // TODO why not use a transparent color? final BufferedImage texture = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR); return new TexturePaint(texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); } /** * Applies line color, size and type attributes to renderer, also * whether to draw lines and/or points. * * @param renderer * Renderer to apply theme to. * @return \param renderer */ private StableXYDifferenceRenderer applyTheme(final StableXYDifferenceRenderer renderer) { applyFillColor(renderer); applyShowBorder(renderer); applyShowArea(renderer); applyOutlineColor(renderer); applyOutlineStyle(renderer); applyShowLine(renderer); applyShowAreaLabel(renderer); applyShowLineLabel(renderer); applyPointStyle(renderer); applyShowMinimumMaximum(renderer); if (this.mode == FILL_MODE.UNDER) { renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA); } else if (this.mode == FILL_MODE.ABOVE) { renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA); } else { renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_ALL_AREA); } // Apply text style. this.theme.parseComplexTextStyle().apply(renderer); return renderer; } private void applyShowMinimumMaximum(final StableXYDifferenceRenderer renderer) { // TODO: nice to have // final boolean minimumVisible = this.theme.parseShowMinimum(); // renderer.setIsMinimumShapeVisible(minimumVisible); // // final boolean maximumVisible = this.theme.parseShowMaximum(); // renderer.setIsMaximumShapeVisible(maximumVisible); } private void applyFillColor(final StableXYDifferenceRenderer renderer) { Paint paint = parseFillPaint(); if (paint != null && this.getMode() == FILL_MODE.ABOVE) { renderer.setPositivePaint(paint); renderer.setNegativePaint(new Color(0, 0, 0, 0)); } else if (paint != null && this.getMode() == FILL_MODE.UNDER) { renderer.setNegativePaint(paint); renderer.setPositivePaint(new Color(0, 0, 0, 0)); } else { if (paint == null) paint = new Color(177, 117, 102); renderer.setPositivePaint(paint); renderer.setNegativePaint(paint); } } private Paint parseFillPaint() { final Color paint = this.theme.parseAreaBackgroundColor(); final int transparency = this.theme.parseAreaTransparency(); final Color alphaPaint = ShapeUtils.withAlpha(paint, transparency); final AreaFillPattern pattern = this.theme.parseAreaBackgroundPattern(); if (pattern == null || pattern == AreaFillPattern.patternFill) return alphaPaint; final BufferedImage image = pattern.getImage(alphaPaint); final Rectangle2D anchor = new Rectangle2D.Double(0, 0, image.getWidth(), image.getHeight()); return new TexturePaint(image, anchor); } private void applyShowBorder(final StableXYDifferenceRenderer renderer) { final boolean show = this.theme.parseAreaShowBorder(); renderer.setDrawOutline(show); } private void applyShowArea(final StableXYDifferenceRenderer renderer) { final boolean showArea = this.theme.parseShowArea(); renderer.setDrawArea(showArea); } private void applyShowLine(final StableXYDifferenceRenderer renderer) { /* FIXME: strange: this will enable/disable showing the 'point' shapes at each vertex. */ /* FIXME: this will also now be overridden by the option 'showpoints' */ final boolean show = this.theme.parseShowLine(); renderer.setShapesVisible(show); } private void applyOutlineColor(final StableXYDifferenceRenderer renderer) { final Color c = this.theme.parseLineColorField(); renderer.setOutlinePaint(c); } private void applyShowAreaLabel(final StableXYDifferenceRenderer renderer) { renderer.setShowAreaLabel(this.theme.parseShowAreaLabel()); } private void applyShowLineLabel(final StableXYDifferenceRenderer renderer) { // REMARK: using 'showlinelabel' to activate labeling the line with the title of the theme. This is the same behaviour // as for line-themes. final boolean showLabelLine = this.theme.parseShowLineLabel(); renderer.setShowTitleLabel(showLabelLine); } private void applyOutlineStyle(final StableXYDifferenceRenderer renderer) { final float[] dashes = this.theme.parseLineStyle(); final int size = this.theme.parseLineWidth(); Stroke stroke = null; if (dashes.length <= 1) { stroke = new BasicStroke(Integer.valueOf(size)); } else { stroke = new BasicStroke(Integer.valueOf(size), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.0f, dashes, 0.0f); } renderer.setOutlineStroke(stroke); } private void applyPointStyle(final StableXYDifferenceRenderer renderer) { final boolean showPoints = this.theme.parseShowPoints(); renderer.setShapesVisible(showPoints); if (showPoints) { final int size = this.theme.parsePointWidth(); final int dim = 2 * size; final Ellipse2D pointShape = new Ellipse2D.Double(-size, -size, dim, dim); final Color pointColor = this.theme.parsePointColor(); renderer.setSeriesPaint(0, pointColor); renderer.setSeriesPaint(1, pointColor); renderer.setSeriesShape(0, pointShape); renderer.setSeriesShape(1, pointShape); } } public boolean shouldCalculateRange() { return this.theme.parseCalculateRange(); } @Override public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument legendTheme) { /* not implemented */ } }