comparison flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java @ 3806:881fcd01e056

merged flys-artifacts/pre2.6-2011-11-04
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:50 +0200
parents c51089a84d13
children 59622ba800c8
comparison
equal deleted inserted replaced
3802:e831dc29e572 3806:881fcd01e056
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 * Legacy-Constructor.
106 * @deprecated
107 */
108 public StickyAxisAnnotation(String text, float x, float y,
109 SimpleAxis stickAxis) {
110 super(text, x, y);
111 setStickyAxis(stickAxis);
112 this.pos = x;
113 }
114
115
116 /**
117 * Sets the "sticky axis" (whether to draw annotations at the
118 * X- or the Y-Axis.
119 *
120 * @param stickyAxis axis to stick to.
121 */
122 public void setStickyAxis(SimpleAxis stickyAxis) {
123 this.stickyAxis = stickyAxis;
124 if (stickyAxis == SimpleAxis.X_AXIS){
125 float o = 270f;
126 if(textOrientation.equals("horizontal")) {
127 o = 0f;
128 }
129 this.setRotationAngle(o * (Math.PI / 180f));
130 this.setRotationAnchor(TextAnchor.CENTER_LEFT);
131 this.setTextAnchor(TextAnchor.CENTER_LEFT);
132 } else {
133 this.setRotationAngle(0f * (Math.PI / 180f));
134 this.setRotationAnchor(TextAnchor.CENTER_LEFT);
135 this.setTextAnchor(TextAnchor.CENTER_LEFT);
136 }
137 }
138
139
140 /**
141 * Draws a small line at axis where this annotation resides.
142 *
143 * @param g2 the graphics device.
144 * @param dataArea the data area.
145 * @param domainAxis the domain axis.
146 * @param rangeAxis the range axis.
147 * @param domainEdge the domain edge.
148 * @param rangeEdge the range edge.
149 * @param orientation the plot orientation.
150 */
151 protected void drawAxisMark(
152 java.awt.Graphics2D g2,
153 java.awt.geom.Rectangle2D dataArea,
154 ValueAxis domainAxis,
155 ValueAxis rangeAxis,
156 RectangleEdge domainEdge,
157 RectangleEdge rangeEdge,
158 PlotOrientation orientation) {
159 float j2DX1 = 0.0f;
160 float j2DX2 = 0.0f;
161 float j2DY1 = 0.0f;
162 float j2DY2 = 0.0f;
163 float x = (float) getX();
164 float y = (float) getY();
165 /* When dependent on X/Y-Axis and orientation, following
166 can be used as a base:
167 if (orientation == PlotOrientation.VERTICAL) {
168 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea,
169 domainEdge);
170 j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea,
171 rangeEdge);
172 j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea,
173 domainEdge);
174 j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea,
175 rangeEdge);
176 }
177 else if (orientation == PlotOrientation.HORIZONTAL) {
178 j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea,
179 domainEdge);
180 j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea,
181 rangeEdge);
182 j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea,
183 domainEdge);
184 j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea,
185 rangeEdge);
186 }
187
188 g2.setPaint(this.paint);
189 g2.setStroke(this.stroke);
190 */
191 if (this.stickyAxis == SimpleAxis.X_AXIS) {
192 j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge);
193 double rangeLow = rangeAxis.getRange().getLowerBound();
194 // Line ends at 1.5% of full distance.
195 j2DY2 = (float) rangeAxis.valueToJava2D(
196 (1f - 0.015f) * rangeLow + 0.015f *
197 rangeAxis.getRange().getUpperBound(),
198 dataArea, rangeEdge);
199 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge);
200 j2DX2 = j2DX1;
201 } else {
202 j2DX1 = (float) RectangleEdge.coordinate(dataArea, rangeEdge);
203 Range domainRange = domainAxis.getRange();
204 double rangeLow = domainRange.getLowerBound();
205 // Line ends at 1.5% of full distance.
206 j2DX2 = (float) domainAxis.valueToJava2D(
207 (1f - 0.015f) * rangeLow + 0.015f *
208 domainRange.getUpperBound(),
209 dataArea, domainEdge);
210 j2DY1 = (float) rangeAxis.valueToJava2D(pos, dataArea, rangeEdge);
211 j2DY2 = j2DY1;
212 }
213
214 Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
215
216 // line is clipped to avoid JRE bug 6574155, for more info
217 // see JFreeChart bug 2221495
218 boolean visible = LineUtilities.clipLine(line, dataArea);
219 if (visible) {
220 setOutlineStroke(new BasicStroke((float) lineWidth));
221 g2.setStroke(getOutlineStroke());
222 g2.setPaint(lineColor);
223 g2.draw(line);
224 }
225 }
226
227
228 /**
229 * Draw the Annotiation if it does not collide with other already drawn
230 * Annotations.
231 *
232 * @param g2 the graphics device.
233 * @param plot the plot.
234 * @param dataArea the data area.
235 * @param domainAxis the domain axis.
236 * @param rangeAxis the range axis.
237 * @param rendererIndex the render index.
238 * @param info state information, escpecially collects info about
239 * already drawn shapes (and thus annotations), used
240 * for collision detection.
241 */
242 @Override
243 public void draw(
244 java.awt.Graphics2D g2,
245 XYPlot plot,
246 java.awt.geom.Rectangle2D dataArea,
247 ValueAxis domainAxis,
248 ValueAxis rangeAxis,
249 int rendererIndex,
250 PlotRenderingInfo info) {
251
252 if (info == null)
253 return;
254
255 if (domainAxis == null || rangeAxis == null
256 || domainAxis.getRange() == null
257 || rangeAxis.getRange() == null
258 ) {
259 logger.error("Annotation cannot be drawn (missing axis).");
260 return;
261 }
262
263 // Calculate the bounding box.
264 ChartRenderingInfo chartInfo = info.getOwner();
265
266 PlotOrientation orientation = plot.getOrientation();
267 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
268 plot.getDomainAxisLocation(), orientation);
269 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
270 plot.getRangeAxisLocation(), orientation);
271 float anchorX = 0f;
272 float anchorY = 0.0f;
273 if (this.stickyAxis == SimpleAxis.X_AXIS) {
274 // Text starts at 1.5% of full distance.
275 float rangeLow = (float) rangeAxis.getRange().getLowerBound();
276 float y = rangeLow + 0.02f * ((float)
277 rangeAxis.getRange().getUpperBound() - rangeLow);
278 setY(y);
279
280 anchorX = (float) domainAxis.valueToJava2D(
281 getX(), dataArea, domainEdge);
282 anchorY = (float) rangeAxis.valueToJava2D(
283 getY(), dataArea, rangeEdge);
284 } else {
285 float rangeLow = (float) domainAxis.getRange().getLowerBound();
286 float x = rangeLow + 0.02f * ((float)
287 domainAxis.getRange().getUpperBound() - rangeLow);
288 setX(x);
289 anchorX = (float) domainAxis.valueToJava2D(
290 getX(), dataArea, domainEdge);
291 anchorY = (float) rangeAxis.valueToJava2D(
292 getY(), dataArea, rangeEdge);
293 }
294 if (orientation == PlotOrientation.HORIZONTAL) {
295 float tempAnchor = anchorX;
296 anchorX = anchorY;
297 anchorY = tempAnchor;
298 }
299
300 //Call to apply orientation.
301 setStickyAxis(stickyAxis);
302
303 // Always draw the small line at axis.
304 drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge,
305 rangeEdge, orientation);
306
307 Shape hotspot = TextUtilities.calculateRotatedStringBounds(
308 getText(), g2, anchorX, anchorY, getTextAnchor(),
309 getRotationAngle(), getRotationAnchor());
310 Rectangle2D hotspotBox = hotspot.getBounds2D();
311 // Check for collisions with other XYAnnotations.
312 for (Iterator i = chartInfo.getEntityCollection().iterator();
313 i.hasNext(); ) {
314 Object next = i.next();
315 // Collision with other stuff than XYAnnotations are okay.
316 if (next instanceof XYAnnotationEntity) {
317 XYAnnotationEntity drawnShape = (XYAnnotationEntity) next;
318 if (drawnShape.getArea().intersects(hotspotBox)) {
319 // Found collision, early stop.
320 return;
321 }
322 }
323 }
324
325 // Draw the background.
326 if (showBackground) {
327 g2.setStroke(new BasicStroke ((float) 1));
328 g2.setBackground(textBackground);
329 g2.setPaint(textBackground);
330 hotspot = TextUtilities.calculateRotatedStringBounds(
331 getText(), g2, anchorX, anchorY, getTextAnchor(),
332 getRotationAngle(), getRotationAnchor());
333 g2.fill(hotspot);
334 g2.draw(hotspot);
335 }
336
337 // Draw the text.
338 g2.setPaint(textColor);
339 g2.setFont(font);
340 TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY,
341 getTextAnchor(), getRotationAngle(), getRotationAnchor());
342
343 // Add info that we have drawn this Annotation.
344 addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL());
345 }
346
347
348 public void applyTheme(ThemeAccess ta) {
349 lineWidth = ta.parseLineWidth();
350 lineColor = ta.parseLineColorField();
351 textColor = ta.parseTextColor();
352 font = ta.parseTextFont();
353 textOrientation = ta.parseTextOrientation();
354 textBackground = ta.parseTextBackground();
355 showBackground = ta.parseShowTextBackground();
356 }
357 }
358 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org