    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2009, 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     * YIntervalRenderer.java
    029     * ----------------------
    030     * (C) Copyright 2002-2009, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * Changes
    036     * -------
    037     * 05-Nov-2002 : Version 1 (DG);
    038     * 25-Mar-2003 : Implemented Serializable (DG);
    039     * 01-May-2003 : Modified drawItem() method signature (DG);
    040     * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
    041     * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
    042     * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG);
    043     * 27-Sep-2004 : Access double values from dataset (DG);
    044     * 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG);
    045     * 11-Apr-2008 : New override for findRangeBounds() (DG);
    046     * 26-May-2008 : Added item label support (DG);
    047     * 27-Mar-2009 : Updated findRangeBounds() (DG);
    048     *
    049     */
    050
    051    package org.jfree.chart.renderer.xy;
    052
    053    import java.awt.Font;
    054    import java.awt.Graphics2D;
    055    import java.awt.Paint;
    056    import java.awt.Shape;
    057    import java.awt.Stroke;
    058    import java.awt.geom.Line2D;
    059    import java.awt.geom.Point2D;
    060    import java.awt.geom.Rectangle2D;
    061    import java.io.Serializable;
    062
    063    import org.jfree.chart.axis.ValueAxis;
    064    import org.jfree.chart.entity.EntityCollection;
    065    import org.jfree.chart.event.RendererChangeEvent;
    066    import org.jfree.chart.labels.ItemLabelPosition;
    067    import org.jfree.chart.labels.XYItemLabelGenerator;
    068    import org.jfree.chart.plot.CrosshairState;
    069    import org.jfree.chart.plot.PlotOrientation;
    070    import org.jfree.chart.plot.PlotRenderingInfo;
    071    import org.jfree.chart.plot.XYPlot;
    072    import org.jfree.data.Range;
    073    import org.jfree.data.general.DatasetUtilities;
    074    import org.jfree.data.xy.IntervalXYDataset;
    075    import org.jfree.data.xy.XYDataset;
    076    import org.jfree.text.TextUtilities;
    077    import org.jfree.ui.RectangleEdge;
    078    import org.jfree.util.ObjectUtilities;
    079    import org.jfree.util.PublicCloneable;
    080    import org.jfree.util.ShapeUtilities;
    081
    082    /**
    083     * A renderer that draws a line connecting the start and end Y values for an
    084     * {@link XYPlot}.  The example shown here is generated by the
    085     * <code>YIntervalRendererDemo1.java</code> program included in the JFreeChart
    086     * demo collection:
    087     * <br><br>
    088     * <img src="../../../../../images/YIntervalRendererSample.png"
    089     * alt="YIntervalRendererSample.png" />
    090     */
    091    public class YIntervalRenderer extends AbstractXYItemRenderer
    092            implements XYItemRenderer, Cloneable, PublicCloneable, Serializable {
    093
    094        /** For serialization. */
    095        private static final long serialVersionUID = -2951586537224143260L;
    096
    097        /**
    098         * An additional item label generator.  If this is non-null, the item
    099         * label generated will be displayed near the lower y-value at the
    100         * position given by getNegativeItemLabelPosition().
    101         *
    102         * @since 1.0.10
    103         */
    104        private XYItemLabelGenerator additionalItemLabelGenerator;
    105
    106        /**
    107         * The default constructor.
    108         */
    109        public YIntervalRenderer() {
    110            super();
    111            this.additionalItemLabelGenerator = null;
    112        }
    113
    114        /**
    115         * Returns the generator for the item labels that appear near the lower
    116         * y-value.
    117         *
    118         * @return The generator (possibly <code>null</code>).
    119         *
    120         * @see #setAdditionalItemLabelGenerator(XYItemLabelGenerator)
    121         *
    122         * @since 1.0.10
    123         */
    124        public XYItemLabelGenerator getAdditionalItemLabelGenerator() {
    125            return this.additionalItemLabelGenerator;
    126        }
    127
    128        /**
    129         * Sets the generator for the item labels that appear near the lower
    130         * y-value and sends a {@link RendererChangeEvent} to all registered
    131         * listeners.  If this is set to <code>null</code>, no item labels will be
    132         * drawn.
    133         *
    134         * @param generator  the generator (<code>null</code> permitted).
    135         *
    136         * @see #getAdditionalItemLabelGenerator()
    137         *
    138         * @since 1.0.10
    139         */
    140        public void setAdditionalItemLabelGenerator(
    141                XYItemLabelGenerator generator) {
    142            this.additionalItemLabelGenerator = generator;
    143            fireChangeEvent();
    144        }
    145
    146        /**
    147         * Returns the range of values the renderer requires to display all the
    148         * items from the specified dataset.
    149         *
    150         * @param dataset  the dataset (<code>null</code> permitted).
    151         *
    152         * @return The range (<code>null</code> if the dataset is <code>null</code>
    153         *         or empty).
    154         */
    155        public Range findRangeBounds(XYDataset dataset) {
    156            return findRangeBounds(dataset, true);
    157        }
    158
    159        /**
    160         * Draws the visual representation of a single data item.
    161         *
    162         * @param g2  the graphics device.
    163         * @param state  the renderer state.
    164         * @param dataArea  the area within which the plot is being drawn.
    165         * @param info  collects information about the drawing.
    166         * @param plot  the plot (can be used to obtain standard color
    167         *              information etc).
    168         * @param domainAxis  the domain axis.
    169         * @param rangeAxis  the range axis.
    170         * @param dataset  the dataset.
    171         * @param series  the series index (zero-based).
    172         * @param item  the item index (zero-based).
    173         * @param crosshairState  crosshair information for the plot
    174         *                        (<code>null</code> permitted).
    175         * @param pass  the pass index (ignored here).
    176         */
    177        public void drawItem(Graphics2D g2,
    178                             XYItemRendererState state,
    179                             Rectangle2D dataArea,
    180                             PlotRenderingInfo info,
    181                             XYPlot plot,
    182                             ValueAxis domainAxis,
    183                             ValueAxis rangeAxis,
    184                             XYDataset dataset,
    185                             int series,
    186                             int item,
    187                             CrosshairState crosshairState,
    188                             int pass) {
    189
    190            // setup for collecting optional entity info...
    191            EntityCollection entities = null;
    192            if (info != null) {
    193                entities = info.getOwner().getEntityCollection();
    194            }
    195
    196            IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
    197
    198            double x = intervalDataset.getXValue(series, item);
    199            double yLow   = intervalDataset.getStartYValue(series, item);
    200            double yHigh  = intervalDataset.getEndYValue(series, item);
    201
    202            RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
    203            RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
    204
    205            double xx = domainAxis.valueToJava2D(x, dataArea, xAxisLocation);
    206            double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, yAxisLocation);
    207            double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, yAxisLocation);
    208
    209            Paint p = getItemPaint(series, item);
    210            Stroke s = getItemStroke(series, item);
    211
    212            Line2D line = null;
    213            Shape shape = getItemShape(series, item);
    214            Shape top = null;
    215            Shape bottom = null;
    216            PlotOrientation orientation = plot.getOrientation();
    217            if (orientation == PlotOrientation.HORIZONTAL) {
    218                line = new Line2D.Double(yyLow, xx, yyHigh, xx);
    219                top = ShapeUtilities.createTranslatedShape(shape, yyHigh, xx);
    220                bottom = ShapeUtilities.createTranslatedShape(shape, yyLow, xx);
    221            }
    222            else if (orientation == PlotOrientation.VERTICAL) {
    223                line = new Line2D.Double(xx, yyLow, xx, yyHigh);
    224                top = ShapeUtilities.createTranslatedShape(shape, xx, yyHigh);
    225                bottom = ShapeUtilities.createTranslatedShape(shape, xx, yyLow);
    226            }
    227            g2.setPaint(p);
    228            g2.setStroke(s);
    229            g2.draw(line);
    230
    231            g2.fill(top);
    232            g2.fill(bottom);
    233
    234            // for item labels, we have a special case because there is the
    235            // possibility to draw (a) the regular item label near to just the
    236            // upper y-value, or (b) the regular item label near the upper y-value
    237            // PLUS an additional item label near the lower y-value.
    238            if (isItemLabelVisible(series, item)) {
    239                drawItemLabel(g2, orientation, dataset, series, item, xx, yyHigh,
    240                        false);
    241                drawAdditionalItemLabel(g2, orientation, dataset, series, item,
    242                        xx, yyLow);
    243            }
    244
    245            // add an entity for the item...
    246            if (entities != null) {
    247                addEntity(entities, line.getBounds(), dataset, series, item, 0.0,
    248                        0.0);
    249            }
    250
    251        }
    252
    253        /**
    254         * Draws an item label.
    255         *
    256         * @param g2  the graphics device.
    257         * @param orientation  the orientation.
    258         * @param dataset  the dataset.
    259         * @param series  the series index (zero-based).
    260         * @param item  the item index (zero-based).
    261         * @param x  the x coordinate (in Java2D space).
    262         * @param y  the y coordinate (in Java2D space).
    263         * @param negative  indicates a negative value (which affects the item
    264         *                  label position).
    265         */
    266        private void drawAdditionalItemLabel(Graphics2D g2,
    267                PlotOrientation orientation, XYDataset dataset, int series,
    268                int item, double x, double y) {
    269
    270            if (this.additionalItemLabelGenerator == null) {
    271                return;
    272            }
    273
    274            Font labelFont = getItemLabelFont(series, item);
    275            Paint paint = getItemLabelPaint(series, item);
    276            g2.setFont(labelFont);
    277            g2.setPaint(paint);
    278            String label = this.additionalItemLabelGenerator.generateLabel(dataset,
    279                    series, item);
    280
    281            ItemLabelPosition position = getNegativeItemLabelPosition(series, item);
    282            Point2D anchorPoint = calculateLabelAnchorPoint(
    283                    position.getItemLabelAnchor(), x, y, orientation);
    284            TextUtilities.drawRotatedString(label, g2,
    285                    (float) anchorPoint.getX(), (float) anchorPoint.getY(),
    286                    position.getTextAnchor(), position.getAngle(),
    287                    position.getRotationAnchor());
    288        }
    289
    290        /**
    291         * Tests this renderer for equality with an arbitrary object.
    292         *
    293         * @param obj  the object (<code>null</code> permitted).
    294         *
    295         * @return A boolean.
    296         */
    297        public boolean equals(Object obj) {
    298            if (obj == this) {
    299                return true;
    300            }
    301            if (!(obj instanceof YIntervalRenderer)) {
    302                return false;
    303            }
    304            YIntervalRenderer that = (YIntervalRenderer) obj;
    305            if (!ObjectUtilities.equal(this.additionalItemLabelGenerator,
    306                    that.additionalItemLabelGenerator)) {
    307                return false;
    308            }
    309            return super.equals(obj);
    310        }
    311
    312        /**
    313         * Returns a clone of the renderer.
    314         *
    315         * @return A clone.
    316         *
    317         * @throws CloneNotSupportedException  if the renderer cannot be cloned.
    318         */
    319        public Object clone() throws CloneNotSupportedException {
    320            return super.clone();
    321        }
    322
    323    }