sascha@422: package de.intevation.gnv.jfreechart;
sascha@422:
sascha@422: import java.awt.AlphaComposite;
sascha@422: import java.awt.Composite;
sascha@422: import java.awt.Graphics2D;
sascha@422: import java.awt.Shape;
sascha@422:
sascha@422: import java.awt.geom.Point2D;
sascha@422: import java.awt.geom.Rectangle2D;
sascha@422:
sascha@422: import java.util.HashMap;
sascha@422: import java.util.Iterator;
sascha@422: import java.util.Map;
sascha@422:
sascha@422: import org.jfree.chart.axis.Axis;
sascha@422: import org.jfree.chart.axis.AxisCollection;
sascha@422: import org.jfree.chart.axis.AxisLocation;
sascha@422: import org.jfree.chart.axis.AxisSpace;
sascha@422: import org.jfree.chart.axis.AxisState;
sascha@422: import org.jfree.chart.axis.ValueAxis;
sascha@422:
sascha@422: import org.jfree.chart.plot.Plot;
sascha@779: import org.jfree.chart.plot.PlotOrientation;
sascha@422: import org.jfree.chart.plot.PlotRenderingInfo;
sascha@422: import org.jfree.chart.plot.PlotState;
sascha@422:
sascha@422: import org.jfree.data.Range;
sascha@422:
sascha@422: import org.jfree.ui.RectangleEdge;
sascha@422: import org.jfree.ui.RectangleInsets;
sascha@422:
sascha@422: import org.jfree.util.ObjectList;
sascha@422:
sascha@422: /**
ingo@795: * A class for plotting polygons into a 2D chart. This plot makes use of
ingo@795: * PolygonRenderer
.
sascha@803: *
sascha@780: * @author Ingo Weinzierl
sascha@422: */
sascha@422: // TODO implement cloneable
sascha@422: public class PolygonPlot
sascha@422: extends Plot
sascha@422: {
sascha@422: public static final String PLOT_TYPE = "PolygonPlot";
sascha@422:
sascha@422: public static final PlotOrientation DEFAULT_PLOT_ORIENTATION =
sascha@422: PlotOrientation.VERTICAL;
sascha@422:
sascha@422: private PolygonDataset dataset;
sascha@422: private transient PolygonRenderer renderer;
sascha@422:
sascha@422: private PlotOrientation orientation;
sascha@422:
sascha@422: private RectangleInsets axisOffset;
sascha@422:
sascha@422: private ObjectList domainAxisLocation;
sascha@422: private ObjectList rangeAxisLocation;
sascha@422: private ObjectList domainAxes;
sascha@422: private ObjectList rangeAxes;
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * Constructs a new PolygonPlot with a dataset and a renderer.
ingo@795: *
ingo@795: * @param dataset Dataset containing polygons.
ingo@795: * @param renderer The renderer used to draw polygons.
ingo@795: */
sascha@422: public PolygonPlot(PolygonDataset dataset, PolygonRenderer renderer) {
sascha@422: this(dataset, renderer, null, null, PlotOrientation.HORIZONTAL);
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * @param dataset Dataset containing polygons.
ingo@795: * @param renderer The renderer used to draw polygons.
ingo@795: * @param orientation The orientation used for this plot.
ingo@795: */
sascha@422: public PolygonPlot(
sascha@422: PolygonDataset dataset,
sascha@422: PolygonRenderer renderer,
sascha@422: PlotOrientation orientation
sascha@422: ) {
sascha@422: this(dataset, renderer, null, null, orientation);
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * @param dataset Dataset containing polygons.
ingo@795: * @param renderer The renderer used to draw polygons.
ingo@795: * @param domainAxis The x axis.
ingo@795: * @param rangeAxis The y axis.
ingo@795: * @param orientation The orientation used for this plot.
ingo@795: */
sascha@422: public PolygonPlot(
sascha@422: PolygonDataset dataset,
sascha@422: PolygonRenderer renderer,
sascha@422: ValueAxis domainAxis,
sascha@422: ValueAxis rangeAxis,
sascha@422: PlotOrientation orientation
sascha@422: ) {
sascha@422: super();
sascha@422:
sascha@422: this.dataset = dataset;
sascha@422: this.renderer = renderer;
sascha@422: this.domainAxes = new ObjectList();
sascha@422: this.rangeAxes = new ObjectList();
sascha@422: this.domainAxisLocation = new ObjectList();
sascha@422: this.rangeAxisLocation = new ObjectList();
sascha@422: this.axisOffset = RectangleInsets.ZERO_INSETS;
sascha@422:
sascha@422: if (orientation != null)
sascha@422: this.orientation = orientation;
sascha@422: else
sascha@422: this.orientation = DEFAULT_PLOT_ORIENTATION;
sascha@422:
sascha@422: if (domainAxis != null) {
sascha@422: this.domainAxes.set(0, domainAxis);
sascha@422: domainAxis.setPlot(this);
sascha@422: }
sascha@422: domainAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
sascha@422:
sascha@422: if (rangeAxis != null) {
sascha@422: this.rangeAxes.set(0, rangeAxis);
sascha@422: rangeAxis.setPlot(this);
sascha@422: }
sascha@422: rangeAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
sascha@422:
sascha@422: configureDomainAxis();
sascha@422: configureRangeAxis();
sascha@422: }
sascha@422:
sascha@422:
sascha@422: public void configureDomainAxis() {
sascha@422: // we just have 1 dataset
sascha@422: Range domainAxisRange = getDataset().getDomainBounds();
sascha@422:
sascha@422: for (int i = 0; i < domainAxes.size(); i++) {
sascha@422: ValueAxis axis = (ValueAxis) domainAxes.get(i);
sascha@422:
sascha@422: if (axis != null) {
sascha@422: axis.configure();
sascha@422: axis.setRange(domainAxisRange);
sascha@422: }
sascha@422: }
sascha@422: }
sascha@422:
sascha@450: public ValueAxis getDomainAxis() {
sascha@450: return getDomainAxis(0);
sascha@450: }
sascha@450:
sascha@450: public ValueAxis getDomainAxis(int index) {
sascha@450: return index < domainAxes.size()
sascha@450: ? (ValueAxis)domainAxes.get(index)
sascha@450: : null;
sascha@450: }
sascha@450:
sascha@450: public ValueAxis getRangeAxis() {
sascha@450: return getRangeAxis(0);
sascha@450: }
sascha@450:
sascha@450: public ValueAxis getRangeAxis(int index) {
sascha@450: return index < rangeAxes.size()
sascha@450: ? (ValueAxis)rangeAxes.get(index)
sascha@450: : null;
sascha@450: }
sascha@422:
sascha@422: public void configureRangeAxis() {
sascha@422: // we just have 1 dataset
sascha@422: Range rangeAxisRange = getDataset().getRangeBounds();
sascha@422:
sascha@422: for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422: ValueAxis axis = (ValueAxis) rangeAxes.get(i);
sascha@422:
sascha@422: if (axis != null) {
sascha@422: axis.configure();
sascha@422: axis.setRange(rangeAxisRange);
sascha@422: }
sascha@422: }
sascha@422: }
sascha@422:
sascha@422: public PolygonDataset getDataset(){
sascha@422: return this.dataset;
sascha@422: }
sascha@422:
sascha@422: public String getPlotType() {
sascha@422: return PLOT_TYPE;
sascha@422: }
sascha@422:
sascha@422: public void setDataset(PolygonDataset dataset) {
sascha@422: this.dataset = dataset;
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * This is the major method to draw the into a given Graphic2D object.
ingo@795: *
ingo@795: * @param g2 Graphics object where the plot is drawn into.
ingo@795: * @param area The bounds for drawing this plot.
ingo@795: * @param anchor An anchor point.
ingo@795: * @param parentState The plot state.
ingo@795: * @param info
ingo@795: */
sascha@422: public void draw(
sascha@422: Graphics2D g2,
sascha@422: Rectangle2D area,
sascha@422: Point2D anchor,
sascha@422: PlotState parentState,
sascha@422: PlotRenderingInfo info
sascha@422: ) {
sascha@422: Graphics2D savedG2 = g2;
sascha@422: Rectangle2D savedDataArea = area;
sascha@422:
sascha@422: if (info != null) {
sascha@422: info.setPlotArea(area);
sascha@422: info.setDataArea(area);
sascha@422: }
sascha@422:
sascha@422: AxisSpace space = calculateAxisSpace(g2, area);
sascha@422: Rectangle2D dataArea = space.shrink(area, null);
sascha@422:
sascha@422: // draw background and outline
sascha@422: drawBackground(g2, area);
sascha@422: drawOutline(g2, area);
sascha@422:
sascha@422: Shape savedClip = g2.getClip();
sascha@422: g2.clip(area);
sascha@422:
sascha@422: Composite originalComposite = g2.getComposite();
sascha@422: g2.setComposite(AlphaComposite.getInstance(
sascha@422: AlphaComposite.SRC_OVER,
sascha@422: getForegroundAlpha()
sascha@422: ));
sascha@778:
sascha@422: // draw axis
sascha@422: drawAxes(g2, area, dataArea, info);
sascha@422:
sascha@422: if (!isEmptyOrNull(dataset)) {
sascha@422: // draw data
sascha@422: drawPolygons(savedG2, dataArea, info);
sascha@450: drawLabels(savedG2, dataArea, info);
sascha@422: }
sascha@422:
sascha@422: g2.setClip(savedClip);
sascha@422: g2.setComposite(originalComposite);
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * Method to draw the axis for this plot.
sascha@803: *
ingo@795: * @param g2
ingo@795: * @param plotArea
ingo@795: * @param dataArea
ingo@795: * @param plotState
ingo@795: */
sascha@422: private void drawAxes(
sascha@422: Graphics2D g2,
sascha@422: Rectangle2D plotArea,
sascha@422: Rectangle2D dataArea,
sascha@422: PlotRenderingInfo plotState
sascha@422: ) {
sascha@422: AxisCollection axisCollection = new AxisCollection();
sascha@422:
sascha@422: for (int i = 0; i < domainAxes.size(); i++) {
sascha@422: ValueAxis axis = (ValueAxis) domainAxes.get(i);
sascha@422: if (axis != null)
sascha@422: axisCollection.add(axis, getDomainAxisEdge(i));
sascha@422: }
sascha@422:
sascha@422: for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422: ValueAxis axis = (ValueAxis) rangeAxes.get(i);
sascha@422: if (axis != null)
sascha@422: axisCollection.add(axis, getRangeAxisEdge(i));
sascha@422: }
sascha@422:
sascha@422: Map axisStateMap = new HashMap();
sascha@422:
sascha@422: // draw the top axes
sascha@422: double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(
sascha@422: dataArea.getHeight());
sascha@422: Iterator iterator = axisCollection.getAxesAtTop().iterator();
sascha@422: while (iterator.hasNext()) {
sascha@422: ValueAxis axis = (ValueAxis) iterator.next();
sascha@422: AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422: RectangleEdge.TOP, plotState);
sascha@422: cursor = info.getCursor();
sascha@422: axisStateMap.put(axis, info);
sascha@422: }
sascha@422:
sascha@422: // draw the bottom axes
sascha@422: cursor = dataArea.getMaxY()
sascha@422: + this.axisOffset.calculateBottomOutset(dataArea.getHeight());
sascha@422: iterator = axisCollection.getAxesAtBottom().iterator();
sascha@422: while (iterator.hasNext()) {
sascha@422: ValueAxis axis = (ValueAxis) iterator.next();
sascha@422: AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422: RectangleEdge.BOTTOM, plotState);
sascha@422: cursor = info.getCursor();
sascha@422: axisStateMap.put(axis, info);
sascha@422: }
sascha@422:
sascha@422: // draw the left axes
sascha@422: cursor = dataArea.getMinX()
sascha@422: - this.axisOffset.calculateLeftOutset(dataArea.getWidth());
sascha@422: iterator = axisCollection.getAxesAtLeft().iterator();
sascha@422: while (iterator.hasNext()) {
sascha@422: ValueAxis axis = (ValueAxis) iterator.next();
sascha@422: AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422: RectangleEdge.LEFT, plotState);
sascha@422: cursor = info.getCursor();
sascha@422: axisStateMap.put(axis, info);
sascha@422: }
sascha@422:
sascha@422: // draw the right axes
sascha@422: cursor = dataArea.getMaxX()
sascha@422: + this.axisOffset.calculateRightOutset(dataArea.getWidth());
sascha@422: iterator = axisCollection.getAxesAtRight().iterator();
sascha@422: while (iterator.hasNext()) {
sascha@422: ValueAxis axis = (ValueAxis) iterator.next();
sascha@422: AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422: RectangleEdge.RIGHT, plotState);
sascha@422: cursor = info.getCursor();
sascha@422: axisStateMap.put(axis, info);
sascha@422: }
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * Put some labels at data items into the plot. Uses PolygonRenderer to do
ingo@795: * this job.
ingo@795: *
ingo@795: * @param g2
ingo@795: * @param area
ingo@795: * @param info
ingo@795: */
sascha@450: private void drawLabels(
sascha@450: Graphics2D g2,
sascha@450: Rectangle2D area,
sascha@450: PlotRenderingInfo info
sascha@450: ) {
sascha@450: renderer.drawLabels(g2, this, area, dataset);
sascha@450: }
sascha@450:
ingo@795:
ingo@795: /**
ingo@795: * Plot the polygons. Uses PolygonRenderer to do this job.
sascha@803: *
ingo@795: * @param g2
ingo@795: * @param area
ingo@795: * @param info
ingo@795: */
sascha@422: private void drawPolygons(
sascha@422: Graphics2D g2,
sascha@422: Rectangle2D area,
sascha@422: PlotRenderingInfo info
sascha@422: ) {
sascha@451: renderer.drawPolygons(g2, this, area, dataset);
sascha@422: }
sascha@422:
sascha@422:
sascha@422: private AxisSpace calculateAxisSpace(Graphics2D g2, Rectangle2D plotArea) {
sascha@422: AxisSpace space = new AxisSpace();
sascha@422: space = calculateRangeAxisSpace(g2, plotArea, space);
sascha@422: Rectangle2D tmpPlotArea = space.shrink(plotArea, null);
sascha@422: space = calculateDomainAxisSpace(g2, plotArea, space);
sascha@422:
sascha@422: return space;
sascha@422: }
sascha@422:
sascha@422:
sascha@422: private AxisSpace calculateDomainAxisSpace(
sascha@422: Graphics2D g2,
sascha@422: Rectangle2D plotArea,
sascha@422: AxisSpace space
sascha@422: ) {
sascha@422: if (space == null)
sascha@422: space = new AxisSpace();
sascha@422:
sascha@422: for (int i = 0; i < domainAxes.size(); i++) {
sascha@422: Axis axis = (Axis) domainAxes.get(i);
sascha@422:
sascha@422: if (axis != null) {
sascha@422: RectangleEdge edge = getDomainAxisEdge(i);
sascha@422: space = axis.reserveSpace(g2, this, plotArea, edge, space);
sascha@422: }
sascha@422: }
sascha@422:
sascha@422: return space;
sascha@422: }
sascha@422:
sascha@422:
sascha@422: private AxisSpace calculateRangeAxisSpace(
sascha@422: Graphics2D g2,
sascha@422: Rectangle2D plotArea,
sascha@422: AxisSpace space
sascha@422: ) {
sascha@422: if (space == null)
sascha@422: space = new AxisSpace();
sascha@422:
sascha@422: for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422: Axis axis = (Axis) rangeAxes.get(i);
sascha@422:
sascha@422: if (axis != null) {
sascha@422: RectangleEdge edge = getRangeAxisEdge(i);
sascha@422: space = axis.reserveSpace(g2, this, plotArea, edge, space);
sascha@422: }
sascha@422: }
sascha@422:
sascha@422: return space;
sascha@422: }
sascha@422:
ingo@795:
sascha@450: public RectangleEdge getDomainAxisEdge() {
sascha@422: return Plot.resolveDomainAxisLocation(
sascha@422: getDomainAxisLocation(), orientation
sascha@422: );
sascha@422: }
sascha@422:
sascha@422:
sascha@450: public RectangleEdge getDomainAxisEdge(int idx) {
sascha@422: AxisLocation location = getDomainAxisLocation(idx);
sascha@422: RectangleEdge result = Plot.resolveDomainAxisLocation(
sascha@422: location, orientation
sascha@422: );
sascha@422:
sascha@422: if (result == null)
sascha@422: result = RectangleEdge.opposite(getDomainAxisEdge());
sascha@422:
sascha@422: return result;
sascha@422: }
sascha@422:
sascha@422:
sascha@450: public RectangleEdge getRangeAxisEdge() {
sascha@422: return Plot.resolveRangeAxisLocation(
sascha@422: getRangeAxisLocation(), orientation
sascha@422: );
sascha@422: }
sascha@422:
sascha@422:
sascha@450: public RectangleEdge getRangeAxisEdge(int idx) {
sascha@422: AxisLocation location = getRangeAxisLocation(idx);
sascha@422: RectangleEdge result = Plot.resolveRangeAxisLocation(
sascha@422: location,
sascha@422: orientation
sascha@422: );
sascha@422:
sascha@422: if (result == null)
sascha@422: result = RectangleEdge.opposite(getRangeAxisEdge());
sascha@422:
sascha@422: return result;
sascha@422: }
sascha@422:
sascha@422:
sascha@422: public AxisLocation getDomainAxisLocation() {
sascha@422: return (AxisLocation) domainAxisLocation.get(0);
sascha@422: }
sascha@422:
sascha@422:
sascha@422: public AxisLocation getDomainAxisLocation(int idx) {
sascha@422: if (idx < domainAxisLocation.size())
sascha@422: return (AxisLocation) domainAxisLocation.get(idx);
sascha@422:
sascha@422: return null;
sascha@422: }
sascha@422:
sascha@422:
sascha@422: public AxisLocation getRangeAxisLocation() {
sascha@422: return (AxisLocation) rangeAxisLocation.get(0);
sascha@422: }
sascha@422:
sascha@422:
sascha@422: public AxisLocation getRangeAxisLocation(int idx) {
sascha@422: if (idx < rangeAxisLocation.size())
sascha@422: return (AxisLocation) rangeAxisLocation.get(idx);
sascha@422:
sascha@422: return null;
sascha@422: }
sascha@422:
sascha@422:
ingo@795: /**
ingo@795: * @return true, if dataset is null or if it does not contain any
ingo@795: * PolygonSeries, otherwise false.
ingo@795: */
sascha@422: private boolean isEmptyOrNull(PolygonDataset dataset) {
sascha@422: if (dataset != null) {
sascha@422: int seriesCount = dataset.getSeriesCount();
sascha@422: for (int s = 0; s < seriesCount; s++) {
sascha@422: PolygonSeries series = dataset.getSeries(s);
sascha@422: if (series.getItemCount() > 0) {
sascha@422: return false;
sascha@422: }
sascha@422: }
sascha@422: }
sascha@422: return true;
sascha@422: }
sascha@422: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :