001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2011, 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     * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025     * Other names may be trademarks of their respective owners.]
026     *
027     * ------------------------
028     * IntervalBarRenderer.java
029     * ------------------------
030     * (C) Copyright 2002-2011, 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, 2791407);
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     * 16-May-2009 : The findRangeBounds() method needs to include the dataset
063     *               interval (DG);
064     * 19-May-2009 : Fixed FindBugs warnings, patch by Michal Wozniak (DG);
065     * 30-Oct-2011 : Fixed alignment when setMaximumBarWidth is applied (DG);
066     */
067    
068    package org.jfree.chart.renderer.category;
069    
070    import java.awt.Graphics2D;
071    import java.awt.geom.Rectangle2D;
072    
073    import org.jfree.chart.axis.CategoryAxis;
074    import org.jfree.chart.axis.ValueAxis;
075    import org.jfree.chart.entity.EntityCollection;
076    import org.jfree.chart.labels.CategoryItemLabelGenerator;
077    import org.jfree.chart.plot.CategoryPlot;
078    import org.jfree.chart.plot.PlotOrientation;
079    import org.jfree.data.Range;
080    import org.jfree.data.category.CategoryDataset;
081    import org.jfree.data.category.IntervalCategoryDataset;
082    import org.jfree.ui.RectangleEdge;
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.  This renderer is for use with the
087     * {@link CategoryPlot} class.  The example shown here is generated by the
088     * <code>IntervalBarChartDemo1.java</code> program included in the JFreeChart
089     * Demo Collection:
090     * <br><br>
091     * <img src="../../../../../images/IntervalBarRendererSample.png"
092     * alt="IntervalBarRendererSample.png" />
093     */
094    public class IntervalBarRenderer extends BarRenderer {
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         * Returns the range of values from the specified dataset.  For this
108         * renderer, this is equivalent to calling
109         * <code>findRangeBounds(dataset, true)</code>.
110         *
111         * @param dataset  the dataset (<code>null</code> permitted).
112         *
113         * @return The range (or <code>null</code> if the dataset is
114         *         <code>null</code> or empty).
115         */
116        public Range findRangeBounds(CategoryDataset dataset) {
117            return findRangeBounds(dataset, true);
118        }
119    
120        /**
121         * Draws the bar for a single (series, category) data item.
122         *
123         * @param g2  the graphics device.
124         * @param state  the renderer state.
125         * @param dataArea  the data area.
126         * @param plot  the plot.
127         * @param domainAxis  the domain axis.
128         * @param rangeAxis  the range axis.
129         * @param dataset  the dataset.
130         * @param row  the row index (zero-based).
131         * @param column  the column index (zero-based).
132         * @param pass  the pass index.
133         */
134        public void drawItem(Graphics2D g2,
135                             CategoryItemRendererState state,
136                             Rectangle2D dataArea,
137                             CategoryPlot plot,
138                             CategoryAxis domainAxis,
139                             ValueAxis rangeAxis,
140                             CategoryDataset dataset,
141                             int row,
142                             int column,
143                             int pass) {
144    
145             if (dataset instanceof IntervalCategoryDataset) {
146                 IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
147                 drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
148                         d, row, column);
149             }
150             else {
151                 super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
152                         dataset, row, column, pass);
153             }
154    
155         }
156    
157         /**
158          * Draws a single interval.
159          *
160          * @param g2  the graphics device.
161          * @param state  the renderer state.
162          * @param dataArea  the data plot area.
163          * @param plot  the plot.
164          * @param domainAxis  the domain axis.
165          * @param rangeAxis  the range axis.
166          * @param dataset  the data.
167          * @param row  the row index (zero-based).
168          * @param column  the column index (zero-based).
169          */
170         protected void drawInterval(Graphics2D g2,
171                                     CategoryItemRendererState state,
172                                     Rectangle2D dataArea,
173                                     CategoryPlot plot,
174                                     CategoryAxis domainAxis,
175                                     ValueAxis rangeAxis,
176                                     IntervalCategoryDataset dataset,
177                                     int row,
178                                     int column) {
179    
180            int visibleRow = state.getVisibleSeriesIndex(row);
181            if (visibleRow < 0) {
182                return;
183            }
184    
185            PlotOrientation orientation = plot.getOrientation();
186            double rectX = 0.0;
187            double rectY = 0.0;
188    
189            RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
190    
191            // Y0
192            Number value0 = dataset.getEndValue(row, column);
193            if (value0 == null) {
194                return;
195            }
196            double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
197                    dataArea, rangeAxisLocation);
198    
199            // Y1
200            Number value1 = dataset.getStartValue(row, column);
201            if (value1 == null) {
202                return;
203            }
204            double java2dValue1 = rangeAxis.valueToJava2D(
205                    value1.doubleValue(), dataArea, rangeAxisLocation);
206    
207            if (java2dValue1 < java2dValue0) {
208                double temp = java2dValue1;
209                java2dValue1 = java2dValue0;
210                java2dValue0 = temp;
211            }
212    
213            // BAR WIDTH
214            double rectWidth = state.getBarWidth();
215    
216            // BAR HEIGHT
217            double rectHeight = Math.abs(java2dValue1 - java2dValue0);
218    
219            RectangleEdge barBase = RectangleEdge.LEFT;
220            if (orientation == PlotOrientation.HORIZONTAL) {
221                // BAR Y
222                rectX = java2dValue0;
223                rectY = calculateBarW0(getPlot(), orientation, dataArea, 
224                        domainAxis, state, visibleRow, column);
225                rectHeight = state.getBarWidth();
226                rectWidth = Math.abs(java2dValue1 - java2dValue0);
227                barBase = RectangleEdge.LEFT;
228            }
229            else if (orientation == PlotOrientation.VERTICAL) {
230                // BAR X
231                rectX = calculateBarW0(getPlot(), orientation, dataArea, 
232                        domainAxis, state, visibleRow, column);
233                rectY = java2dValue0;
234                barBase = RectangleEdge.BOTTOM;
235            }
236            Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
237                    rectHeight);
238            BarPainter painter = getBarPainter();
239            if (getShadowsVisible()) {
240                painter.paintBarShadow(g2, this, row, column, bar, barBase, false);
241            }
242            getBarPainter().paintBar(g2, this, row, column, bar, barBase);
243    
244            CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
245                    column);
246            if (generator != null && isItemLabelVisible(row, column)) {
247                drawItemLabel(g2, dataset, row, column, plot, generator, bar,
248                        false);
249            }
250    
251            // add an item entity, if this information is being collected
252            EntityCollection entities = state.getEntityCollection();
253            if (entities != null) {
254                addItemEntity(entities, dataset, row, column, bar);
255            }
256    
257        }
258    
259        /**
260         * Tests this renderer for equality with an arbitrary object.
261         *
262         * @param obj  the object (<code>null</code> permitted).
263         *
264         * @return A boolean.
265         */
266        public boolean equals(Object obj) {
267            if (obj == this) {
268                return true;
269            }
270            if (!(obj instanceof IntervalBarRenderer)) {
271                return false;
272            }
273            // there are no fields to check
274            return super.equals(obj);
275        }
276    
277    }