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