001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2014, 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-2014, 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
068package org.jfree.chart.renderer.category;
069
070import java.awt.Graphics2D;
071import java.awt.geom.Rectangle2D;
072
073import org.jfree.chart.axis.CategoryAxis;
074import org.jfree.chart.axis.ValueAxis;
075import org.jfree.chart.entity.EntityCollection;
076import org.jfree.chart.labels.CategoryItemLabelGenerator;
077import org.jfree.chart.plot.CategoryPlot;
078import org.jfree.chart.plot.PlotOrientation;
079import org.jfree.data.Range;
080import org.jfree.data.category.CategoryDataset;
081import org.jfree.data.category.IntervalCategoryDataset;
082import 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 */
094public 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    @Override
117    public Range findRangeBounds(CategoryDataset dataset) {
118        return findRangeBounds(dataset, true);
119    }
120
121    /**
122     * Draws the bar for a single (series, category) data item.
123     *
124     * @param g2  the graphics device.
125     * @param state  the renderer state.
126     * @param dataArea  the data area.
127     * @param plot  the plot.
128     * @param domainAxis  the domain axis.
129     * @param rangeAxis  the range axis.
130     * @param dataset  the dataset.
131     * @param row  the row index (zero-based).
132     * @param column  the column index (zero-based).
133     * @param pass  the pass index.
134     */
135    @Override
136    public void drawItem(Graphics2D g2, CategoryItemRendererState state,
137            Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
138            ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
139            int pass) {
140
141         if (dataset instanceof IntervalCategoryDataset) {
142             IntervalCategoryDataset d = (IntervalCategoryDataset) dataset;
143             drawInterval(g2, state, dataArea, plot, domainAxis, rangeAxis,
144                     d, row, column);
145         }
146         else {
147             super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
148                     dataset, row, column, pass);
149         }
150
151     }
152
153     /**
154      * Draws a single interval.
155      *
156      * @param g2  the graphics device.
157      * @param state  the renderer state.
158      * @param dataArea  the data plot area.
159      * @param plot  the plot.
160      * @param domainAxis  the domain axis.
161      * @param rangeAxis  the range axis.
162      * @param dataset  the data.
163      * @param row  the row index (zero-based).
164      * @param column  the column index (zero-based).
165      */
166     protected void drawInterval(Graphics2D g2,
167                                 CategoryItemRendererState state,
168                                 Rectangle2D dataArea,
169                                 CategoryPlot plot,
170                                 CategoryAxis domainAxis,
171                                 ValueAxis rangeAxis,
172                                 IntervalCategoryDataset dataset,
173                                 int row,
174                                 int column) {
175
176        int visibleRow = state.getVisibleSeriesIndex(row);
177        if (visibleRow < 0) {
178            return;
179        }
180
181        PlotOrientation orientation = plot.getOrientation();
182        double rectX = 0.0;
183        double rectY = 0.0;
184
185        RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
186
187        // Y0
188        Number value0 = dataset.getEndValue(row, column);
189        if (value0 == null) {
190            return;
191        }
192        double java2dValue0 = rangeAxis.valueToJava2D(value0.doubleValue(),
193                dataArea, rangeAxisLocation);
194
195        // Y1
196        Number value1 = dataset.getStartValue(row, column);
197        if (value1 == null) {
198            return;
199        }
200        double java2dValue1 = rangeAxis.valueToJava2D(
201                value1.doubleValue(), dataArea, rangeAxisLocation);
202
203        if (java2dValue1 < java2dValue0) {
204            double temp = java2dValue1;
205            java2dValue1 = java2dValue0;
206            java2dValue0 = temp;
207        }
208
209        // BAR WIDTH
210        double rectWidth = state.getBarWidth();
211
212        // BAR HEIGHT
213        double rectHeight = Math.abs(java2dValue1 - java2dValue0);
214
215        RectangleEdge barBase = RectangleEdge.LEFT;
216        if (orientation == PlotOrientation.HORIZONTAL) {
217            // BAR Y
218            rectX = java2dValue0;
219            rectY = calculateBarW0(getPlot(), orientation, dataArea, 
220                    domainAxis, state, visibleRow, column);
221            rectHeight = state.getBarWidth();
222            rectWidth = Math.abs(java2dValue1 - java2dValue0);
223            barBase = RectangleEdge.LEFT;
224        }
225        else if (orientation == PlotOrientation.VERTICAL) {
226            // BAR X
227            rectX = calculateBarW0(getPlot(), orientation, dataArea, 
228                    domainAxis, state, visibleRow, column);
229            rectY = java2dValue0;
230            barBase = RectangleEdge.BOTTOM;
231        }
232        Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
233                rectHeight);
234        BarPainter painter = getBarPainter();
235        if (getShadowsVisible()) {
236            painter.paintBarShadow(g2, this, row, column, bar, barBase, false);
237        }
238        getBarPainter().paintBar(g2, this, row, column, bar, barBase);
239
240        CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
241                column);
242        if (generator != null && isItemLabelVisible(row, column)) {
243            drawItemLabel(g2, dataset, row, column, plot, generator, bar,
244                    false);
245        }
246
247        // add an item entity, if this information is being collected
248        EntityCollection entities = state.getEntityCollection();
249        if (entities != null) {
250            addItemEntity(entities, dataset, row, column, bar);
251        }
252
253    }
254
255    /**
256     * Tests this renderer for equality with an arbitrary object.
257     *
258     * @param obj  the object (<code>null</code> permitted).
259     *
260     * @return A boolean.
261     */
262    @Override
263    public boolean equals(Object obj) {
264        if (obj == this) {
265            return true;
266        }
267        if (!(obj instanceof IntervalBarRenderer)) {
268            return false;
269        }
270        // there are no fields to check
271        return super.equals(obj);
272    }
273
274}