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.3 2007/02/02 15:52:07 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(
232                    column, getColumnCount(), dataArea, domainAxisLocation
233                );
234    
235                if (seriesCount > 1) {
236                    double seriesGap = dataArea.getWidth() * getItemMargin()
237                                       / (categoryCount * (seriesCount - 1));
238                    rectX = rectX + row * (state.getBarWidth() + seriesGap);
239                }
240                else {
241                    rectX = rectX + row * state.getBarWidth();
242                }
243    
244                rectY = java2dValue0;
245    
246            }
247            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth, 
248                    rectHeight);
249            Paint seriesPaint = getItemPaint(row, column);
250            g2.setPaint(seriesPaint);
251            g2.fill(bar);
252            
253            // draw the outline...
254            if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
255                Stroke stroke = getItemOutlineStroke(row, column);
256                Paint paint = getItemOutlinePaint(row, column);
257                if (stroke != null && paint != null) {
258                    g2.setStroke(stroke);
259                    g2.setPaint(paint);
260                    g2.draw(bar);
261                }
262            }
263            
264            CategoryItemLabelGenerator generator 
265                = getItemLabelGenerator(row, column);
266            if (generator != null && isItemLabelVisible(row, column)) {
267                drawItemLabel(g2, dataset, row, column, plot, generator, bar, 
268                        false);
269            }        
270    
271            // collect entity and tool tip information...
272            if (state.getInfo() != null) {
273                EntityCollection entities = state.getEntityCollection();
274                if (entities != null) {
275                    String tip = null;
276                    CategoryToolTipGenerator tipster 
277                            = getToolTipGenerator(row, column);
278                    if (tipster != null) {
279                        tip = tipster.generateToolTip(dataset, row, column);
280                    }
281                    String url = null;
282                    if (getItemURLGenerator(row, column) != null) {
283                        url = getItemURLGenerator(row, column).generateURL(
284                                dataset, row, column);
285                    }
286                    CategoryItemEntity entity = new CategoryItemEntity(bar, tip, 
287                            url, dataset, row, dataset.getColumnKey(column), 
288                            column);
289                    entities.add(entity);
290                }
291            }
292    
293        }
294    
295    }