001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2013, 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 * ColorBar.java
029 * -------------
030 * (C) Copyright 2002-2008, by David M. O'Donnell and Contributors.
031 *
032 * Original Author:  David M. O'Donnell;
033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
034 *
035 * Changes
036 * -------
037 * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
038 * 14-Jan-2003 : Changed autoRangeMinimumSize from Number --> double (DG);
039 * 17-Jan-2003 : Moved plot classes to separate package (DG);
040 * 20-Jan-2003 : Removed unnecessary constructors (DG);
041 * 26-Mar-2003 : Implemented Serializable (DG);
042 * 09-Jul-2003 : Changed ColorBar from extending axis classes to enclosing
043 *               them (DG);
044 * 05-Aug-2003 : Applied changes in bug report 780298 (DG);
045 * 14-Aug-2003 : Implemented Cloneable (DG);
046 * 08-Sep-2003 : Changed ValueAxis API (DG);
047 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
048 * ------------- JFREECHART 1.0.x ---------------------------------------------
049 * 31-Jan-2007 : Deprecated (DG);
050 *
051 */
052
053package org.jfree.chart.axis;
054
055import java.awt.BasicStroke;
056import java.awt.Graphics2D;
057import java.awt.Paint;
058import java.awt.RenderingHints;
059import java.awt.Stroke;
060import java.awt.geom.Line2D;
061import java.awt.geom.Rectangle2D;
062import java.io.Serializable;
063
064import org.jfree.chart.plot.ColorPalette;
065import org.jfree.chart.plot.ContourPlot;
066import org.jfree.chart.plot.Plot;
067import org.jfree.chart.plot.RainbowPalette;
068import org.jfree.chart.plot.XYPlot;
069import org.jfree.chart.renderer.xy.XYBlockRenderer;
070import org.jfree.ui.RectangleEdge;
071
072/**
073 * A color bar.
074 *
075 * @deprecated This class is no longer supported (as of version 1.0.4).  If
076 *     you are creating contour plots, please try to use {@link XYPlot} and
077 *     {@link XYBlockRenderer}.
078 */
079public class ColorBar implements Cloneable, Serializable {
080
081    /** For serialization. */
082    private static final long serialVersionUID = -2101776212647268103L;
083
084    /** The default color bar thickness. */
085    public static final int DEFAULT_COLORBAR_THICKNESS = 0;
086
087    /** The default color bar thickness percentage. */
088    public static final double DEFAULT_COLORBAR_THICKNESS_PERCENT = 0.10;
089
090    /** The default outer gap. */
091    public static final int DEFAULT_OUTERGAP = 2;
092
093    /** The axis. */
094    private ValueAxis axis;
095
096    /** The color bar thickness. */
097    private int colorBarThickness = DEFAULT_COLORBAR_THICKNESS;
098
099    /**
100     * The color bar thickness as a percentage of the height of the data area.
101     */
102    private double colorBarThicknessPercent
103            = DEFAULT_COLORBAR_THICKNESS_PERCENT;
104
105    /** The color palette. */
106    private ColorPalette colorPalette = null;
107
108    /** The color bar length. */
109    private int colorBarLength = 0; // default make height of plotArea
110
111    /** The amount of blank space around the colorbar. */
112    private int outerGap;
113
114    /**
115     * Constructs a horizontal colorbar axis, using default values where
116     * necessary.
117     *
118     * @param label  the axis label.
119     */
120    public ColorBar(String label) {
121
122        NumberAxis a = new NumberAxis(label);
123        a.setAutoRangeIncludesZero(false);
124        this.axis = a;
125        this.axis.setLowerMargin(0.0);
126        this.axis.setUpperMargin(0.0);
127
128        this.colorPalette = new RainbowPalette();
129        this.colorBarThickness = DEFAULT_COLORBAR_THICKNESS;
130        this.colorBarThicknessPercent = DEFAULT_COLORBAR_THICKNESS_PERCENT;
131        this.outerGap = DEFAULT_OUTERGAP;
132        this.colorPalette.setMinZ(this.axis.getRange().getLowerBound());
133        this.colorPalette.setMaxZ(this.axis.getRange().getUpperBound());
134
135    }
136
137    /**
138     * Configures the color bar.
139     *
140     * @param plot  the plot.
141     */
142    public void configure(ContourPlot plot) {
143        double minZ = plot.getDataset().getMinZValue();
144        double maxZ = plot.getDataset().getMaxZValue();
145        setMinimumValue(minZ);
146        setMaximumValue(maxZ);
147    }
148
149    /**
150     * Returns the axis.
151     *
152     * @return The axis.
153     */
154    public ValueAxis getAxis() {
155        return this.axis;
156    }
157
158    /**
159     * Sets the axis.
160     *
161     * @param axis  the axis.
162     */
163    public void setAxis(ValueAxis axis) {
164        this.axis = axis;
165    }
166
167    /**
168     * Rescales the axis to ensure that all data are visible.
169     */
170    public void autoAdjustRange() {
171        this.axis.autoAdjustRange();
172        this.colorPalette.setMinZ(this.axis.getLowerBound());
173        this.colorPalette.setMaxZ(this.axis.getUpperBound());
174    }
175
176    /**
177     * Draws the plot on a Java 2D graphics device (such as the screen or a
178     * printer).
179     *
180     * @param g2  the graphics device.
181     * @param cursor  the cursor.
182     * @param plotArea  the area within which the chart should be drawn.
183     * @param dataArea  the area within which the plot should be drawn (a
184     *                  subset of the drawArea).
185     * @param reservedArea  the reserved area.
186     * @param edge  the color bar location.
187     *
188     * @return The new cursor location.
189     */
190    public double draw(Graphics2D g2, double cursor,
191                       Rectangle2D plotArea, Rectangle2D dataArea,
192                       Rectangle2D reservedArea, RectangleEdge edge) {
193
194        Rectangle2D colorBarArea = null;
195
196        double thickness = calculateBarThickness(dataArea, edge);
197        if (this.colorBarThickness > 0) {
198            thickness = this.colorBarThickness;  // allow fixed thickness
199        }
200
201        double length;
202        if (RectangleEdge.isLeftOrRight(edge)) {
203            length = dataArea.getHeight();
204        }
205        else {
206            length = dataArea.getWidth();
207        }
208
209        if (this.colorBarLength > 0) {
210            length = this.colorBarLength;
211        }
212
213        if (edge == RectangleEdge.BOTTOM) {
214            colorBarArea = new Rectangle2D.Double(dataArea.getX(),
215                    plotArea.getMaxY() + this.outerGap, length, thickness);
216        }
217        else if (edge == RectangleEdge.TOP) {
218            colorBarArea = new Rectangle2D.Double(dataArea.getX(),
219                    reservedArea.getMinY() + this.outerGap, length, thickness);
220        }
221        else if (edge == RectangleEdge.LEFT) {
222            colorBarArea = new Rectangle2D.Double(plotArea.getX() - thickness
223                    - this.outerGap, dataArea.getMinY(), thickness, length);
224        }
225        else if (edge == RectangleEdge.RIGHT) {
226            colorBarArea = new Rectangle2D.Double(plotArea.getMaxX()
227                    + this.outerGap, dataArea.getMinY(), thickness, length);
228        }
229
230        // update, but dont draw tick marks (needed for stepped colors)
231        this.axis.refreshTicks(g2, new AxisState(), colorBarArea, edge);
232
233        drawColorBar(g2, colorBarArea, edge);
234
235        AxisState state = null;
236        assert colorBarArea != null; // suppresses compiler warnings
237        if (edge == RectangleEdge.TOP) {
238            cursor = colorBarArea.getMinY();
239            state = this.axis.draw(g2, cursor, reservedArea, colorBarArea,
240                    RectangleEdge.TOP, null);
241        }
242        else if (edge == RectangleEdge.BOTTOM) {
243            cursor = colorBarArea.getMaxY();
244            state = this.axis.draw(g2, cursor, reservedArea, colorBarArea,
245                    RectangleEdge.BOTTOM, null);
246        }
247        else if (edge == RectangleEdge.LEFT) {
248            cursor = colorBarArea.getMinX();
249            state = this.axis.draw(g2, cursor, reservedArea, colorBarArea,
250                    RectangleEdge.LEFT, null);
251        }
252        else if (edge == RectangleEdge.RIGHT) {
253            cursor = colorBarArea.getMaxX();
254            state = this.axis.draw(g2, cursor, reservedArea, colorBarArea,
255                    RectangleEdge.RIGHT, null);
256        }
257        assert state != null; // suppresses compiler warning
258        return state.getCursor();
259
260    }
261
262    /**
263     * Draws the plot on a Java 2D graphics device (such as the screen or a
264     * printer).
265     *
266     * @param g2  the graphics device.
267     * @param colorBarArea  the area within which the axis should be drawn.
268     * @param edge  the location.
269     */
270    public void drawColorBar(Graphics2D g2, Rectangle2D colorBarArea,
271                             RectangleEdge edge) {
272
273        Object antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
274        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
275                            RenderingHints.VALUE_ANTIALIAS_OFF);
276
277        // setTickValues was missing from ColorPalette v. 0.96
278        //colorPalette.setTickValues(this.axis.getTicks());
279
280        Stroke strokeSaved = g2.getStroke();
281        g2.setStroke(new BasicStroke(1.0f));
282
283        if (RectangleEdge.isTopOrBottom(edge)) {
284            double y1 = colorBarArea.getY();
285            double y2 = colorBarArea.getMaxY();
286            double xx = colorBarArea.getX();
287            Line2D line = new Line2D.Double();
288            while (xx <= colorBarArea.getMaxX()) {
289                double value = this.axis.java2DToValue(xx, colorBarArea, edge);
290                line.setLine(xx, y1, xx, y2);
291                g2.setPaint(getPaint(value));
292                g2.draw(line);
293                xx += 1;
294            }
295        }
296        else {
297            double y1 = colorBarArea.getX();
298            double y2 = colorBarArea.getMaxX();
299            double xx = colorBarArea.getY();
300            Line2D line = new Line2D.Double();
301            while (xx <= colorBarArea.getMaxY()) {
302                double value = this.axis.java2DToValue(xx, colorBarArea, edge);
303                line.setLine(y1, xx, y2, xx);
304                g2.setPaint(getPaint(value));
305                g2.draw(line);
306                xx += 1;
307            }
308        }
309
310        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias);
311        g2.setStroke(strokeSaved);
312
313    }
314
315    /**
316     * Returns the color palette.
317     *
318     * @return The color palette.
319     */
320    public ColorPalette getColorPalette() {
321        return this.colorPalette;
322    }
323
324    /**
325     * Returns the Paint associated with a value.
326     *
327     * @param value  the value.
328     *
329     * @return The paint.
330     */
331    public Paint getPaint(double value) {
332        return this.colorPalette.getPaint(value);
333    }
334
335    /**
336     * Sets the color palette.
337     *
338     * @param palette  the new palette.
339     */
340    public void setColorPalette(ColorPalette palette) {
341        this.colorPalette = palette;
342    }
343
344    /**
345     * Sets the maximum value.
346     *
347     * @param value  the maximum value.
348     */
349    public void setMaximumValue(double value) {
350        this.colorPalette.setMaxZ(value);
351        this.axis.setUpperBound(value);
352    }
353
354    /**
355     * Sets the minimum value.
356     *
357     * @param value  the minimum value.
358     */
359    public void setMinimumValue(double value) {
360        this.colorPalette.setMinZ(value);
361        this.axis.setLowerBound(value);
362    }
363
364    /**
365     * Reserves the space required to draw the color bar.
366     *
367     * @param g2  the graphics device.
368     * @param plot  the plot that the axis belongs to.
369     * @param plotArea  the area within which the plot should be drawn.
370     * @param dataArea  the data area.
371     * @param edge  the axis location.
372     * @param space  the space already reserved.
373     *
374     * @return The space required to draw the axis in the specified plot area.
375     */
376    public AxisSpace reserveSpace(Graphics2D g2, Plot plot,
377                                  Rectangle2D plotArea,
378                                  Rectangle2D dataArea, RectangleEdge edge,
379                                  AxisSpace space) {
380
381        AxisSpace result = this.axis.reserveSpace(g2, plot, plotArea, edge,
382                space);
383        double thickness = calculateBarThickness(dataArea, edge);
384        result.add(thickness + 2 * this.outerGap, edge);
385        return result;
386
387    }
388
389    /**
390     * Calculates the bar thickness.
391     *
392     * @param plotArea  the plot area.
393     * @param edge  the location.
394     *
395     * @return The thickness.
396     */
397    private double calculateBarThickness(Rectangle2D plotArea,
398            RectangleEdge edge) {
399        double result;
400        if (RectangleEdge.isLeftOrRight(edge)) {
401            result = plotArea.getWidth() * this.colorBarThicknessPercent;
402        }
403        else {
404            result = plotArea.getHeight() * this.colorBarThicknessPercent;
405        }
406        return result;
407    }
408
409    /**
410     * Returns a clone of the object.
411     *
412     * @return A clone.
413     *
414     * @throws CloneNotSupportedException if some component of the color bar
415     *         does not support cloning.
416     */
417    @Override
418    public Object clone() throws CloneNotSupportedException {
419        ColorBar clone = (ColorBar) super.clone();
420        clone.axis = (ValueAxis) this.axis.clone();
421        return clone;
422    }
423
424    /**
425     * Tests this object for equality with another.
426     *
427     * @param obj  the object to test against.
428     *
429     * @return A boolean.
430     */
431    @Override
432    public boolean equals(Object obj) {
433        if (obj == this) {
434            return true;
435        }
436        if (!(obj instanceof ColorBar)) {
437            return false;
438        }
439        ColorBar that = (ColorBar) obj;
440        if (!this.axis.equals(that.axis)) {
441            return false;
442        }
443        if (this.colorBarThickness != that.colorBarThickness) {
444            return false;
445        }
446        if (this.colorBarThicknessPercent != that.colorBarThicknessPercent) {
447            return false;
448        }
449        if (!this.colorPalette.equals(that.colorPalette)) {
450            return false;
451        }
452        if (this.colorBarLength != that.colorBarLength) {
453            return false;
454        }
455        if (this.outerGap != that.outerGap) {
456            return false;
457        }
458        return true;
459    }
460
461    /**
462     * Returns a hash code for this object.
463     *
464     * @return A hash code.
465     */
466    @Override
467    public int hashCode() {
468        return this.axis.hashCode();
469    }
470
471}