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