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