view artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java @ 8910:d9c89651bd67

Area chart layers may now have an 'arebgpattern'. Real pattern yet to be defined.
author gernotbelger
date Thu, 22 Feb 2018 18:46:37 +0100
parents e5f688820951
children 924cd9943337
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.jfree.data.xy.XYSeriesCollection;

import org.dive4elements.river.themes.ThemeDocument;

/**
 * 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 {
    private static final long serialVersionUID = 5274940965666948237L;

    /** 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 ThemeDocument theme;

    /**
     * @param theme the theme-document.
     */
    public StyledAreaSeriesCollection(ThemeDocument theme) {
        this.theme = theme;
        this.mode = FILL_MODE.BETWEEN;
   }


    /** Gets the Fill mode. */
    public FILL_MODE getMode() {
        return this.mode;
    }


    /** Sets the Fill mode. */
    public void setMode(FILL_MODE fMode) {
        this.mode = fMode;
    }


    /**
     * 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
     */
    public StableXYDifferenceRenderer applyTheme(
        StableXYDifferenceRenderer renderer
    ) {
        applyFillColor(renderer);
        applyShowShape(renderer);
        applyOutlineColor(renderer);
        applyOutlineStyle(renderer);
        applyShowLine(renderer);
        applyShowAreaLabel(renderer);
        applyPointStyle(renderer);
        if (mode == FILL_MODE.UNDER) {
            renderer.setAreaCalculationMode(
                StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA);
        }
        else if (mode == FILL_MODE.ABOVE) {
            renderer.setAreaCalculationMode(
                StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA);
        }
        else {
            renderer.setAreaCalculationMode(
                StableXYDifferenceRenderer.CALCULATE_ALL_AREA);
        }

        // Apply text style.
        theme.parseComplexTextStyle().apply(renderer);
        return renderer;
    }

    private void applyFillColor(final StableXYDifferenceRenderer renderer) {
        
        final boolean showArea = theme.parseShowArea();
        if( !showArea ) {
            renderer.setPositivePaint(null);
            renderer.setNegativePaint(null);
            return;
        }

        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 = theme.parseAreaTransparency();
        
        final Color alphaPaint = withAlpha(paint, transparency);
        
        final AreaFillPattern pattern = this.theme.parseAreaBackgroundPattern();

        if( pattern == null )
            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 Color withAlpha(final Color color, final int transparency) {

        if (transparency <= 0 || color == null)
            return color;
        
        return new Color(
                color.getRed(),
                color.getGreen(),
                color.getBlue(),
                (int)((100 - transparency) * 2.55f));
    }

    private void applyShowShape(StableXYDifferenceRenderer renderer) {
        boolean show = theme.parseAreaShowBorder();
        renderer.setDrawOutline(show);
    }


    private void applyShowLine(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 = theme.parseShowLine();
        renderer.setShapesVisible(show);
    }

    private void applyOutlineColor(StableXYDifferenceRenderer renderer) {
        Color c = theme.parseLineColorField();
        renderer.setOutlinePaint(c);
    }

    /** Inform renderer whether it should draw a label. */
    private void applyShowAreaLabel(StableXYDifferenceRenderer renderer) {
        renderer.setLabelArea(theme.parseShowAreaLabel());
    }

    private void applyOutlineStyle(StableXYDifferenceRenderer renderer) {
        float[] dashes = theme.parseLineStyle();
        int size       = 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 = theme.parsePointWidth();
            final int dim  = 2 * size;

            final Ellipse2D pointShape = new Ellipse2D.Double(-size, -size, dim, dim);
            final Color pointColor = theme.parsePointColor();

            renderer.setSeriesPaint(0, pointColor);
            renderer.setSeriesPaint(1, pointColor);

            renderer.setSeriesShape(0, pointShape);
            renderer.setSeriesShape(1, pointShape);
        }
    }

    public boolean shouldCalculateRange() {
        return theme.parseCalculateRange();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org