    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 * 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
    051package org.jfree.chart.renderer.xy;
    052
    053import java.awt.Font;
    054import java.awt.Graphics2D;
    055import java.awt.Paint;
    056import java.awt.Shape;
    057import java.awt.Stroke;
    058import java.awt.geom.Line2D;
    059import java.awt.geom.Point2D;
    060import java.awt.geom.Rectangle2D;
    061import java.io.Serializable;
    062
    063import org.jfree.chart.axis.ValueAxis;
    064import org.jfree.chart.entity.EntityCollection;
    065import org.jfree.chart.event.RendererChangeEvent;
    066import org.jfree.chart.labels.ItemLabelPosition;
    067import org.jfree.chart.labels.XYItemLabelGenerator;
    068import org.jfree.chart.plot.CrosshairState;
    069import org.jfree.chart.plot.PlotOrientation;
    070import org.jfree.chart.plot.PlotRenderingInfo;
    071import org.jfree.chart.plot.XYPlot;
    072import org.jfree.data.Range;
    073import org.jfree.data.general.DatasetUtilities;
    074import org.jfree.data.xy.IntervalXYDataset;
    075import org.jfree.data.xy.XYDataset;
    076import org.jfree.text.TextUtilities;
    077import org.jfree.ui.RectangleEdge;
    078import org.jfree.util.ObjectUtilities;
    079import org.jfree.util.PublicCloneable;
    080import 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 */
    091public 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     */
    264    private void drawAdditionalItemLabel(Graphics2D g2,
    265            PlotOrientation orientation, XYDataset dataset, int series,
    266            int item, double x, double y) {
    267
    268        if (this.additionalItemLabelGenerator == null) {
    269            return;
    270        }
    271
    272        Font labelFont = getItemLabelFont(series, item);
    273        Paint paint = getItemLabelPaint(series, item);
    274        g2.setFont(labelFont);
    275        g2.setPaint(paint);
    276        String label = this.additionalItemLabelGenerator.generateLabel(dataset,
    277                series, item);
    278
    279        ItemLabelPosition position = getNegativeItemLabelPosition(series, item);
    280        Point2D anchorPoint = calculateLabelAnchorPoint(
    281                position.getItemLabelAnchor(), x, y, orientation);
    282        TextUtilities.drawRotatedString(label, g2,
    283                (float) anchorPoint.getX(), (float) anchorPoint.getY(),
    284                position.getTextAnchor(), position.getAngle(),
    285                position.getRotationAnchor());
    286    }
    287
    288    /**
    289     * Tests this renderer for equality with an arbitrary object.
    290     *
    291     * @param obj  the object (<code>null</code> permitted).
    292     *
    293     * @return A boolean.
    294     */
    295    public boolean equals(Object obj) {
    296        if (obj == this) {
    297            return true;
    298        }
    299        if (!(obj instanceof YIntervalRenderer)) {
    300            return false;
    301        }
    302        YIntervalRenderer that = (YIntervalRenderer) obj;
    303        if (!ObjectUtilities.equal(this.additionalItemLabelGenerator,
    304                that.additionalItemLabelGenerator)) {
    305            return false;
    306        }
    307        return super.equals(obj);
    308    }
    309
    310    /**
    311     * Returns a clone of the renderer.
    312     *
    313     * @return A clone.
    314     *
    315     * @throws CloneNotSupportedException  if the renderer cannot be cloned.
    316     */
    317    public Object clone() throws CloneNotSupportedException {
    318        return super.clone();
    319    }
    320
    321}