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 * CategoryLabelPositions.java 029 * --------------------------- 030 * (C) Copyright 2004-present, by David Gilbert and Contributors. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): Tracy Hiltbrand (equals/hashCode comply with EqualsVerifier); 034 * 035 */ 036 037package org.jfree.chart.axis; 038 039import java.io.Serializable; 040import java.util.Objects; 041import org.jfree.chart.text.TextBlockAnchor; 042import org.jfree.chart.ui.RectangleAnchor; 043import org.jfree.chart.ui.RectangleEdge; 044import org.jfree.chart.ui.TextAnchor; 045import org.jfree.chart.util.Args; 046 047 048/** 049 * Records the label positions for a category axis. Instances of this class 050 * are immutable. 051 */ 052public class CategoryLabelPositions implements Serializable { 053 054 /** For serialization. */ 055 private static final long serialVersionUID = -8999557901920364580L; 056 057 /** STANDARD category label positions. */ 058 public static final CategoryLabelPositions 059 STANDARD = new CategoryLabelPositions( 060 new CategoryLabelPosition( 061 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_CENTER), // TOP 062 new CategoryLabelPosition( 063 RectangleAnchor.TOP, TextBlockAnchor.TOP_CENTER), // BOTTOM 064 new CategoryLabelPosition( 065 RectangleAnchor.RIGHT, TextBlockAnchor.CENTER_RIGHT, 066 CategoryLabelWidthType.RANGE, 0.30f), // LEFT 067 new CategoryLabelPosition( 068 RectangleAnchor.LEFT, TextBlockAnchor.CENTER_LEFT, 069 CategoryLabelWidthType.RANGE, 0.30f) // RIGHT 070 ); 071 072 /** UP_90 category label positions. */ 073 public static final CategoryLabelPositions 074 UP_90 = new CategoryLabelPositions( 075 new CategoryLabelPosition( 076 RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_LEFT, 077 TextAnchor.CENTER_LEFT, -Math.PI / 2.0, 078 CategoryLabelWidthType.RANGE, 0.30f), // TOP 079 new CategoryLabelPosition( 080 RectangleAnchor.TOP, TextBlockAnchor.CENTER_RIGHT, 081 TextAnchor.CENTER_RIGHT, -Math.PI / 2.0, 082 CategoryLabelWidthType.RANGE, 0.30f), // BOTTOM 083 new CategoryLabelPosition( 084 RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_CENTER, 085 TextAnchor.BOTTOM_CENTER, -Math.PI / 2.0, 086 CategoryLabelWidthType.CATEGORY, 0.9f), // LEFT 087 new CategoryLabelPosition( 088 RectangleAnchor.LEFT, TextBlockAnchor.TOP_CENTER, 089 TextAnchor.TOP_CENTER, -Math.PI / 2.0, 090 CategoryLabelWidthType.CATEGORY, 0.90f) // RIGHT 091 ); 092 093 /** DOWN_90 category label positions. */ 094 public static final CategoryLabelPositions 095 DOWN_90 = new CategoryLabelPositions( 096 new CategoryLabelPosition( 097 RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_RIGHT, 098 TextAnchor.CENTER_RIGHT, Math.PI / 2.0, 099 CategoryLabelWidthType.RANGE, 0.30f), // TOP 100 new CategoryLabelPosition( 101 RectangleAnchor.TOP, TextBlockAnchor.CENTER_LEFT, 102 TextAnchor.CENTER_LEFT, Math.PI / 2.0, 103 CategoryLabelWidthType.RANGE, 0.30f), // BOTTOM 104 new CategoryLabelPosition( 105 RectangleAnchor.RIGHT, TextBlockAnchor.TOP_CENTER, 106 TextAnchor.TOP_CENTER, Math.PI / 2.0, 107 CategoryLabelWidthType.CATEGORY, 0.90f), // LEFT 108 new CategoryLabelPosition( 109 RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_CENTER, 110 TextAnchor.BOTTOM_CENTER, Math.PI / 2.0, 111 CategoryLabelWidthType.CATEGORY, 0.90f) // RIGHT 112 ); 113 114 /** UP_45 category label positions. */ 115 public static final CategoryLabelPositions UP_45 116 = createUpRotationLabelPositions(Math.PI / 4.0); 117 118 /** DOWN_45 category label positions. */ 119 public static final CategoryLabelPositions DOWN_45 120 = createDownRotationLabelPositions(Math.PI / 4.0); 121 122 /** 123 * Creates a new instance where the category labels angled upwards by the 124 * specified amount. 125 * 126 * @param angle the rotation angle (should be < Math.PI / 2.0). 127 * 128 * @return A category label position specification. 129 */ 130 public static CategoryLabelPositions createUpRotationLabelPositions( 131 double angle) { 132 return new CategoryLabelPositions( 133 new CategoryLabelPosition( 134 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_LEFT, 135 TextAnchor.BOTTOM_LEFT, -angle, 136 CategoryLabelWidthType.RANGE, 0.50f), // TOP 137 new CategoryLabelPosition( 138 RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT, 139 TextAnchor.TOP_RIGHT, -angle, 140 CategoryLabelWidthType.RANGE, 0.50f), // BOTTOM 141 new CategoryLabelPosition( 142 RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_RIGHT, 143 TextAnchor.BOTTOM_RIGHT, -angle, 144 CategoryLabelWidthType.RANGE, 0.50f), // LEFT 145 new CategoryLabelPosition( 146 RectangleAnchor.LEFT, TextBlockAnchor.TOP_LEFT, 147 TextAnchor.TOP_LEFT, -angle, 148 CategoryLabelWidthType.RANGE, 0.50f) // RIGHT 149 ); 150 } 151 152 /** 153 * Creates a new instance where the category labels angled downwards by the 154 * specified amount. 155 * 156 * @param angle the rotation angle (should be < Math.PI / 2.0). 157 * 158 * @return A category label position specification. 159 */ 160 public static CategoryLabelPositions createDownRotationLabelPositions( 161 double angle) { 162 return new CategoryLabelPositions( 163 new CategoryLabelPosition( 164 RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_RIGHT, 165 TextAnchor.BOTTOM_RIGHT, angle, 166 CategoryLabelWidthType.RANGE, 0.50f), // TOP 167 new CategoryLabelPosition( 168 RectangleAnchor.TOP, TextBlockAnchor.TOP_LEFT, 169 TextAnchor.TOP_LEFT, angle, 170 CategoryLabelWidthType.RANGE, 0.50f), // BOTTOM 171 new CategoryLabelPosition( 172 RectangleAnchor.RIGHT, TextBlockAnchor.TOP_RIGHT, 173 TextAnchor.TOP_RIGHT, angle, 174 CategoryLabelWidthType.RANGE, 0.50f), // LEFT 175 new CategoryLabelPosition( 176 RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_LEFT, 177 TextAnchor.BOTTOM_LEFT, angle, 178 CategoryLabelWidthType.RANGE, 0.50f) // RIGHT 179 ); 180 } 181 182 /** 183 * The label positioning details used when an axis is at the top of a 184 * chart. 185 */ 186 private final CategoryLabelPosition positionForAxisAtTop; 187 188 /** 189 * The label positioning details used when an axis is at the bottom of a 190 * chart. 191 */ 192 private final CategoryLabelPosition positionForAxisAtBottom; 193 194 /** 195 * The label positioning details used when an axis is at the left of a 196 * chart. 197 */ 198 private final CategoryLabelPosition positionForAxisAtLeft; 199 200 /** 201 * The label positioning details used when an axis is at the right of a 202 * chart. 203 */ 204 private final CategoryLabelPosition positionForAxisAtRight; 205 206 /** 207 * Default constructor. 208 */ 209 public CategoryLabelPositions() { 210 this.positionForAxisAtTop = new CategoryLabelPosition(); 211 this.positionForAxisAtBottom = new CategoryLabelPosition(); 212 this.positionForAxisAtLeft = new CategoryLabelPosition(); 213 this.positionForAxisAtRight = new CategoryLabelPosition(); 214 } 215 216 /** 217 * Creates a new position specification. 218 * 219 * @param top the label position info used when an axis is at the top 220 * ({@code null} not permitted). 221 * @param bottom the label position info used when an axis is at the 222 * bottom ({@code null} not permitted). 223 * @param left the label position info used when an axis is at the left 224 * ({@code null} not permitted). 225 * @param right the label position info used when an axis is at the right 226 * ({@code null} not permitted). 227 */ 228 public CategoryLabelPositions(CategoryLabelPosition top, 229 CategoryLabelPosition bottom, CategoryLabelPosition left, 230 CategoryLabelPosition right) { 231 232 Args.nullNotPermitted(top, "top"); 233 Args.nullNotPermitted(bottom, "bottom"); 234 Args.nullNotPermitted(left, "left"); 235 Args.nullNotPermitted(right, "right"); 236 237 this.positionForAxisAtTop = top; 238 this.positionForAxisAtBottom = bottom; 239 this.positionForAxisAtLeft = left; 240 this.positionForAxisAtRight = right; 241 } 242 243 /** 244 * Returns the category label position specification for an axis at the 245 * given location. 246 * 247 * @param edge the axis location. 248 * 249 * @return The category label position specification. 250 */ 251 public CategoryLabelPosition getLabelPosition(RectangleEdge edge) { 252 CategoryLabelPosition result = null; 253 if (edge == RectangleEdge.TOP) { 254 result = this.positionForAxisAtTop; 255 } 256 else if (edge == RectangleEdge.BOTTOM) { 257 result = this.positionForAxisAtBottom; 258 } 259 else if (edge == RectangleEdge.LEFT) { 260 result = this.positionForAxisAtLeft; 261 } 262 else if (edge == RectangleEdge.RIGHT) { 263 result = this.positionForAxisAtRight; 264 } 265 return result; 266 } 267 268 /** 269 * Returns a new instance based on an existing instance but with the top 270 * position changed. 271 * 272 * @param base the base ({@code null} not permitted). 273 * @param top the top position ({@code null} not permitted). 274 * 275 * @return A new instance (never {@code null}). 276 */ 277 public static CategoryLabelPositions replaceTopPosition( 278 CategoryLabelPositions base, CategoryLabelPosition top) { 279 280 Args.nullNotPermitted(base, "base"); 281 Args.nullNotPermitted(top, "top"); 282 283 return new CategoryLabelPositions(top, 284 base.getLabelPosition(RectangleEdge.BOTTOM), 285 base.getLabelPosition(RectangleEdge.LEFT), 286 base.getLabelPosition(RectangleEdge.RIGHT)); 287 } 288 289 /** 290 * Returns a new instance based on an existing instance but with the bottom 291 * position changed. 292 * 293 * @param base the base ({@code null} not permitted). 294 * @param bottom the bottom position ({@code null} not permitted). 295 * 296 * @return A new instance (never {@code null}). 297 */ 298 public static CategoryLabelPositions replaceBottomPosition( 299 CategoryLabelPositions base, CategoryLabelPosition bottom) { 300 301 Args.nullNotPermitted(base, "base"); 302 Args.nullNotPermitted(bottom, "bottom"); 303 304 return new CategoryLabelPositions( 305 base.getLabelPosition(RectangleEdge.TOP), 306 bottom, 307 base.getLabelPosition(RectangleEdge.LEFT), 308 base.getLabelPosition(RectangleEdge.RIGHT)); 309 } 310 311 /** 312 * Returns a new instance based on an existing instance but with the left 313 * position changed. 314 * 315 * @param base the base ({@code null} not permitted). 316 * @param left the left position ({@code null} not permitted). 317 * 318 * @return A new instance (never {@code null}). 319 */ 320 public static CategoryLabelPositions replaceLeftPosition( 321 CategoryLabelPositions base, CategoryLabelPosition left) { 322 323 Args.nullNotPermitted(base, "base"); 324 Args.nullNotPermitted(left, "left"); 325 326 return new CategoryLabelPositions( 327 base.getLabelPosition(RectangleEdge.TOP), 328 base.getLabelPosition(RectangleEdge.BOTTOM), 329 left, 330 base.getLabelPosition(RectangleEdge.RIGHT)); 331 } 332 333 /** 334 * Returns a new instance based on an existing instance but with the right 335 * position changed. 336 * 337 * @param base the base ({@code null} not permitted). 338 * @param right the right position ({@code null} not permitted). 339 * 340 * @return A new instance (never {@code null}). 341 */ 342 public static CategoryLabelPositions replaceRightPosition( 343 CategoryLabelPositions base, CategoryLabelPosition right) { 344 345 Args.nullNotPermitted(base, "base"); 346 Args.nullNotPermitted(right, "right"); 347 return new CategoryLabelPositions( 348 base.getLabelPosition(RectangleEdge.TOP), 349 base.getLabelPosition(RectangleEdge.BOTTOM), 350 base.getLabelPosition(RectangleEdge.LEFT), 351 right); 352 } 353 354 /** 355 * Returns {@code true} if this object is equal to the specified 356 * object, and {@code false} otherwise. 357 * 358 * @param obj the other object. 359 * 360 * @return A boolean. 361 */ 362 @Override 363 public boolean equals(Object obj) { 364 if (this == obj) { 365 return true; 366 } 367 if (!(obj instanceof CategoryLabelPositions)) { 368 return false; 369 } 370 371 CategoryLabelPositions that = (CategoryLabelPositions) obj; 372 if (!Objects.equals(this.positionForAxisAtTop, 373 that.positionForAxisAtTop)) { 374 return false; 375 } 376 if (!Objects.equals(this.positionForAxisAtBottom, 377 that.positionForAxisAtBottom)) { 378 return false; 379 } 380 if (!Objects.equals(this.positionForAxisAtLeft, 381 that.positionForAxisAtLeft)) { 382 return false; 383 } 384 if (!Objects.equals(this.positionForAxisAtRight, 385 that.positionForAxisAtRight)) { 386 return false; 387 } 388 return true; 389 } 390 391 /** 392 * Returns a hash code for this object. 393 * 394 * @return A hash code. 395 */ 396 @Override 397 public int hashCode() { 398 int result = 19; 399 result = 19 * result + Objects.hashCode(this.positionForAxisAtTop); 400 result = 19 * result + Objects.hashCode(this.positionForAxisAtBottom); 401 result = 19 * result + Objects.hashCode(this.positionForAxisAtLeft); 402 result = 19 * result + Objects.hashCode(this.positionForAxisAtRight); 403 return result; 404 } 405}