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