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