    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    }