comparison flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java @ 1190:f514894ec2fd

merged flys-artifacts/2.5
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:17 +0200
parents f1c9bfb07ba7
children f708120cb7bc
comparison
equal deleted inserted replaced
917:b48c36076e17 1190:f514894ec2fd
1 package de.intevation.flys.jfree;
2
3 import org.apache.log4j.Logger;
4
5 import java.util.Iterator;
6
7 import java.awt.Shape;
8 import java.awt.geom.Rectangle2D;
9 import java.awt.geom.Line2D;
10
11 import org.jfree.chart.annotations.XYTextAnnotation;
12 import org.jfree.chart.axis.ValueAxis;
13 import org.jfree.chart.util.LineUtilities;
14 import org.jfree.chart.plot.PlotOrientation;
15 import org.jfree.chart.plot.XYPlot;
16 import org.jfree.chart.entity.XYAnnotationEntity;
17 import org.jfree.chart.plot.PlotRenderingInfo;
18 import org.jfree.chart.ChartRenderingInfo;
19 import org.jfree.chart.plot.Plot;
20
21 import org.jfree.data.Range;
22
23 import org.jfree.text.TextUtilities;
24
25 import org.jfree.ui.RectangleEdge;
26 import org.jfree.ui.TextAnchor;
27
28
29 /**
30 * Custom Annotations class that is drawn only if no collisions with other
31 * already drawn CustomAnnotations in current plot are found.
32 * Draws a given text and a line to it from either axis.
33 */
34 public class StickyAxisAnnotation extends XYTextAnnotation {
35
36 /** Logger for this class. */
37 private static Logger logger =
38 Logger.getLogger(StickyAxisAnnotation.class);
39
40 /** Simplified view on axes. */
41 public static enum SimpleAxis {
42 X_AXIS, /** Usually "horizontal". */
43 Y_AXIS /** Usually "vertical". */
44 }
45
46 /** Which axis to stick to. */
47 protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS;
48
49 /** The 1-dimensional position of this annotation. */
50 protected float pos;
51
52
53 /**
54 * Trivial constructor.
55 *
56 * @param text Text to display.
57 * @param x X-position in dataspace (typical horizontal, in km).
58 * @param y Y-position in dataspace (typical vertical, in m).
59 * @deprecated
60 */
61 public StickyAxisAnnotation(String text, float x, float y) {
62 super(text, x, y);
63 setStickyAxis(SimpleAxis.X_AXIS);
64 }
65
66
67 /**
68 * Constructor with implicit sticky x-axis.
69 * @param text the text to display.
70 * @param pos the position at which to draw the text and mark.
71 */
72 public StickyAxisAnnotation(String text, float pos) {
73 this(text, pos, pos, SimpleAxis.X_AXIS);
74 }
75
76
77 /**
78 * Constructor with given explicit axis.
79 * @param text the text to display.
80 * @param pos the position at which to draw the text and mark.
81 * @param stickyAxis the axis at which to stick (and to which 'pos' is
82 * relative).
83 */
84 public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis) {
85 super(text, pos, pos);
86 setStickyAxis(stickAxis);
87 this.pos = pos;
88 }
89
90 /**
91 * Legacy-Constructor.
92 * @deprecated
93 */
94 public StickyAxisAnnotation(String text, float x, float y,
95 SimpleAxis stickAxis) {
96 super(text, x, y);
97 setStickyAxis(stickAxis);
98 this.pos = x;
99 }
100
101
102 /**
103 * Sets the "sticky axis" (whether to draw annotations at the
104 * X- or the Y-Axis.
105 *
106 * @param stickyAxis axis to stick to.
107 */
108 public void setStickyAxis(SimpleAxis stickyAxis) {
109 this.stickyAxis = stickyAxis;
110 if (stickyAxis == SimpleAxis.X_AXIS) {
111 this.setRotationAngle(270f * (Math.PI / 180f));
112 this.setRotationAnchor(TextAnchor.CENTER_LEFT);
113 this.setTextAnchor(TextAnchor.CENTER_LEFT);
114 } else {
115 this.setRotationAngle(0f * (Math.PI / 180f));
116 this.setRotationAnchor(TextAnchor.CENTER_LEFT);
117 this.setTextAnchor(TextAnchor.CENTER_LEFT);
118 }
119 }
120
121
122 /**
123 * Draws a small line at axis where this annotation resides.
124 *
125 * @param g2 the graphics device.
126 * @param dataArea the data area.
127 * @param domainAxis the domain axis.
128 * @param rangeAxis the range axis.
129 * @param domainEdge the domain edge.
130 * @param rangeEdge the range edge.
131 * @param orientation the plot orientation.
132 */
133 protected void drawAxisMark(
134 java.awt.Graphics2D g2,
135 java.awt.geom.Rectangle2D dataArea,
136 ValueAxis domainAxis,
137 ValueAxis rangeAxis,
138 RectangleEdge domainEdge,
139 RectangleEdge rangeEdge,
140 PlotOrientation orientation) {
141 float j2DX1 = 0.0f;
142 float j2DX2 = 0.0f;
143 float j2DY1 = 0.0f;
144 float j2DY2 = 0.0f;
145 float x = (float) getX();
146 float y = (float) getY();
147 /* When dependent on X/Y-Axis and orientation, following
148 can be used as a base:
149 if (orientation == PlotOrientation.VERTICAL) {
150 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea,
151 domainEdge);
152 j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea,
153 rangeEdge);
154 j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea,
155 domainEdge);
156 j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea,
157 rangeEdge);
158 }
159 else if (orientation == PlotOrientation.HORIZONTAL) {
160 j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea,
161 domainEdge);
162 j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea,
163 rangeEdge);
164 j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea,
165 domainEdge);
166 j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea,
167 rangeEdge);
168 }
169
170 g2.setPaint(this.paint);
171 g2.setStroke(this.stroke);
172 */
173 if (this.stickyAxis == SimpleAxis.X_AXIS) {
174 j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge);
175 double rangeLow = rangeAxis.getRange().getLowerBound();
176 // Line ends at 1.5% of full distance.
177 j2DY2 = (float) rangeAxis.valueToJava2D(
178 (1f - 0.015f) * rangeLow + 0.015f *
179 rangeAxis.getRange().getUpperBound(),
180 dataArea, rangeEdge);
181 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge);
182 j2DX2 = j2DX1;
183 } else {
184 j2DX1 = (float) RectangleEdge.coordinate(dataArea, rangeEdge);
185 Range domainRange = domainAxis.getRange();
186 double rangeLow = domainRange.getLowerBound();
187 // Line ends at 1.5% of full distance.
188 j2DX2 = (float) domainAxis.valueToJava2D(
189 (1f - 0.015f) * rangeLow + 0.015f *
190 domainRange.getUpperBound(),
191 dataArea, domainEdge);
192 j2DY1 = (float) rangeAxis.valueToJava2D(pos, dataArea, rangeEdge);
193 j2DY2 = j2DY1;
194 }
195
196 Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
197
198 // line is clipped to avoid JRE bug 6574155, for more info
199 // see JFreeChart bug 2221495
200 boolean visible = LineUtilities.clipLine(line, dataArea);
201 if (visible) {
202 g2.draw(line);
203 }
204 }
205
206
207 /**
208 * Draw the Annotiation if it does not collide with other already drawn
209 * Annotations.
210 *
211 * @param g2 the graphics device.
212 * @param plot the plot.
213 * @param dataArea the data area.
214 * @param domainAxis the domain axis.
215 * @param rangeAxis the range axis.
216 * @param rendererIndex the render index.
217 * @param info state information, escpecially collects info about
218 * already drawn shapes (and thus annotations), used
219 * for collision detection.
220 */
221 @Override
222 public void draw(
223 java.awt.Graphics2D g2,
224 XYPlot plot,
225 java.awt.geom.Rectangle2D dataArea,
226 ValueAxis domainAxis,
227 ValueAxis rangeAxis,
228 int rendererIndex,
229 PlotRenderingInfo info) {
230
231 if (info == null)
232 return;
233
234 if (domainAxis == null || rangeAxis == null
235 || domainAxis.getRange() == null
236 || rangeAxis.getRange() == null
237 ) {
238 logger.error("Annotation cannot be drawn (missing axis).");
239 return;
240 }
241
242 // Calculate the bounding box.
243 ChartRenderingInfo chartInfo = info.getOwner();
244
245 PlotOrientation orientation = plot.getOrientation();
246 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
247 plot.getDomainAxisLocation(), orientation);
248 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
249 plot.getRangeAxisLocation(), orientation);
250 float anchorX = 0f;
251 float anchorY = 0.0f;
252 if (this.stickyAxis == SimpleAxis.X_AXIS) {
253 // Text starts at 1.5% of full distance.
254 float rangeLow = (float) rangeAxis.getRange().getLowerBound();
255 float y = rangeLow + 0.02f * ((float)
256 rangeAxis.getRange().getUpperBound() - rangeLow);
257 setY(y);
258
259 anchorX = (float) domainAxis.valueToJava2D(
260 getX(), dataArea, domainEdge);
261 anchorY = (float) rangeAxis.valueToJava2D(
262 getY(), dataArea, rangeEdge);
263 } else {
264 float rangeLow = (float) domainAxis.getRange().getLowerBound();
265 float x = rangeLow + 0.02f * ((float)
266 domainAxis.getRange().getUpperBound() - rangeLow);
267 setX(x);
268 anchorX = (float) domainAxis.valueToJava2D(
269 getX(), dataArea, domainEdge);
270 anchorY = (float) rangeAxis.valueToJava2D(
271 getY(), dataArea, rangeEdge);
272 }
273 if (orientation == PlotOrientation.HORIZONTAL) {
274 float tempAnchor = anchorX;
275 anchorX = anchorY;
276 anchorY = tempAnchor;
277 }
278
279 // Always draw the small line at axis.
280 drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge,
281 rangeEdge, orientation);
282
283 g2.setFont(getFont());
284 Shape hotspot = TextUtilities.calculateRotatedStringBounds(
285 getText(), g2, anchorX, anchorY, getTextAnchor(),
286 getRotationAngle(), getRotationAnchor());
287 Rectangle2D hotspotBox = hotspot.getBounds2D();
288 // Check for collisions with other XYAnnotations.
289 for (Iterator i = chartInfo.getEntityCollection().iterator();
290 i.hasNext(); ) {
291 Object next = i.next();
292 // Collision with other stuff than XYAnnotations are okay.
293 if (next instanceof XYAnnotationEntity) {
294 XYAnnotationEntity drawnShape = (XYAnnotationEntity) next;
295 if (drawnShape.getArea().intersects(hotspotBox)) {
296 // Found collision, early stop.
297 return;
298 }
299 }
300 }
301
302 // Actuall drawing.
303 if (getBackgroundPaint() != null) {
304 g2.setPaint(getBackgroundPaint());
305 g2.fill(hotspot);
306 }
307 g2.setPaint(getPaint());
308 TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY,
309 getTextAnchor(), getRotationAngle(), getRotationAnchor());
310 // Draw outline.
311 if (false) {
312 g2.setStroke(getOutlineStroke());
313 g2.setPaint(getOutlinePaint());
314 g2.draw(hotspot);
315 }
316
317 // Add info that we have drawn this Annotation.
318 addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL());
319 }
320 }
321
322

http://dive4elements.wald.intevation.org