comparison flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java @ 2161:c68f4f227c09

Somewhat unified Annotation handling, use jfreechart-house-toolkit instead of custom StickyAxisAnnotation. flys-artifacts/trunk@3747 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Mon, 23 Jan 2012 10:44:34 +0000
parents 59622ba800c8
children 105097966111
comparison
equal deleted inserted replaced
2160:8428de5846e8 2161:c68f4f227c09
1 package de.intevation.flys.jfree; 1 package de.intevation.flys.jfree;
2 2
3 import org.apache.log4j.Logger; 3 import org.apache.log4j.Logger;
4 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 5
33 /** 6 /**
34 * Custom Annotations class that is drawn only if no collisions with other 7 * Custom Annotations class that is drawn only if no collisions with other
35 * already drawn CustomAnnotations in current plot are found. A mark on 8 * already drawn CustomAnnotations in current plot are found. A mark on
36 * the axis is shown in all cases, though. 9 * the axis is shown in all cases, though.
37 * Draws a given text and a line to it from either axis. 10 * Draws a given text and a line to it from either axis.
38 */ 11 */
39 public class StickyAxisAnnotation extends XYTextAnnotation { 12 public class StickyAxisAnnotation {
40 13
41 /** Logger for this class. */ 14 /** Logger for this class. */
42 private static Logger logger = 15 private static Logger logger =
43 Logger.getLogger(StickyAxisAnnotation.class); 16 Logger.getLogger(StickyAxisAnnotation.class);
44 17
52 protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS; 25 protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS;
53 26
54 /** The 1-dimensional position of this annotation. */ 27 /** The 1-dimensional position of this annotation. */
55 protected float pos; 28 protected float pos;
56 29
57 /** Theme attributes. */ 30 String text;
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 31
81 /** 32 /**
82 * Constructor with implicit sticky x-axis. 33 * Constructor with implicit sticky x-axis.
83 * @param text the text to display. 34 * @param text the text to display.
84 * @param pos the position at which to draw the text and mark. 35 * @param pos the position at which to draw the text and mark.
85 */ 36 */
86 public StickyAxisAnnotation(String text, float pos) { 37 public StickyAxisAnnotation(String text, float pos) {
87 this(text, pos, pos, SimpleAxis.X_AXIS); 38 this(text, pos, SimpleAxis.X_AXIS);
88 } 39 }
89 40
90 41
91 /** 42 /**
92 * Constructor with given explicit axis. 43 * Constructor with given explicit axis.
93 * @param text the text to display. 44 * @param text the text to display.
94 * @param pos the position at which to draw the text and mark. 45 * @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 46 * @param stickyAxis the axis at which to stick (and to which 'pos' is
96 * relative). 47 * relative).
48 * @param lineTo upto where to draw a line (NaN for none).
97 */ 49 */
98 public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis) { 50 public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis
99 super(text, pos, pos); 51 ) {
100 setStickyAxis(stickAxis); 52 setStickyAxis(stickAxis);
101 this.pos = pos; 53 this.text = text;
102 } 54 this.pos = pos;
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 } 55 }
115 56
116 57
117 /** 58 /**
118 * Sets the "sticky axis" (whether to draw annotations at the 59 * Sets the "sticky axis" (whether to draw annotations at the
120 * 61 *
121 * @param stickyAxis axis to stick to. 62 * @param stickyAxis axis to stick to.
122 */ 63 */
123 public void setStickyAxis(SimpleAxis stickyAxis) { 64 public void setStickyAxis(SimpleAxis stickyAxis) {
124 this.stickyAxis = stickyAxis; 65 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 } 66 }
139 67
140 68
141 /** 69 public float getPos() {
142 * Draws a small line at axis where this annotation resides. 70 return this.pos;
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 } 71 }
227 72
228 73 public SimpleAxis getStickyAxis() {
229 /** 74 return this.stickyAxis;
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 } 75 }
347 76
77 public boolean atX() {
78 return this.getStickyAxis() == SimpleAxis.X_AXIS;
79 }
348 80
349 public void applyTheme(ThemeAccess ta) { 81 public String getText() {
350 lineWidth = ta.parseLineWidth(); 82 return this.text;
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 } 83 }
358 } 84 }
359 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : 85 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org