001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2009, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ------------------------
028 * IntervalBarRenderer.java
029 * ------------------------
030 * (C) Copyright 2002-2009, 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);
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 *
063 */
064
065package org.jfree.chart.renderer.category;
066
067import java.awt.Graphics2D;
068import java.awt.geom.Rectangle2D;
069
070import org.jfree.chart.axis.CategoryAxis;
071import org.jfree.chart.axis.ValueAxis;
072import org.jfree.chart.entity.EntityCollection;
073import org.jfree.chart.labels.CategoryItemLabelGenerator;
074import org.jfree.chart.plot.CategoryPlot;
075import org.jfree.chart.plot.PlotOrientation;
076import org.jfree.data.category.CategoryDataset;
077import org.jfree.data.category.IntervalCategoryDataset;
078import org.jfree.ui.RectangleEdge;
079
080/**
081 * A renderer that handles the drawing of bars for a bar plot where
082 * each bar has a high and low value.  This renderer is for use with the
083 * {@link CategoryPlot} class.  The example shown here is generated by the
084 * <code>IntervalBarChartDemo1.java</code> program included in the JFreeChart
085 * Demo Collection:
086 * <br><br>
087 * <img src="../../../../../images/IntervalBarRendererSample.png"
088 * alt="IntervalBarRendererSample.png" />
089 */
090public class IntervalBarRenderer extends BarRenderer {
091
092    /** For serialization. */
093    private static final long serialVersionUID = -5068857361615528725L;
094
095    /**
096     * Constructs a new renderer.
097     */
098    public IntervalBarRenderer() {
099        super();
100    }
101
102    /**
103     * Draws the bar for a single (series, category) data item.
104     *
105     * @param g2  the graphics device.
106     * @param state  the renderer state.
107     * @param dataArea  the data area.
108     * @param plot  the plot.
109     * @param domainAxis  the domain axis.
110     * @param rangeAxis  the range axis.
111     * @param dataset  the dataset.
112     * @param row  the row index (zero-based).
113     * @param column  the column index (zero-based).
114     * @param pass  the pass index.
115     */
116    public void drawItem(Graphics2D g2,
117                         CategoryItemRendererState state,
118                         Rectangle2D dataArea,
119                         CategoryPlot plot,
120                         CategoryAxis domainAxis,
121                         ValueAxis rangeAxis,
122                         CategoryDataset dataset,
123                         int row,
124                         int column,
125                         int pass) {
126
127         if (dataset instanceof IntervalCategoryDataset) {
128             IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
129             drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
130                     d, row, column);
131         }
132         else {
133             super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
134                     dataset, row, column, pass);
135         }
136
137     }
138
139     /**
140      * Draws a single interval.
141      *
142      * @param g2  the graphics device.
143      * @param state  the renderer state.
144      * @param dataArea  the data plot area.
145      * @param plot  the plot.
146      * @param domainAxis  the domain axis.
147      * @param rangeAxis  the range axis.
148      * @param dataset  the data.
149      * @param row  the row index (zero-based).
150      * @param column  the column index (zero-based).
151      */
152     protected void drawInterval(Graphics2D g2,
153                                 CategoryItemRendererState state,
154                                 Rectangle2D dataArea,
155                                 CategoryPlot plot,
156                                 CategoryAxis domainAxis,
157                                 ValueAxis rangeAxis,
158                                 IntervalCategoryDataset dataset,
159                                 int row,
160                                 int column) {
161
162        int visibleRow = state.getVisibleSeriesIndex(row);
163        if (visibleRow < 0) {
164            return;
165        }
166        int seriesCount = state.getVisibleSeriesCount() >= 0
167                ? state.getVisibleSeriesCount() : getRowCount();
168
169        int categoryCount = getColumnCount();
170
171        PlotOrientation orientation = plot.getOrientation();
172
173        double rectX = 0.0;
174        double rectY = 0.0;
175
176        RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
177        RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
178
179        // Y0
180        Number value0 = dataset.getEndValue(row, column);
181        if (value0 == null) {
182            return;
183        }
184        double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
185                dataArea, rangeAxisLocation);
186
187        // Y1
188        Number value1 = dataset.getStartValue(row, column);
189        if (value1 == null) {
190            return;
191        }
192        double java2dValue1 = rangeAxis.valueToJava2D(
193                value1.doubleValue(), dataArea, rangeAxisLocation);
194
195        if (java2dValue1 < java2dValue0) {
196            double temp = java2dValue1;
197            java2dValue1 = java2dValue0;
198            java2dValue0 = temp;
199            Number tempNum = value1;
200            value1 = value0;
201            value0 = tempNum;
202        }
203
204        // BAR WIDTH
205        double rectWidth = state.getBarWidth();
206
207        // BAR HEIGHT
208        double rectHeight = Math.abs(java2dValue1 - java2dValue0);
209
210        RectangleEdge barBase = RectangleEdge.LEFT;
211        if (orientation == PlotOrientation.HORIZONTAL) {
212            // BAR Y
213            rectY = domainAxis.getCategoryStart(column, getColumnCount(),
214                    dataArea, domainAxisLocation);
215            if (seriesCount > 1) {
216                double seriesGap = dataArea.getHeight() * getItemMargin()
217                                   / (categoryCount * (seriesCount - 1));
218                rectY = rectY + visibleRow * (state.getBarWidth() + seriesGap);
219            }
220            else {
221                rectY = rectY + visibleRow * state.getBarWidth();
222            }
223
224            rectX = java2dValue0;
225
226            rectHeight = state.getBarWidth();
227            rectWidth = Math.abs(java2dValue1 - java2dValue0);
228            barBase = RectangleEdge.LEFT;
229        }
230        else if (orientation == PlotOrientation.VERTICAL) {
231            // BAR X
232            rectX = domainAxis.getCategoryStart(column, getColumnCount(),
233                    dataArea, domainAxisLocation);
234
235            if (seriesCount > 1) {
236                double seriesGap = dataArea.getWidth() * getItemMargin()
237                                   / (categoryCount * (seriesCount - 1));
238                rectX = rectX + visibleRow * (state.getBarWidth() + seriesGap);
239            }
240            else {
241                rectX = rectX + visibleRow * state.getBarWidth();
242            }
243
244            rectY = java2dValue0;
245            barBase = RectangleEdge.BOTTOM;
246        }
247        Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
248                rectHeight);
249        BarPainter painter = getBarPainter();
250        if (getShadowsVisible()) {
251            painter.paintBarShadow(g2, this, row, column, bar, barBase, false);
252        }
253        getBarPainter().paintBar(g2, this, row, column, bar, barBase);
254
255        CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
256                column);
257        if (generator != null && isItemLabelVisible(row, column)) {
258            drawItemLabel(g2, dataset, row, column, plot, generator, bar,
259                    false);
260        }
261
262        // add an item entity, if this information is being collected
263        EntityCollection entities = state.getEntityCollection();
264        if (entities != null) {
265            addItemEntity(entities, dataset, row, column, bar);
266        }
267
268    }
269
270    /**
271     * Tests this renderer for equality with an arbitrary object.
272     *
273     * @param obj  the object (<code>null</code> permitted).
274     *
275     * @return A boolean.
276     */
277    public boolean equals(Object obj) {
278        if (obj == this) {
279            return true;
280        }
281        if (!(obj instanceof IntervalBarRenderer)) {
282            return false;
283        }
284        // there are no fields to check
285        return super.equals(obj);
286    }
287
288}