001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2007, 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-2007, by Jeremy Bowman.
031     *
032     * Original Author:  Jeremy Bowman;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *                   Christian W. Zuckschwerdt;
035     *
036     * $Id: IntervalBarRenderer.java,v 1.6.2.4 2007/06/01 15:12:15 mungady Exp $
037     *
038     * Changes
039     * -------
040     * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
041     * 11-May-2002 : Use CategoryPlot.getLabelsVisible() (JB);
042     * 29-May-2002 : Added constructors (DG);
043     * 26-Jun-2002 : Added axis to initialise method (DG);
044     * 20-Sep-2002 : Added basic support for chart entities (DG);
045     * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 
046     *               CategoryToolTipGenerator interface (DG);
047     * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
048     * 25-Mar-2003 : Implemented Serializable (DG);
049     * 30-Jul-2003 : Modified entity constructor (CZ);
050     * 19-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
051     * 08-Sep-2003 : Added checks for null values (DG);
052     * 07-Oct-2003 : Added renderer state (DG);
053     * 21-Oct-2003 : Bar width moved into renderer state (DG);
054     * 23-Dec-2003 : Removed the deprecated MultiIntervalCategoryDataset 
055     *               interface (DG);
056     * 05-Nov-2004 : Modified drawItem() signature (DG);
057     * 20-Apr-2005 : Renamed CategoryLabelGenerator 
058     *               --> CategoryItemLabelGenerator (DG);
059     * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
060     * 
061     */
062    
063    package org.jfree.chart.renderer.category;
064    
065    import java.awt.Graphics2D;
066    import java.awt.Paint;
067    import java.awt.Stroke;
068    import java.awt.geom.Rectangle2D;
069    import java.io.Serializable;
070    
071    import org.jfree.chart.axis.CategoryAxis;
072    import org.jfree.chart.axis.ValueAxis;
073    import org.jfree.chart.entity.CategoryItemEntity;
074    import org.jfree.chart.entity.EntityCollection;
075    import org.jfree.chart.labels.CategoryItemLabelGenerator;
076    import org.jfree.chart.labels.CategoryToolTipGenerator;
077    import org.jfree.chart.plot.CategoryPlot;
078    import org.jfree.chart.plot.PlotOrientation;
079    import org.jfree.data.category.CategoryDataset;
080    import org.jfree.data.category.IntervalCategoryDataset;
081    import org.jfree.ui.RectangleEdge;
082    import org.jfree.util.PublicCloneable;
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.
087     * <p>
088     * For use with the {@link CategoryPlot} class.
089     */
090    public class IntervalBarRenderer extends BarRenderer
091                                     implements CategoryItemRenderer, 
092                                                Cloneable, 
093                                                PublicCloneable, 
094                                                Serializable {
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         * Draws the bar for a single (series, category) data item.
108         *
109         * @param g2  the graphics device.
110         * @param state  the renderer state.
111         * @param dataArea  the data area.
112         * @param plot  the plot.
113         * @param domainAxis  the domain axis.
114         * @param rangeAxis  the range axis.
115         * @param dataset  the dataset.
116         * @param row  the row index (zero-based).
117         * @param column  the column index (zero-based).
118         * @param pass  the pass index.
119         */
120        public void drawItem(Graphics2D g2,
121                             CategoryItemRendererState state,
122                             Rectangle2D dataArea,
123                             CategoryPlot plot,
124                             CategoryAxis domainAxis,
125                             ValueAxis rangeAxis,
126                             CategoryDataset dataset,
127                             int row,
128                             int column,
129                             int pass) {
130    
131             if (dataset instanceof IntervalCategoryDataset) {
132                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
133                 drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis, 
134                         d, row, column);
135             }
136             else {
137                 super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis, 
138                         dataset, row, column, pass);
139             } 
140             
141         }
142                              
143         /**
144          * Draws a single interval.
145          *
146          * @param g2  the graphics device.
147          * @param state  the renderer state.
148          * @param dataArea  the data plot area.
149          * @param plot  the plot.
150          * @param domainAxis  the domain axis.
151          * @param rangeAxis  the range axis.
152          * @param dataset  the data.
153          * @param row  the row index (zero-based).
154          * @param column  the column index (zero-based).
155          */
156         protected void drawInterval(Graphics2D g2,
157                                     CategoryItemRendererState state,
158                                     Rectangle2D dataArea,
159                                     CategoryPlot plot,
160                                     CategoryAxis domainAxis,
161                                     ValueAxis rangeAxis,
162                                     IntervalCategoryDataset dataset,
163                                     int row,
164                                     int column) {
165    
166            int seriesCount = getRowCount();
167            int categoryCount = getColumnCount();
168    
169            PlotOrientation orientation = plot.getOrientation();
170            
171            double rectX = 0.0;
172            double rectY = 0.0;
173    
174            RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
175            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
176            
177            // Y0
178            Number value0 = dataset.getEndValue(row, column);
179            if (value0 == null) {
180                return;
181            }
182            double java2dValue0 = rangeAxis.valueToJava2D(
183                value0.doubleValue(), dataArea, rangeAxisLocation
184            );
185    
186            // Y1
187            Number value1 = dataset.getStartValue(row, column);
188            if (value1 == null) {
189                return;
190            }
191            double java2dValue1 = rangeAxis.valueToJava2D(
192                    value1.doubleValue(), dataArea, rangeAxisLocation);
193    
194            if (java2dValue1 < java2dValue0) {
195                double temp = java2dValue1;
196                java2dValue1 = java2dValue0;
197                java2dValue0 = temp;
198                Number tempNum = value1;
199                value1 = value0;
200                value0 = tempNum;
201            }
202    
203            // BAR WIDTH
204            double rectWidth = state.getBarWidth();
205    
206            // BAR HEIGHT
207            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
208    
209            if (orientation == PlotOrientation.HORIZONTAL) {
210                // BAR Y
211                rectY = domainAxis.getCategoryStart(
212                    column, getColumnCount(), dataArea, domainAxisLocation
213                );
214                if (seriesCount > 1) {
215                    double seriesGap = dataArea.getHeight() * getItemMargin()
216                                       / (categoryCount * (seriesCount - 1));
217                    rectY = rectY + row * (state.getBarWidth() + seriesGap);
218                }
219                else {
220                    rectY = rectY + row * state.getBarWidth();
221                }
222                
223                rectX = java2dValue0;
224    
225                rectHeight = state.getBarWidth();
226                rectWidth = Math.abs(java2dValue1 - java2dValue0);
227    
228            }
229            else if (orientation == PlotOrientation.VERTICAL) {
230                // BAR X
231                rectX = domainAxis.getCategoryStart(column, getColumnCount(), 
232                        dataArea, domainAxisLocation);
233    
234                if (seriesCount > 1) {
235                    double seriesGap = dataArea.getWidth() * getItemMargin()
236                                       / (categoryCount * (seriesCount - 1));
237                    rectX = rectX + row * (state.getBarWidth() + seriesGap);
238                }
239                else {
240                    rectX = rectX + row * state.getBarWidth();
241                }
242    
243                rectY = java2dValue0;
244    
245            }
246            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth, 
247                    rectHeight);
248            Paint seriesPaint = getItemPaint(row, column);
249            g2.setPaint(seriesPaint);
250            g2.fill(bar);
251            
252            // draw the outline...
253            if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
254                Stroke stroke = getItemOutlineStroke(row, column);
255                Paint paint = getItemOutlinePaint(row, column);
256                if (stroke != null && paint != null) {
257                    g2.setStroke(stroke);
258                    g2.setPaint(paint);
259                    g2.draw(bar);
260                }
261            }
262            
263            CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
264                    column);
265            if (generator != null && isItemLabelVisible(row, column)) {
266                drawItemLabel(g2, dataset, row, column, plot, generator, bar, 
267                        false);
268            }        
269    
270            // collect entity and tool tip information...
271            if (state.getInfo() != null) {
272                EntityCollection entities = state.getEntityCollection();
273                if (entities != null) {
274                    String tip = null;
275                    CategoryToolTipGenerator tipster 
276                            = getToolTipGenerator(row, column);
277                    if (tipster != null) {
278                        tip = tipster.generateToolTip(dataset, row, column);
279                    }
280                    String url = null;
281                    if (getItemURLGenerator(row, column) != null) {
282                        url = getItemURLGenerator(row, column).generateURL(
283                                dataset, row, column);
284                    }
285                    CategoryItemEntity entity = new CategoryItemEntity(bar, tip, 
286                            url, dataset, dataset.getRowKey(row), 
287                            dataset.getColumnKey(column));
288                    entities.add(entity);
289                }
290            }
291    
292        }
293    
294    }