    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
    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    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}