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 * MarkerAxisBand.java 029 * ------------------- 030 * (C) Copyright 2000-2005, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: MarkerAxisBand.java,v 1.6.2.1 2005/10/25 20:37:34 mungady Exp $ 036 * 037 * Changes (from 03-Sep-2002) 038 * -------------------------- 039 * 03-Sep-2002 : Updated Javadoc comments (DG); 040 * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG); 041 * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG); 042 * 26-Mar-2003 : Implemented Serializable (DG); 043 * 13-May-2003 : Renamed HorizontalMarkerAxisBand --> MarkerAxisBand (DG); 044 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG); 045 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 046 * 07-Apr-2004 : Changed text bounds calculation (DG); 047 * 048 */ 049 050 package org.jfree.chart.axis; 051 052 import java.awt.AlphaComposite; 053 import java.awt.Color; 054 import java.awt.Composite; 055 import java.awt.Font; 056 import java.awt.FontMetrics; 057 import java.awt.Graphics2D; 058 import java.awt.font.LineMetrics; 059 import java.awt.geom.Rectangle2D; 060 import java.io.Serializable; 061 import java.util.Iterator; 062 import java.util.List; 063 064 import org.jfree.chart.plot.IntervalMarker; 065 import org.jfree.text.TextUtilities; 066 import org.jfree.ui.RectangleEdge; 067 import org.jfree.util.ObjectUtilities; 068 069 /** 070 * A band that can be added to a number axis to display regions. 071 */ 072 public class MarkerAxisBand implements Serializable { 073 074 /** For serialization. */ 075 private static final long serialVersionUID = -1729482413886398919L; 076 077 /** The axis that the band belongs to. */ 078 private NumberAxis axis; 079 080 /** The top outer gap. */ 081 private double topOuterGap; 082 083 /** The top inner gap. */ 084 private double topInnerGap; 085 086 /** The bottom outer gap. */ 087 private double bottomOuterGap; 088 089 /** The bottom inner gap. */ 090 private double bottomInnerGap; 091 092 /** The font. */ 093 private Font font; 094 095 /** Storage for the markers. */ 096 private List markers; 097 098 /** 099 * Constructs a new axis band. 100 * 101 * @param axis the owner. 102 * @param topOuterGap the top outer gap. 103 * @param topInnerGap the top inner gap. 104 * @param bottomOuterGap the bottom outer gap. 105 * @param bottomInnerGap the bottom inner gap. 106 * @param font the font. 107 */ 108 public MarkerAxisBand(NumberAxis axis, 109 double topOuterGap, double topInnerGap, 110 double bottomOuterGap, double bottomInnerGap, 111 Font font) { 112 this.axis = axis; 113 this.topOuterGap = topOuterGap; 114 this.topInnerGap = topInnerGap; 115 this.bottomOuterGap = bottomOuterGap; 116 this.bottomInnerGap = bottomInnerGap; 117 this.font = font; 118 this.markers = new java.util.ArrayList(); 119 } 120 121 /** 122 * Adds a marker to the band. 123 * 124 * @param marker the marker. 125 */ 126 public void addMarker(IntervalMarker marker) { 127 this.markers.add(marker); 128 } 129 130 /** 131 * Returns the height of the band. 132 * 133 * @param g2 the graphics device. 134 * 135 * @return The height of the band. 136 */ 137 public double getHeight(Graphics2D g2) { 138 139 double result = 0.0; 140 if (this.markers.size() > 0) { 141 LineMetrics metrics = this.font.getLineMetrics( 142 "123g", g2.getFontRenderContext() 143 ); 144 result = this.topOuterGap + this.topInnerGap + metrics.getHeight() 145 + this.bottomInnerGap + this.bottomOuterGap; 146 } 147 return result; 148 149 } 150 151 /** 152 * A utility method that draws a string inside a rectangle. 153 * 154 * @param g2 the graphics device. 155 * @param bounds the rectangle. 156 * @param font the font. 157 * @param text the text. 158 */ 159 private void drawStringInRect(Graphics2D g2, Rectangle2D bounds, Font font, 160 String text) { 161 162 g2.setFont(font); 163 FontMetrics fm = g2.getFontMetrics(font); 164 Rectangle2D r = TextUtilities.getTextBounds(text, g2, fm); 165 double x = bounds.getX(); 166 if (r.getWidth() < bounds.getWidth()) { 167 x = x + (bounds.getWidth() - r.getWidth()) / 2; 168 } 169 LineMetrics metrics = font.getLineMetrics( 170 text, g2.getFontRenderContext() 171 ); 172 g2.drawString( 173 text, (float) x, (float) (bounds.getMaxY() 174 - this.bottomInnerGap - metrics.getDescent()) 175 ); 176 } 177 178 /** 179 * Draws the band. 180 * 181 * @param g2 the graphics device. 182 * @param plotArea the plot area. 183 * @param dataArea the data area. 184 * @param x the x-coordinate. 185 * @param y the y-coordinate. 186 */ 187 public void draw(Graphics2D g2, Rectangle2D plotArea, Rectangle2D dataArea, 188 double x, double y) { 189 190 double h = getHeight(g2); 191 Iterator iterator = this.markers.iterator(); 192 while (iterator.hasNext()) { 193 IntervalMarker marker = (IntervalMarker) iterator.next(); 194 double start = Math.max( 195 marker.getStartValue(), this.axis.getRange().getLowerBound() 196 ); 197 double end = Math.min( 198 marker.getEndValue(), this.axis.getRange().getUpperBound() 199 ); 200 double s = this.axis.valueToJava2D( 201 start, dataArea, RectangleEdge.BOTTOM 202 ); 203 double e = this.axis.valueToJava2D( 204 end, dataArea, RectangleEdge.BOTTOM 205 ); 206 Rectangle2D r = new Rectangle2D.Double( 207 s, y + this.topOuterGap, e - s, 208 h - this.topOuterGap - this.bottomOuterGap 209 ); 210 211 Composite originalComposite = g2.getComposite(); 212 g2.setComposite(AlphaComposite.getInstance( 213 AlphaComposite.SRC_OVER, marker.getAlpha()) 214 ); 215 g2.setPaint(marker.getPaint()); 216 g2.fill(r); 217 g2.setPaint(marker.getOutlinePaint()); 218 g2.draw(r); 219 g2.setComposite(originalComposite); 220 221 g2.setPaint(Color.black); 222 drawStringInRect(g2, r, this.font, marker.getLabel()); 223 } 224 225 } 226 227 /** 228 * Tests this axis for equality with another object. Note that the axis 229 * that the band belongs to is ignored in the test. 230 * 231 * @param obj the object (<code>null</code> permitted). 232 * 233 * @return <code>true</code> or <code>false</code>. 234 */ 235 public boolean equals(Object obj) { 236 if (obj == this) { 237 return true; 238 } 239 if (!(obj instanceof MarkerAxisBand)) { 240 return false; 241 } 242 MarkerAxisBand that = (MarkerAxisBand) obj; 243 if (this.topOuterGap != that.topOuterGap) { 244 return false; 245 } 246 if (this.topInnerGap != that.topInnerGap) { 247 return false; 248 } 249 if (this.bottomInnerGap != that.bottomInnerGap) { 250 return false; 251 } 252 if (this.bottomOuterGap != that.bottomOuterGap) { 253 return false; 254 } 255 if (!ObjectUtilities.equal(this.font, that.font)) { 256 return false; 257 } 258 if (!ObjectUtilities.equal(this.markers, that.markers)) { 259 return false; 260 } 261 return true; 262 } 263 264 /** 265 * Returns a hash code for the object. 266 * 267 * @return A hash code. 268 */ 269 public int hashCode() { 270 int result = 37; 271 result = 19 * result + this.font.hashCode(); 272 result = 19 * result + this.markers.hashCode(); 273 return result; 274 } 275 276 }