view gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonPlot.java @ 1087:92fce3b3d07f

Centered histograms in pdf exports. gnv-artifacts/trunk@1189 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 10 Jun 2010 09:23:33 +0000
parents 9cbc8343a04d
children f953c9a559d8
line wrap: on
line source
package de.intevation.gnv.jfreechart;

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Shape;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.AxisCollection;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.AxisSpace;
import org.jfree.chart.axis.AxisState;
import org.jfree.chart.axis.ValueAxis;

import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.PlotState;

import org.jfree.data.Range;

import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;

import org.jfree.util.ObjectList;

/**
 * A class for plotting polygons into a 2D chart. This plot makes use of <code>
 * PolygonRenderer</code>.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
// TODO implement cloneable
public class PolygonPlot
extends      Plot
{
    public static final String PLOT_TYPE = "PolygonPlot";

    public static final PlotOrientation DEFAULT_PLOT_ORIENTATION =
        PlotOrientation.VERTICAL;

    private PolygonDataset  dataset;
    private transient PolygonRenderer renderer;

    private PlotOrientation orientation;

    private RectangleInsets axisOffset;

    private ObjectList      domainAxisLocation;
    private ObjectList      rangeAxisLocation;
    private ObjectList      domainAxes;
    private ObjectList      rangeAxes;


    /**
     * Constructs a new PolygonPlot with a dataset and a renderer.
     *
     * @param dataset Dataset containing polygons.
     * @param renderer The renderer used to draw polygons.
     */
    public PolygonPlot(PolygonDataset dataset, PolygonRenderer renderer) {
        this(dataset, renderer, null, null, PlotOrientation.HORIZONTAL);
    }


    /**
     * @param dataset Dataset containing polygons.
     * @param renderer The renderer used to draw polygons.
     * @param orientation The orientation used for this plot.
     */
    public PolygonPlot(
        PolygonDataset  dataset,
        PolygonRenderer renderer,
        PlotOrientation orientation
    ) {
        this(dataset, renderer, null, null, orientation);
    }


    /**
     * @param dataset Dataset containing polygons.
     * @param renderer The renderer used to draw polygons.
     * @param domainAxis The x axis.
     * @param rangeAxis The y axis.
     * @param orientation The orientation used for this plot.
     */
    public PolygonPlot(
        PolygonDataset  dataset,
        PolygonRenderer renderer,
        ValueAxis       domainAxis,
        ValueAxis       rangeAxis,
        PlotOrientation orientation
    ) {
        super();

        this.dataset            = dataset;
        this.renderer           = renderer;
        this.domainAxes         = new ObjectList();
        this.rangeAxes          = new ObjectList();
        this.domainAxisLocation = new ObjectList();
        this.rangeAxisLocation  = new ObjectList();
        this.axisOffset         = RectangleInsets.ZERO_INSETS;

        if (orientation != null)
            this.orientation = orientation;
        else
            this.orientation = DEFAULT_PLOT_ORIENTATION;

        if (domainAxis != null) {
            this.domainAxes.set(0, domainAxis);
            domainAxis.setPlot(this);
        }
        domainAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);

        if (rangeAxis != null) {
            this.rangeAxes.set(0, rangeAxis);
            rangeAxis.setPlot(this);
        }
        rangeAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);

        configureDomainAxis();
        configureRangeAxis();
    }


    public void configureDomainAxis() {
        // we just have 1 dataset
        Range domainAxisRange = getDataset().getDomainBounds();

        for (int i = 0; i < domainAxes.size(); i++) {
            ValueAxis axis = (ValueAxis) domainAxes.get(i);

            if (axis != null) {
                axis.configure();
                axis.setRange(domainAxisRange);
            }
        }
    }

    public ValueAxis getDomainAxis() {
        return getDomainAxis(0);
    }

    public void setDomainAxis(ValueAxis axis) {
        domainAxes.set(0, axis);
    }

    public ValueAxis getDomainAxis(int index) {
        return index < domainAxes.size()
            ? (ValueAxis)domainAxes.get(index)
            : null;
    }

    public ValueAxis getRangeAxis() {
        return getRangeAxis(0);
    }

    public void setRangeAxis(ValueAxis axis) {
        rangeAxes.set(0, axis);
    }

    public ValueAxis getRangeAxis(int index) {
        return index < rangeAxes.size()
            ? (ValueAxis)rangeAxes.get(index)
            : null;
    }

    public  void configureRangeAxis() {
        // we just have 1 dataset
        Range rangeAxisRange = getDataset().getRangeBounds();

        for (int i = 0; i < rangeAxes.size(); i++) {
            ValueAxis axis = (ValueAxis) rangeAxes.get(i);

            if (axis != null) {
                axis.configure();
                axis.setRange(rangeAxisRange);
            }
        }
    }

    public PolygonDataset getDataset(){
        return this.dataset;
    }

    public String getPlotType() {
        return PLOT_TYPE;
    }

    public  void setDataset(PolygonDataset dataset) {
        this.dataset = dataset;
    }


    /**
     * This is the major method to draw the into a given Graphic2D object.
     *
     * @param g2 Graphics object where the plot is drawn into.
     * @param area The bounds for drawing this plot.
     * @param anchor An anchor point.
     * @param parentState The plot state.
     * @param info
     */
    public void draw(
        Graphics2D        g2,
        Rectangle2D       area,
        Point2D           anchor,
        PlotState         parentState,
        PlotRenderingInfo info
    ) {
        Graphics2D  savedG2       = g2;
        Rectangle2D savedDataArea = area;

        if (info != null) {
            info.setPlotArea(area);
            info.setDataArea(area);
        }

        AxisSpace space      = calculateAxisSpace(g2, area);
        Rectangle2D dataArea = space.shrink(area, null);

        // draw background and outline
        drawBackground(g2, area);
        drawOutline(g2, area);

        Shape savedClip = g2.getClip();
        g2.clip(area);

        Composite originalComposite = g2.getComposite();
        g2.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER,
            getForegroundAlpha()
        ));

        // draw axis
        drawAxes(g2, area, dataArea, info);

        if (!isEmptyOrNull(dataset)) {
            // draw data
            drawPolygons(savedG2, dataArea, info);
            drawLabels(savedG2, dataArea, info);
        }

        g2.setClip(savedClip);
        g2.setComposite(originalComposite);
    }


    /**
     * Method to draw the axis for this plot.
     *
     * @param g2
     * @param plotArea
     * @param dataArea
     * @param plotState
     */
    private void drawAxes(
        Graphics2D        g2,
        Rectangle2D       plotArea,
        Rectangle2D       dataArea,
        PlotRenderingInfo plotState
    ) {
        AxisCollection axisCollection = new AxisCollection();

        for (int i = 0; i < domainAxes.size(); i++) {
            ValueAxis axis = (ValueAxis) domainAxes.get(i);
            if (axis != null)
                axisCollection.add(axis, getDomainAxisEdge(i));
        }

        for (int i = 0; i < rangeAxes.size(); i++) {
            ValueAxis axis = (ValueAxis) rangeAxes.get(i);
            if (axis != null)
                axisCollection.add(axis, getRangeAxisEdge(i));
        }

        Map axisStateMap = new HashMap();

        // draw the top axes
        double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(
                dataArea.getHeight());
        Iterator iterator = axisCollection.getAxesAtTop().iterator();
        while (iterator.hasNext()) {
            ValueAxis axis = (ValueAxis) iterator.next();
            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
                    RectangleEdge.TOP, plotState);
            cursor = info.getCursor();
            axisStateMap.put(axis, info);
        }

        // draw the bottom axes
        cursor = dataArea.getMaxY()
                 + this.axisOffset.calculateBottomOutset(dataArea.getHeight());
        iterator = axisCollection.getAxesAtBottom().iterator();
        while (iterator.hasNext()) {
            ValueAxis axis = (ValueAxis) iterator.next();
            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
                    RectangleEdge.BOTTOM, plotState);
            cursor = info.getCursor();
            axisStateMap.put(axis, info);
        }

        // draw the left axes
        cursor = dataArea.getMinX()
                 - this.axisOffset.calculateLeftOutset(dataArea.getWidth());
        iterator = axisCollection.getAxesAtLeft().iterator();
        while (iterator.hasNext()) {
            ValueAxis axis = (ValueAxis) iterator.next();
            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
                    RectangleEdge.LEFT, plotState);
            cursor = info.getCursor();
            axisStateMap.put(axis, info);
        }

        // draw the right axes
        cursor = dataArea.getMaxX()
                 + this.axisOffset.calculateRightOutset(dataArea.getWidth());
        iterator = axisCollection.getAxesAtRight().iterator();
        while (iterator.hasNext()) {
            ValueAxis axis = (ValueAxis) iterator.next();
            AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
                    RectangleEdge.RIGHT, plotState);
            cursor = info.getCursor();
            axisStateMap.put(axis, info);
        }
    }


    /**
     * Put some labels at data items into the plot. Uses PolygonRenderer to do
     * this job.
     *
     * @param g2
     * @param area
     * @param info
     */
    private void drawLabels(
        Graphics2D        g2,
        Rectangle2D       area,
        PlotRenderingInfo info
    ) {
        renderer.drawLabels(g2, this, area, dataset);
    }


    /**
     * Plot the polygons. Uses PolygonRenderer to do this job.
     *
     * @param g2
     * @param area
     * @param info
     */
    private void drawPolygons(
        Graphics2D        g2,
        Rectangle2D       area,
        PlotRenderingInfo info
    ) {
        renderer.drawPolygons(g2, this, area, dataset);
    }


    private AxisSpace calculateAxisSpace(Graphics2D  g2, Rectangle2D plotArea) {
        AxisSpace space         = new AxisSpace();
        space                   = calculateRangeAxisSpace(g2, plotArea, space);
        Rectangle2D tmpPlotArea = space.shrink(plotArea, null);
        space                   = calculateDomainAxisSpace(g2, plotArea, space);

        return space;
    }


    private AxisSpace calculateDomainAxisSpace(
        Graphics2D  g2,
        Rectangle2D plotArea,
        AxisSpace   space
    ) {
        if (space == null)
            space = new AxisSpace();

        for (int i = 0; i < domainAxes.size(); i++) {
            Axis axis = (Axis) domainAxes.get(i);

            if (axis != null) {
                RectangleEdge edge = getDomainAxisEdge(i);
                space = axis.reserveSpace(g2, this, plotArea, edge, space);
            }
        }

        return space;
    }


    private AxisSpace calculateRangeAxisSpace(
        Graphics2D  g2,
        Rectangle2D plotArea,
        AxisSpace   space
    ) {
        if (space == null)
            space = new AxisSpace();

        for (int i = 0; i < rangeAxes.size(); i++) {
            Axis axis = (Axis) rangeAxes.get(i);

            if (axis != null) {
                RectangleEdge edge = getRangeAxisEdge(i);
                space = axis.reserveSpace(g2, this, plotArea, edge, space);
            }
        }

        return space;
    }


    public RectangleEdge getDomainAxisEdge() {
        return Plot.resolveDomainAxisLocation(
            getDomainAxisLocation(), orientation
        );
    }


    public RectangleEdge getDomainAxisEdge(int idx) {
        AxisLocation  location = getDomainAxisLocation(idx);
        RectangleEdge result   = Plot.resolveDomainAxisLocation(
            location, orientation
        );

        if (result == null)
            result = RectangleEdge.opposite(getDomainAxisEdge());

        return result;
    }


    public RectangleEdge getRangeAxisEdge() {
        return Plot.resolveRangeAxisLocation(
            getRangeAxisLocation(), orientation
        );
    }


    public RectangleEdge getRangeAxisEdge(int idx) {
        AxisLocation  location = getRangeAxisLocation(idx);
        RectangleEdge result   = Plot.resolveRangeAxisLocation(
            location,
            orientation
        );

        if (result == null)
            result = RectangleEdge.opposite(getRangeAxisEdge());

        return result;
    }


    public AxisLocation getDomainAxisLocation() {
        return (AxisLocation) domainAxisLocation.get(0);
    }


    public AxisLocation getDomainAxisLocation(int idx) {
        if (idx < domainAxisLocation.size())
            return (AxisLocation) domainAxisLocation.get(idx);

        return null;
    }


    public AxisLocation getRangeAxisLocation() {
        return (AxisLocation) rangeAxisLocation.get(0);
    }


    public AxisLocation getRangeAxisLocation(int idx) {
        if (idx < rangeAxisLocation.size())
            return (AxisLocation) rangeAxisLocation.get(idx);

        return null;
    }


    /**
     * @return true, if dataset is null or if it does not contain any
     * PolygonSeries, otherwise false.
     */
    private boolean isEmptyOrNull(PolygonDataset dataset) {
        if (dataset != null) {
            int seriesCount = dataset.getSeriesCount();
            for (int s = 0; s < seriesCount; s++) {
                PolygonSeries series = dataset.getSeries(s);
                if (series.getItemCount() > 0) {
                    return false;
                }
            }
        }
        return true;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org