001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * ------------------------
028 * IntervalBarRenderer.java
029 * ------------------------
030 * (C) Copyright 2002-2011, by Jeremy Bowman.
031 *
032 * Original Author:  Jeremy Bowman;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *                   Christian W. Zuckschwerdt;
035 *                   Peter Kolb (patch 2497611, 2791407);
036 *
037 * Changes
038 * -------
039 * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
040 * 11-May-2002 : Use CategoryPlot.getLabelsVisible() (JB);
041 * 29-May-2002 : Added constructors (DG);
042 * 26-Jun-2002 : Added axis to initialise method (DG);
043 * 20-Sep-2002 : Added basic support for chart entities (DG);
044 * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
045 *               CategoryToolTipGenerator interface (DG);
046 * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
047 * 25-Mar-2003 : Implemented Serializable (DG);
048 * 30-Jul-2003 : Modified entity constructor (CZ);
049 * 19-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
050 * 08-Sep-2003 : Added checks for null values (DG);
051 * 07-Oct-2003 : Added renderer state (DG);
052 * 21-Oct-2003 : Bar width moved into renderer state (DG);
053 * 23-Dec-2003 : Removed the deprecated MultiIntervalCategoryDataset
054 *               interface (DG);
055 * 05-Nov-2004 : Modified drawItem() signature (DG);
056 * 20-Apr-2005 : Renamed CategoryLabelGenerator
057 *               --> CategoryItemLabelGenerator (DG);
058 * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
059 * 24-Jun-2008 : Added new barPainter mechanism (DG);
060 * 07-Oct-2008 : Override equals() method to fix minor bug (DG);
061 * 14-Jan-2009 : Added support for seriesVisible flags (PK);
062 * 16-May-2009 : The findRangeBounds() method needs to include the dataset
063 *               interval (DG);
064 * 19-May-2009 : Fixed FindBugs warnings, patch by Michal Wozniak (DG);
065 * 30-Oct-2011 : Fixed alignment when setMaximumBarWidth is applied (DG);
066 */
067
068package org.jfree.chart.renderer.category;
069
070import java.awt.Graphics2D;
071import java.awt.geom.Rectangle2D;
072
073import org.jfree.chart.axis.CategoryAxis;
074import org.jfree.chart.axis.ValueAxis;
075import org.jfree.chart.entity.EntityCollection;
076import org.jfree.chart.labels.CategoryItemLabelGenerator;
077import org.jfree.chart.plot.CategoryPlot;
078import org.jfree.chart.plot.PlotOrientation;
079import org.jfree.data.Range;
080import org.jfree.data.category.CategoryDataset;
081import org.jfree.data.category.IntervalCategoryDataset;
082import org.jfree.ui.RectangleEdge;
083
084/**
085 * A renderer that handles the drawing of bars for a bar plot where
086 * each bar has a high and low value.  This renderer is for use with the
087 * {@link CategoryPlot} class.  The example shown here is generated by the
088 * <code>IntervalBarChartDemo1.java</code> program included in the JFreeChart
089 * Demo Collection:
090 * <br><br>
091 * <img src="../../../../../images/IntervalBarRendererSample.png"
092 * alt="IntervalBarRendererSample.png" />
093 */
094public class IntervalBarRenderer extends BarRenderer {
095
096    /** For serialization. */
097    private static final long serialVersionUID = -5068857361615528725L;
098
099    /**
100     * Constructs a new renderer.
101     */
102    public IntervalBarRenderer() {
103        super();
104    }
105
106    /**
107     * Returns the range of values from the specified dataset.  For this
108     * renderer, this is equivalent to calling
109     * <code>findRangeBounds(dataset, true)</code>.
110     *
111     * @param dataset  the dataset (<code>null</code> permitted).
112     *
113     * @return The range (or <code>null</code> if the dataset is
114     *         <code>null</code> or empty).
115     */
116    public Range findRangeBounds(CategoryDataset dataset) {
117        return findRangeBounds(dataset, true);
118    }
119
120    /**
121     * Draws the bar for a single (series, category) data item.
122     *
123     * @param g2  the graphics device.
124     * @param state  the renderer state.
125     * @param dataArea  the data area.
126     * @param plot  the plot.
127     * @param domainAxis  the domain axis.
128     * @param rangeAxis  the range axis.
129     * @param dataset  the dataset.
130     * @param row  the row index (zero-based).
131     * @param column  the column index (zero-based).
132     * @param pass  the pass index.
133     */
134    public void drawItem(Graphics2D g2,
135                         CategoryItemRendererState state,
136                         Rectangle2D dataArea,
137                         CategoryPlot plot,
138                         CategoryAxis domainAxis,
139                         ValueAxis rangeAxis,
140                         CategoryDataset dataset,
141                         int row,
142                         int column,
143                         int pass) {
144
145         if (dataset instanceof IntervalCategoryDataset) {
146             IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
147             drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
148                     d, row, column);
149         }
150         else {
151             super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
152                     dataset, row, column, pass);
153         }
154
155     }
156
157     /**
158      * Draws a single interval.
159      *
160      * @param g2  the graphics device.
161      * @param state  the renderer state.
162      * @param dataArea  the data plot area.
163      * @param plot  the plot.
164      * @param domainAxis  the domain axis.
165      * @param rangeAxis  the range axis.
166      * @param dataset  the data.
167      * @param row  the row index (zero-based).
168      * @param column  the column index (zero-based).
169      */
170     protected void drawInterval(Graphics2D g2,
171                                 CategoryItemRendererState state,
172                                 Rectangle2D dataArea,
173                                 CategoryPlot plot,
174                                 CategoryAxis domainAxis,
175                                 ValueAxis rangeAxis,
176                                 IntervalCategoryDataset dataset,
177                                 int row,
178                                 int column) {
179
180        int visibleRow = state.getVisibleSeriesIndex(row);
181        if (visibleRow < 0) {
182            return;
183        }
184
185        PlotOrientation orientation = plot.getOrientation();
186        double rectX = 0.0;
187        double rectY = 0.0;
188
189        RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
190
191        // Y0
192        Number value0 = dataset.getEndValue(row, column);
193        if (value0 == null) {
194            return;
195        }
196        double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
197                dataArea, rangeAxisLocation);
198
199        // Y1
200        Number value1 = dataset.getStartValue(row, column);
201        if (value1 == null) {
202            return;
203        }
204        double java2dValue1 = rangeAxis.valueToJava2D(
205                value1.doubleValue(), dataArea, rangeAxisLocation);
206
207        if (java2dValue1 < java2dValue0) {
208            double temp = java2dValue1;
209            java2dValue1 = java2dValue0;
210            java2dValue0 = temp;
211        }
212
213        // BAR WIDTH
214        double rectWidth = state.getBarWidth();
215
216        // BAR HEIGHT
217        double rectHeight = Math.abs(java2dValue1 - java2dValue0);
218
219        RectangleEdge barBase = RectangleEdge.LEFT;
220        if (orientation == PlotOrientation.HORIZONTAL) {
221            // BAR Y
222            rectX = java2dValue0;
223            rectY = calculateBarW0(getPlot(), orientation, dataArea, 
224                    domainAxis, state, visibleRow, column);
225            rectHeight = state.getBarWidth();
226            rectWidth = Math.abs(java2dValue1 - java2dValue0);
227            barBase = RectangleEdge.LEFT;
228        }
229        else if (orientation == PlotOrientation.VERTICAL) {
230            // BAR X
231            rectX = calculateBarW0(getPlot(), orientation, dataArea, 
232                    domainAxis, state, visibleRow, column);
233            rectY = java2dValue0;
234            barBase = RectangleEdge.BOTTOM;
235        }
236        Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
237                rectHeight);
238        BarPainter painter = getBarPainter();
239        if (getShadowsVisible()) {
240            painter.paintBarShadow(g2, this, row, column, bar, barBase, false);
241        }
242        getBarPainter().paintBar(g2, this, row, column, bar, barBase);
243
244        CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
245                column);
246        if (generator != null && isItemLabelVisible(row, column)) {
247            drawItemLabel(g2, dataset, row, column, plot, generator, bar,
248                    false);
249        }
250
251        // add an item entity, if this information is being collected
252        EntityCollection entities = state.getEntityCollection();
253        if (entities != null) {
254            addItemEntity(entities, dataset, row, column, bar);
255        }
256
257    }
258
259    /**
260     * Tests this renderer for equality with an arbitrary object.
261     *
262     * @param obj  the object (<code>null</code> permitted).
263     *
264     * @return A boolean.
265     */
266    public boolean equals(Object obj) {
267        if (obj == this) {
268            return true;
269        }
270        if (!(obj instanceof IntervalBarRenderer)) {
271            return false;
272        }
273        // there are no fields to check
274        return super.equals(obj);
275    }
276
277}