001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package org.jfree.chart3d.marker; 034 035import java.awt.Color; 036import java.awt.Font; 037import java.awt.Graphics2D; 038import java.awt.Stroke; 039import java.awt.geom.Line2D; 040import java.awt.geom.Point2D; 041import java.io.IOException; 042import java.io.ObjectInputStream; 043import java.io.ObjectOutputStream; 044import java.io.Serializable; 045 046import org.jfree.chart3d.data.Range; 047import org.jfree.chart3d.graphics2d.Anchor2D; 048import org.jfree.chart3d.internal.Args; 049import org.jfree.chart3d.internal.ObjectUtils; 050import org.jfree.chart3d.internal.SerialUtils; 051 052/** 053 * A marker used to mark one value on an axis. 054 * <br><br> 055 * NOTE: This class is serializable, but the serialization format is subject 056 * to change in future releases and should not be relied upon for persisting 057 * instances of this class. 058 * 059 * @since 1.2 060 */ 061@SuppressWarnings("serial") 062public class NumberMarker extends AbstractMarker implements ValueMarker, 063 Serializable { 064 065 /** The data value to be marked. */ 066 private double value; 067 068 /** The label for the marker (optional). */ 069 private String label; 070 071 /** The font for the label. */ 072 private Font font; 073 074 /** The color for the label. */ 075 private Color labelColor; 076 077 /** The anchor for the label. */ 078 private Anchor2D labelAnchor; 079 080 /** The stroke for the marker line. */ 081 private transient Stroke stroke; 082 083 /** The color for the marker line. */ 084 private Color lineColor; 085 086 /** 087 * Creates a new marker. 088 * 089 * @param value the value. 090 */ 091 public NumberMarker(double value) { 092 super(); 093 this.value = value; 094 this.label = null; 095 this.font = DEFAULT_MARKER_FONT; 096 this.labelColor = DEFAULT_LABEL_COLOR; 097 this.stroke = DEFAULT_LINE_STROKE; 098 this.lineColor = DEFAULT_LINE_COLOR; 099 this.labelAnchor = Anchor2D.CENTER; 100 } 101 102 /** 103 * Returns the value for the marker (the initial value comes from the 104 * constructor). 105 * 106 * @return The value. 107 */ 108 public double getValue() { 109 return this.value; 110 } 111 112 /** 113 * Sets the value for the marker and sends a change event to all registered 114 * listeners. 115 * 116 * @param value the value. 117 */ 118 public void setValue(double value) { 119 this.value = value; 120 fireChangeEvent(); 121 } 122 123 /** 124 * Returns the range for the marker (in this case, a single value range). 125 * This method is used by the axis to filter out markers that do not touch 126 * the current axis range. 127 * 128 * @return The range for the marker (never {@code null}). 129 */ 130 @Override 131 public Range getRange() { 132 return new Range(this.value, this.value); 133 } 134 135 /** 136 * Returns the label for the marker (if this is {@code null} then no 137 * label is displayed). The default value is {@code null}. 138 * 139 * @return The label (possibly {@code null}). 140 */ 141 public String getLabel() { 142 return this.label; 143 } 144 145 /** 146 * Sets the label and sends a change event to all registered listeners. 147 * 148 * @param label the label ({@code null} permitted). 149 */ 150 public void setLabel(String label) { 151 this.label = label; 152 fireChangeEvent(); 153 } 154 155 /** 156 * Returns the font for the label. The default value is 157 * {@link Marker#DEFAULT_MARKER_FONT}. 158 * 159 * @return The font (never {@code null}). 160 */ 161 public Font getFont() { 162 return this.font; 163 } 164 165 /** 166 * Sets the font for the marker label and sends a change event to all 167 * registered listeners. 168 * 169 * @param font the font ({@code null} not permitted). 170 */ 171 public void setFont(Font font) { 172 Args.nullNotPermitted(font, "font"); 173 this.font = font; 174 fireChangeEvent(); 175 } 176 177 /** 178 * Returns the label color. The default value is 179 * {@link Marker#DEFAULT_LABEL_COLOR}. 180 * 181 * @return The label color (never {@code null}). 182 */ 183 public Color getLabelColor() { 184 return this.labelColor; 185 } 186 187 /** 188 * Sets the label color and sends a change event to all registered 189 * listeners. 190 * 191 * @param color the color ({@code null} not permitted). 192 */ 193 public void setLabelColor(Color color) { 194 Args.nullNotPermitted(color, "color"); 195 this.labelColor = color; 196 fireChangeEvent(); 197 } 198 199 /** 200 * Returns the anchor for the label. The default value is 201 * {@link Anchor2D#CENTER}. 202 * 203 * @return The anchor for the label. 204 */ 205 public Anchor2D getLabelAnchor() { 206 return this.labelAnchor; 207 } 208 209 /** 210 * Sets the anchor for the label and sends a change event to all registered 211 * listeners. 212 * 213 * @param anchor the anchor ({@code null} not permitted). 214 */ 215 public void setLabelAnchor(Anchor2D anchor) { 216 Args.nullNotPermitted(anchor, "anchor"); 217 this.labelAnchor = anchor; 218 fireChangeEvent(); 219 } 220 221 /** 222 * Returns the stroke for the marker line. The default value is 223 * {@link Marker#DEFAULT_LINE_STROKE}. 224 * 225 * @return The stroke for the marker line (never {@code null}). 226 */ 227 public Stroke getLineStroke() { 228 return this.stroke; 229 } 230 231 /** 232 * Sets the stroke for the marker line and sends a change event to all 233 * registered listeners. 234 * 235 * @param stroke the stroke ({@code null} not permitted). 236 */ 237 public void setLineStroke(Stroke stroke) { 238 Args.nullNotPermitted(stroke, "stroke"); 239 this.stroke = stroke; 240 fireChangeEvent(); 241 } 242 243 /** 244 * Returns the color for the marker line. The default value is 245 * {@link Marker#DEFAULT_LINE_COLOR}. 246 * 247 * @return The color for the marker line (never {@code null}). 248 */ 249 public Color getLineColor() { 250 return this.lineColor; 251 } 252 253 /** 254 * Sets the color for the marker line and sends a change event to all 255 * registered listeners. 256 * 257 * @param color the color ({@code null} not permitted). 258 */ 259 public void setLineColor(Color color) { 260 Args.nullNotPermitted(color, "color"); 261 this.lineColor = color; 262 fireChangeEvent(); 263 } 264 265 /** 266 * Draws the marker. This method is called by the library, you won't 267 * normally call it directly. 268 * 269 * @param g2 the graphics target ({@code null} not permitted). 270 * @param markerData transient marker data ({@code null} not 271 * permitted). 272 */ 273 @Override 274 public void draw(Graphics2D g2, MarkerData markerData, boolean reverse) { 275 MarkerLine line = markerData.getValueLine(); 276 g2.setPaint(this.lineColor); 277 g2.setStroke(this.stroke); 278 Line2D l = new Line2D.Double(line.getStartPoint(), line.getEndPoint()); 279 g2.draw(l); 280 Point2D labelPoint = markerData.getLabelPoint(); 281 if (labelPoint != null) { 282 g2.setFont(this.font); 283 g2.setColor(this.labelColor); 284 drawMarkerLabel(g2, this.label, labelPoint.getX(), 285 labelPoint.getY(), this.labelAnchor, l, reverse); 286 } 287 } 288 289 @Override 290 public int hashCode() { 291 int hash = 7; 292 hash = 19 * hash + (int) (Double.doubleToLongBits(this.value) 293 ^ (Double.doubleToLongBits(this.value) >>> 32)); 294 hash = 19 * hash + ObjectUtils.hashCode(this.label); 295 return hash; 296 } 297 298 @Override 299 public boolean equals(Object obj) { 300 if (obj == null) { 301 return false; 302 } 303 if (getClass() != obj.getClass()) { 304 return false; 305 } 306 final NumberMarker other = (NumberMarker) obj; 307 if (Double.doubleToLongBits(this.value) 308 != Double.doubleToLongBits(other.value)) { 309 return false; 310 } 311 if (!ObjectUtils.equals(this.label, other.label)) { 312 return false; 313 } 314 if (!ObjectUtils.equals(this.font, other.font)) { 315 return false; 316 } 317 if (!ObjectUtils.equals(this.labelColor, other.labelColor)) { 318 return false; 319 } 320 if (!ObjectUtils.equals(this.labelAnchor, other.labelAnchor)) { 321 return false; 322 } 323 if (!ObjectUtils.equals(this.stroke, other.stroke)) { 324 return false; 325 } 326 if (!ObjectUtils.equals(this.lineColor, other.lineColor)) { 327 return false; 328 } 329 return true; 330 } 331 332 /** 333 * Provides serialization support. 334 * 335 * @param stream the output stream. 336 * 337 * @throws IOException if there is an I/O error. 338 */ 339 private void writeObject(ObjectOutputStream stream) throws IOException { 340 stream.defaultWriteObject(); 341 SerialUtils.writeStroke(this.stroke, stream); 342 } 343 344 /** 345 * Provides serialization support. 346 * 347 * @param stream the input stream. 348 * 349 * @throws IOException if there is an I/O error. 350 * @throws ClassNotFoundException if there is a classpath problem. 351 */ 352 private void readObject(ObjectInputStream stream) 353 throws IOException, ClassNotFoundException { 354 stream.defaultReadObject(); 355 this.stroke = SerialUtils.readStroke(stream); 356 } 357 358}