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 * 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
061package org.jfree.chart.renderer.category;
062
063import java.awt.Graphics2D;
064import java.awt.Paint;
065import java.awt.Stroke;
066import java.awt.geom.Rectangle2D;
067import java.io.Serializable;
068
069import org.jfree.chart.axis.CategoryAxis;
070import org.jfree.chart.axis.ValueAxis;
071import org.jfree.chart.entity.CategoryItemEntity;
072import org.jfree.chart.entity.EntityCollection;
073import org.jfree.chart.labels.CategoryItemLabelGenerator;
074import org.jfree.chart.labels.CategoryToolTipGenerator;
075import org.jfree.chart.plot.CategoryPlot;
076import org.jfree.chart.plot.PlotOrientation;
077import org.jfree.data.category.CategoryDataset;
078import org.jfree.data.category.IntervalCategoryDataset;
079import org.jfree.ui.RectangleEdge;
080import org.jfree.util.PublicCloneable;
081
082/**
083 * A renderer that handles the drawing of bars for a bar plot where
084 * each bar has a high and low value.
085 * <p>
086 * For use with the {@link CategoryPlot} class.
087 */
088public class IntervalBarRenderer extends BarRenderer
089                                 implements CategoryItemRenderer, 
090                                            Cloneable, 
091                                            PublicCloneable, 
092                                            Serializable {
093
094    /** For serialization. */
095    private static final long serialVersionUID = -5068857361615528725L;
096    
097    /**
098     * Constructs a new renderer.
099     */
100    public IntervalBarRenderer() {
101        super();
102    }
103
104    /**
105     * Draws the bar for a single (series, category) data item.
106     *
107     * @param g2  the graphics device.
108     * @param state  the renderer state.
109     * @param dataArea  the data area.
110     * @param plot  the plot.
111     * @param domainAxis  the domain axis.
112     * @param rangeAxis  the range axis.
113     * @param dataset  the dataset.
114     * @param row  the row index (zero-based).
115     * @param column  the column index (zero-based).
116     * @param pass  the pass index.
117     */
118    public void drawItem(Graphics2D g2,
119                         CategoryItemRendererState state,
120                         Rectangle2D dataArea,
121                         CategoryPlot plot,
122                         CategoryAxis domainAxis,
123                         ValueAxis rangeAxis,
124                         CategoryDataset dataset,
125                         int row,
126                         int column,
127                         int pass) {
128
129         if (dataset instanceof IntervalCategoryDataset) {
130             IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
131             drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis, 
132                     d, row, column);
133         }
134         else {
135             super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis, 
136                     dataset, row, column, pass);
137         } 
138         
139     }
140                          
141     /**
142      * Draws a single interval.
143      *
144      * @param g2  the graphics device.
145      * @param state  the renderer state.
146      * @param dataArea  the data plot area.
147      * @param plot  the plot.
148      * @param domainAxis  the domain axis.
149      * @param rangeAxis  the range axis.
150      * @param dataset  the data.
151      * @param row  the row index (zero-based).
152      * @param column  the column index (zero-based).
153      */
154     protected void drawInterval(Graphics2D g2,
155                                 CategoryItemRendererState state,
156                                 Rectangle2D dataArea,
157                                 CategoryPlot plot,
158                                 CategoryAxis domainAxis,
159                                 ValueAxis rangeAxis,
160                                 IntervalCategoryDataset dataset,
161                                 int row,
162                                 int column) {
163
164        int seriesCount = getRowCount();
165        int categoryCount = getColumnCount();
166
167        PlotOrientation orientation = plot.getOrientation();
168        
169        double rectX = 0.0;
170        double rectY = 0.0;
171
172        RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
173        RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
174        
175        // Y0
176        Number value0 = dataset.getEndValue(row, column);
177        if (value0 == null) {
178            return;
179        }
180        double java2dValue0 = rangeAxis.valueToJava2D(
181            value0.doubleValue(), dataArea, rangeAxisLocation
182        );
183
184        // Y1
185        Number value1 = dataset.getStartValue(row, column);
186        if (value1 == null) {
187            return;
188        }
189        double java2dValue1 = rangeAxis.valueToJava2D(
190                value1.doubleValue(), dataArea, rangeAxisLocation);
191
192        if (java2dValue1 < java2dValue0) {
193            double temp = java2dValue1;
194            java2dValue1 = java2dValue0;
195            java2dValue0 = temp;
196            Number tempNum = value1;
197            value1 = value0;
198            value0 = tempNum;
199        }
200
201        // BAR WIDTH
202        double rectWidth = state.getBarWidth();
203
204        // BAR HEIGHT
205        double rectHeight = Math.abs(java2dValue1 - java2dValue0);
206
207        if (orientation == PlotOrientation.HORIZONTAL) {
208            // BAR Y
209            rectY = domainAxis.getCategoryStart(
210                column, getColumnCount(), dataArea, domainAxisLocation
211            );
212            if (seriesCount > 1) {
213                double seriesGap = dataArea.getHeight() * getItemMargin()
214                                   / (categoryCount * (seriesCount - 1));
215                rectY = rectY + row * (state.getBarWidth() + seriesGap);
216            }
217            else {
218                rectY = rectY + row * state.getBarWidth();
219            }
220            
221            rectX = java2dValue0;
222
223            rectHeight = state.getBarWidth();
224            rectWidth = Math.abs(java2dValue1 - java2dValue0);
225
226        }
227        else if (orientation == PlotOrientation.VERTICAL) {
228            // BAR X
229            rectX = domainAxis.getCategoryStart(column, getColumnCount(), 
230                    dataArea, domainAxisLocation);
231
232            if (seriesCount > 1) {
233                double seriesGap = dataArea.getWidth() * getItemMargin()
234                                   / (categoryCount * (seriesCount - 1));
235                rectX = rectX + row * (state.getBarWidth() + seriesGap);
236            }
237            else {
238                rectX = rectX + row * state.getBarWidth();
239            }
240
241            rectY = java2dValue0;
242
243        }
244        Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth, 
245                rectHeight);
246        Paint seriesPaint = getItemPaint(row, column);
247        g2.setPaint(seriesPaint);
248        g2.fill(bar);
249        
250        // draw the outline...
251        if (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
252            Stroke stroke = getItemOutlineStroke(row, column);
253            Paint paint = getItemOutlinePaint(row, column);
254            if (stroke != null && paint != null) {
255                g2.setStroke(stroke);
256                g2.setPaint(paint);
257                g2.draw(bar);
258            }
259        }
260        
261        CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
262                column);
263        if (generator != null && isItemLabelVisible(row, column)) {
264            drawItemLabel(g2, dataset, row, column, plot, generator, bar, 
265                    false);
266        }        
267
268        // collect entity and tool tip information...
269        if (state.getInfo() != null) {
270            EntityCollection entities = state.getEntityCollection();
271            if (entities != null) {
272                String tip = null;
273                CategoryToolTipGenerator tipster 
274                        = getToolTipGenerator(row, column);
275                if (tipster != null) {
276                    tip = tipster.generateToolTip(dataset, row, column);
277                }
278                String url = null;
279                if (getItemURLGenerator(row, column) != null) {
280                    url = getItemURLGenerator(row, column).generateURL(
281                            dataset, row, column);
282                }
283                CategoryItemEntity entity = new CategoryItemEntity(bar, tip, 
284                        url, dataset, dataset.getRowKey(row), 
285                        dataset.getColumnKey(column));
286                entities.add(entity);
287            }
288        }
289
290    }
291
292}