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     *
059     */
060    
061    package org.jfree.chart.renderer.category;
062    
063    import java.awt.Graphics2D;
064    import java.awt.Paint;
065    import java.awt.Stroke;
066    import java.awt.geom.Rectangle2D;
067    import java.io.Serializable;
068    
069    import org.jfree.chart.axis.CategoryAxis;
070    import org.jfree.chart.axis.ValueAxis;
071    import org.jfree.chart.entity.EntityCollection;
072    import org.jfree.chart.labels.CategoryItemLabelGenerator;
073    import org.jfree.chart.plot.CategoryPlot;
074    import org.jfree.chart.plot.PlotOrientation;
075    import org.jfree.data.category.CategoryDataset;
076    import org.jfree.data.category.IntervalCategoryDataset;
077    import org.jfree.ui.RectangleEdge;
078    import org.jfree.util.PublicCloneable;
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.
083     * <p>
084     * For use with the {@link CategoryPlot} class.
085     */
086    public class IntervalBarRenderer extends BarRenderer
087            implements CategoryItemRenderer, Cloneable, PublicCloneable,
088                       Serializable {
089    
090        /** For serialization. */
091        private static final long serialVersionUID = -5068857361615528725L;
092    
093        /**
094         * Constructs a new renderer.
095         */
096        public IntervalBarRenderer() {
097            super();
098        }
099    
100        /**
101         * Draws the bar for a single (series, category) data item.
102         *
103         * @param g2  the graphics device.
104         * @param state  the renderer state.
105         * @param dataArea  the data area.
106         * @param plot  the plot.
107         * @param domainAxis  the domain axis.
108         * @param rangeAxis  the range axis.
109         * @param dataset  the dataset.
110         * @param row  the row index (zero-based).
111         * @param column  the column index (zero-based).
112         * @param pass  the pass index.
113         */
114        public void drawItem(Graphics2D g2,
115                             CategoryItemRendererState state,
116                             Rectangle2D dataArea,
117                             CategoryPlot plot,
118                             CategoryAxis domainAxis,
119                             ValueAxis rangeAxis,
120                             CategoryDataset dataset,
121                             int row,
122                             int column,
123                             int pass) {
124    
125             if (dataset instanceof IntervalCategoryDataset) {
126                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
127                 drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
128                         d, row, column);
129             }
130             else {
131                 super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
132                         dataset, row, column, pass);
133             }
134    
135         }
136    
137         /**
138          * Draws a single interval.
139          *
140          * @param g2  the graphics device.
141          * @param state  the renderer state.
142          * @param dataArea  the data plot area.
143          * @param plot  the plot.
144          * @param domainAxis  the domain axis.
145          * @param rangeAxis  the range axis.
146          * @param dataset  the data.
147          * @param row  the row index (zero-based).
148          * @param column  the column index (zero-based).
149          */
150         protected void drawInterval(Graphics2D g2,
151                                     CategoryItemRendererState state,
152                                     Rectangle2D dataArea,
153                                     CategoryPlot plot,
154                                     CategoryAxis domainAxis,
155                                     ValueAxis rangeAxis,
156                                     IntervalCategoryDataset dataset,
157                                     int row,
158                                     int column) {
159    
160            int seriesCount = getRowCount();
161            int categoryCount = getColumnCount();
162    
163            PlotOrientation orientation = plot.getOrientation();
164    
165            double rectX = 0.0;
166            double rectY = 0.0;
167    
168            RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
169            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
170    
171            // Y0
172            Number value0 = dataset.getEndValue(row, column);
173            if (value0 == null) {
174                return;
175            }
176            double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
177                            dataArea, rangeAxisLocation);
178    
179            // Y1
180            Number value1 = dataset.getStartValue(row, column);
181            if (value1 == null) {
182                return;
183            }
184            double java2dValue1 = rangeAxis.valueToJava2D(
185                    value1.doubleValue(), dataArea, rangeAxisLocation);
186    
187            if (java2dValue1 < java2dValue0) {
188                double temp = java2dValue1;
189                java2dValue1 = java2dValue0;
190                java2dValue0 = temp;
191                Number tempNum = value1;
192                value1 = value0;
193                value0 = tempNum;
194            }
195    
196            // BAR WIDTH
197            double rectWidth = state.getBarWidth();
198    
199            // BAR HEIGHT
200            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
201    
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    
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    
237            }
238            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
239                    rectHeight);
240            Paint seriesPaint = getItemPaint(row, column);
241            g2.setPaint(seriesPaint);
242            g2.fill(bar);
243    
244            // draw the outline...
245            if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
246                Stroke stroke = getItemOutlineStroke(row, column);
247                Paint paint = getItemOutlinePaint(row, column);
248                if (stroke != null && paint != null) {
249                    g2.setStroke(stroke);
250                    g2.setPaint(paint);
251                    g2.draw(bar);
252                }
253            }
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    }