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 * XYDrawableAnnotation.java 029 * ------------------------- 030 * (C) Copyright 2003-2020, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart.annotations; 038 039import java.awt.Graphics2D; 040import java.awt.geom.AffineTransform; 041import java.awt.geom.Rectangle2D; 042import java.io.Serializable; 043 044import org.jfree.chart.axis.ValueAxis; 045import org.jfree.chart.plot.Plot; 046import org.jfree.chart.plot.PlotOrientation; 047import org.jfree.chart.plot.PlotRenderingInfo; 048import org.jfree.chart.plot.XYPlot; 049import org.jfree.chart.ui.Drawable; 050import org.jfree.chart.ui.RectangleEdge; 051import org.jfree.chart.util.ObjectUtils; 052import org.jfree.chart.util.Args; 053import org.jfree.chart.util.PublicCloneable; 054 055/** 056 * A general annotation that can be placed on an {@link XYPlot}. 057 */ 058public class XYDrawableAnnotation extends AbstractXYAnnotation 059 implements Cloneable, PublicCloneable, Serializable { 060 061 /** For serialization. */ 062 private static final long serialVersionUID = -6540812859722691020L; 063 064 /** The scaling factor. */ 065 private double drawScaleFactor; 066 067 /** The x-coordinate. */ 068 private double x; 069 070 /** The y-coordinate. */ 071 private double y; 072 073 /** The width. */ 074 private double displayWidth; 075 076 /** The height. */ 077 private double displayHeight; 078 079 /** The drawable object. */ 080 private Drawable drawable; 081 082 /** 083 * Creates a new annotation to be displayed within the given area. 084 * 085 * @param x the x-coordinate for the area. 086 * @param y the y-coordinate for the area. 087 * @param width the width of the area. 088 * @param height the height of the area. 089 * @param drawable the drawable object ({@code null} not permitted). 090 */ 091 public XYDrawableAnnotation(double x, double y, double width, double height, 092 Drawable drawable) { 093 this(x, y, width, height, 1.0, drawable); 094 } 095 096 /** 097 * Creates a new annotation to be displayed within the given area. If you 098 * specify a {@code drawScaleFactor} of 2.0, the {@code drawable} 099 * will be drawn at twice the requested display size then scaled down to 100 * fit the space. 101 * 102 * @param x the x-coordinate for the area. 103 * @param y the y-coordinate for the area. 104 * @param displayWidth the width of the area. 105 * @param displayHeight the height of the area. 106 * @param drawScaleFactor the scaling factor for drawing. 107 * @param drawable the drawable object ({@code null} not permitted). 108 * 109 * @since 1.0.11 110 */ 111 public XYDrawableAnnotation(double x, double y, double displayWidth, 112 double displayHeight, double drawScaleFactor, Drawable drawable) { 113 114 super(); 115 Args.nullNotPermitted(drawable, "drawable"); 116 this.x = x; 117 this.y = y; 118 this.displayWidth = displayWidth; 119 this.displayHeight = displayHeight; 120 this.drawScaleFactor = drawScaleFactor; 121 this.drawable = drawable; 122 123 } 124 125 /** 126 * Draws the annotation. 127 * 128 * @param g2 the graphics device. 129 * @param plot the plot. 130 * @param dataArea the data area. 131 * @param domainAxis the domain axis. 132 * @param rangeAxis the range axis. 133 * @param rendererIndex the renderer index. 134 * @param info if supplied, this info object will be populated with 135 * entity information. 136 */ 137 @Override 138 public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, 139 ValueAxis domainAxis, ValueAxis rangeAxis, 140 int rendererIndex, 141 PlotRenderingInfo info) { 142 143 PlotOrientation orientation = plot.getOrientation(); 144 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( 145 plot.getDomainAxisLocation(), orientation); 146 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( 147 plot.getRangeAxisLocation(), orientation); 148 float j2DX = (float) domainAxis.valueToJava2D(this.x, dataArea, 149 domainEdge); 150 float j2DY = (float) rangeAxis.valueToJava2D(this.y, dataArea, 151 rangeEdge); 152 Rectangle2D displayArea = new Rectangle2D.Double( 153 j2DX - this.displayWidth / 2.0, 154 j2DY - this.displayHeight / 2.0, this.displayWidth, 155 this.displayHeight); 156 157 // here we change the AffineTransform so we can draw the annotation 158 // to a larger area and scale it down into the display area 159 // afterwards, the original transform is restored 160 AffineTransform savedTransform = g2.getTransform(); 161 Rectangle2D drawArea = new Rectangle2D.Double(0.0, 0.0, 162 this.displayWidth * this.drawScaleFactor, 163 this.displayHeight * this.drawScaleFactor); 164 165 g2.scale(1 / this.drawScaleFactor, 1 / this.drawScaleFactor); 166 g2.translate((j2DX - this.displayWidth / 2.0) * this.drawScaleFactor, 167 (j2DY - this.displayHeight / 2.0) * this.drawScaleFactor); 168 this.drawable.draw(g2, drawArea); 169 g2.setTransform(savedTransform); 170 String toolTip = getToolTipText(); 171 String url = getURL(); 172 if (toolTip != null || url != null) { 173 addEntity(info, displayArea, rendererIndex, toolTip, url); 174 } 175 176 } 177 178 /** 179 * Tests this annotation for equality with an arbitrary object. 180 * 181 * @param obj the object to test against. 182 * 183 * @return {@code true} or {@code false}. 184 */ 185 @Override 186 public boolean equals(Object obj) { 187 188 if (obj == this) { // simple case 189 return true; 190 } 191 // now try to reject equality... 192 if (!super.equals(obj)) { 193 return false; 194 } 195 if (!(obj instanceof XYDrawableAnnotation)) { 196 return false; 197 } 198 XYDrawableAnnotation that = (XYDrawableAnnotation) obj; 199 if (this.x != that.x) { 200 return false; 201 } 202 if (this.y != that.y) { 203 return false; 204 } 205 if (this.displayWidth != that.displayWidth) { 206 return false; 207 } 208 if (this.displayHeight != that.displayHeight) { 209 return false; 210 } 211 if (this.drawScaleFactor != that.drawScaleFactor) { 212 return false; 213 } 214 if (!ObjectUtils.equal(this.drawable, that.drawable)) { 215 return false; 216 } 217 // seem to be the same... 218 return true; 219 220 } 221 222 /** 223 * Returns a hash code. 224 * 225 * @return A hash code. 226 */ 227 @Override 228 public int hashCode() { 229 int result; 230 long temp; 231 temp = Double.doubleToLongBits(this.x); 232 result = (int) (temp ^ (temp >>> 32)); 233 temp = Double.doubleToLongBits(this.y); 234 result = 29 * result + (int) (temp ^ (temp >>> 32)); 235 temp = Double.doubleToLongBits(this.displayWidth); 236 result = 29 * result + (int) (temp ^ (temp >>> 32)); 237 temp = Double.doubleToLongBits(this.displayHeight); 238 result = 29 * result + (int) (temp ^ (temp >>> 32)); 239 return result; 240 } 241 242 /** 243 * Returns a clone of the annotation. 244 * 245 * @return A clone. 246 * 247 * @throws CloneNotSupportedException if the annotation can't be cloned. 248 */ 249 @Override 250 public Object clone() throws CloneNotSupportedException { 251 return super.clone(); 252 } 253 254}