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