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