001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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-2008, by Jeremy Bowman.
031     *
032     * Original Author:  Jeremy Bowman;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *                   Christian W. Zuckschwerdt;
035     *
036     * Changes
037     * -------
038     * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
039     * 11-May-2002 : Use CategoryPlot.getLabelsVisible() (JB);
040     * 29-May-2002 : Added constructors (DG);
041     * 26-Jun-2002 : Added axis to initialise method (DG);
042     * 20-Sep-2002 : Added basic support for chart entities (DG);
043     * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
044     *               CategoryToolTipGenerator interface (DG);
045     * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
046     * 25-Mar-2003 : Implemented Serializable (DG);
047     * 30-Jul-2003 : Modified entity constructor (CZ);
048     * 19-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
049     * 08-Sep-2003 : Added checks for null values (DG);
050     * 07-Oct-2003 : Added renderer state (DG);
051     * 21-Oct-2003 : Bar width moved into renderer state (DG);
052     * 23-Dec-2003 : Removed the deprecated MultiIntervalCategoryDataset
053     *               interface (DG);
054     * 05-Nov-2004 : Modified drawItem() signature (DG);
055     * 20-Apr-2005 : Renamed CategoryLabelGenerator
056     *               --> CategoryItemLabelGenerator (DG);
057     * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
058     * 24-Jun-2008 : Added new barPainter mechanism (DG);
059     *
060     */
061    
062    package org.jfree.chart.renderer.category;
063    
064    import java.awt.Graphics2D;
065    import java.awt.geom.Rectangle2D;
066    import java.io.Serializable;
067    
068    import org.jfree.chart.axis.CategoryAxis;
069    import org.jfree.chart.axis.ValueAxis;
070    import org.jfree.chart.entity.EntityCollection;
071    import org.jfree.chart.labels.CategoryItemLabelGenerator;
072    import org.jfree.chart.plot.CategoryPlot;
073    import org.jfree.chart.plot.PlotOrientation;
074    import org.jfree.data.category.CategoryDataset;
075    import org.jfree.data.category.IntervalCategoryDataset;
076    import org.jfree.ui.RectangleEdge;
077    import org.jfree.util.PublicCloneable;
078    
079    /**
080     * A renderer that handles the drawing of bars for a bar plot where
081     * each bar has a high and low value.
082     * <p>
083     * For use with the {@link CategoryPlot} class.
084     */
085    public class IntervalBarRenderer extends BarRenderer
086            implements CategoryItemRenderer, Cloneable, PublicCloneable,
087                       Serializable {
088    
089        /** For serialization. */
090        private static final long serialVersionUID = -5068857361615528725L;
091    
092        /**
093         * Constructs a new renderer.
094         */
095        public IntervalBarRenderer() {
096            super();
097        }
098    
099        /**
100         * Draws the bar for a single (series, category) data item.
101         *
102         * @param g2  the graphics device.
103         * @param state  the renderer state.
104         * @param dataArea  the data area.
105         * @param plot  the plot.
106         * @param domainAxis  the domain axis.
107         * @param rangeAxis  the range axis.
108         * @param dataset  the dataset.
109         * @param row  the row index (zero-based).
110         * @param column  the column index (zero-based).
111         * @param pass  the pass index.
112         */
113        public void drawItem(Graphics2D g2,
114                             CategoryItemRendererState state,
115                             Rectangle2D dataArea,
116                             CategoryPlot plot,
117                             CategoryAxis domainAxis,
118                             ValueAxis rangeAxis,
119                             CategoryDataset dataset,
120                             int row,
121                             int column,
122                             int pass) {
123    
124             if (dataset instanceof IntervalCategoryDataset) {
125                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
126                 drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
127                         d, row, column);
128             }
129             else {
130                 super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
131                         dataset, row, column, pass);
132             }
133    
134         }
135    
136         /**
137          * Draws a single interval.
138          *
139          * @param g2  the graphics device.
140          * @param state  the renderer state.
141          * @param dataArea  the data plot area.
142          * @param plot  the plot.
143          * @param domainAxis  the domain axis.
144          * @param rangeAxis  the range axis.
145          * @param dataset  the data.
146          * @param row  the row index (zero-based).
147          * @param column  the column index (zero-based).
148          */
149         protected void drawInterval(Graphics2D g2,
150                                     CategoryItemRendererState state,
151                                     Rectangle2D dataArea,
152                                     CategoryPlot plot,
153                                     CategoryAxis domainAxis,
154                                     ValueAxis rangeAxis,
155                                     IntervalCategoryDataset dataset,
156                                     int row,
157                                     int column) {
158    
159            int seriesCount = getRowCount();
160            int categoryCount = getColumnCount();
161    
162            PlotOrientation orientation = plot.getOrientation();
163    
164            double rectX = 0.0;
165            double rectY = 0.0;
166    
167            RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
168            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
169    
170            // Y0
171            Number value0 = dataset.getEndValue(row, column);
172            if (value0 == null) {
173                return;
174            }
175            double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
176                    dataArea, rangeAxisLocation);
177    
178            // Y1
179            Number value1 = dataset.getStartValue(row, column);
180            if (value1 == null) {
181                return;
182            }
183            double java2dValue1 = rangeAxis.valueToJava2D(
184                    value1.doubleValue(), dataArea, rangeAxisLocation);
185    
186            if (java2dValue1 < java2dValue0) {
187                double temp = java2dValue1;
188                java2dValue1 = java2dValue0;
189                java2dValue0 = temp;
190                Number tempNum = value1;
191                value1 = value0;
192                value0 = tempNum;
193            }
194    
195            // BAR WIDTH
196            double rectWidth = state.getBarWidth();
197    
198            // BAR HEIGHT
199            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
200    
201            RectangleEdge barBase = RectangleEdge.LEFT;
202            if (orientation == PlotOrientation.HORIZONTAL) {
203                // BAR Y
204                rectY = domainAxis.getCategoryStart(column, getColumnCount(),
205                        dataArea, domainAxisLocation);
206                if (seriesCount > 1) {
207                    double seriesGap = dataArea.getHeight() * getItemMargin()
208                                       / (categoryCount * (seriesCount - 1));
209                    rectY = rectY + row * (state.getBarWidth() + seriesGap);
210                }
211                else {
212                    rectY = rectY + row * state.getBarWidth();
213                }
214    
215                rectX = java2dValue0;
216    
217                rectHeight = state.getBarWidth();
218                rectWidth = Math.abs(java2dValue1 - java2dValue0);
219                barBase = RectangleEdge.LEFT;
220            }
221            else if (orientation == PlotOrientation.VERTICAL) {
222                // BAR X
223                rectX = domainAxis.getCategoryStart(column, getColumnCount(),
224                        dataArea, domainAxisLocation);
225    
226                if (seriesCount > 1) {
227                    double seriesGap = dataArea.getWidth() * getItemMargin()
228                                       / (categoryCount * (seriesCount - 1));
229                    rectX = rectX + row * (state.getBarWidth() + seriesGap);
230                }
231                else {
232                    rectX = rectX + row * state.getBarWidth();
233                }
234    
235                rectY = java2dValue0;
236                barBase = RectangleEdge.BOTTOM;
237            }
238            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
239                    rectHeight);
240            BarPainter painter = getBarPainter();
241            if (getShadowsVisible()) {
242                painter.paintBarShadow(g2, this, row, column, bar, barBase, false);
243            }
244            getBarPainter().paintBar(g2, this, row, column, bar, barBase);
245    
246            CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
247                    column);
248            if (generator != null && isItemLabelVisible(row, column)) {
249                drawItemLabel(g2, dataset, row, column, plot, generator, bar,
250                        false);
251            }
252    
253            // add an item entity, if this information is being collected
254            EntityCollection entities = state.getEntityCollection();
255            if (entities != null) {
256                addItemEntity(entities, dataset, row, column, bar);
257            }
258    
259        }
260    
261    }