Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java @ 1037:75cf1b11c97e
Improved CustomAnnotation rendering.
flys-artifacts/trunk@2498 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Wed, 17 Aug 2011 12:32:26 +0000 |
parents | e6aff80b59ff |
children | 4dcc635d6ca6 |
comparison
equal
deleted
inserted
replaced
1036:e6aff80b59ff | 1037:75cf1b11c97e |
---|---|
6 | 6 |
7 import org.apache.log4j.Logger; | 7 import org.apache.log4j.Logger; |
8 | 8 |
9 import java.awt.Shape; | 9 import java.awt.Shape; |
10 import java.awt.geom.Rectangle2D; | 10 import java.awt.geom.Rectangle2D; |
11 import java.awt.geom.Line2D; | |
11 | 12 |
12 import org.jfree.chart.annotations.XYLineAnnotation; | 13 import org.jfree.chart.annotations.XYLineAnnotation; |
13 import org.jfree.chart.annotations.XYTextAnnotation; | 14 import org.jfree.chart.annotations.XYTextAnnotation; |
14 import org.jfree.chart.JFreeChart; | 15 import org.jfree.chart.JFreeChart; |
15 import org.jfree.chart.axis.NumberAxis; | 16 import org.jfree.chart.axis.NumberAxis; |
24 import org.jfree.chart.entity.XYAnnotationEntity; | 25 import org.jfree.chart.entity.XYAnnotationEntity; |
25 import org.jfree.chart.plot.PlotOrientation; | 26 import org.jfree.chart.plot.PlotOrientation; |
26 import org.jfree.ui.RectangleEdge; | 27 import org.jfree.ui.RectangleEdge; |
27 import org.jfree.chart.plot.Plot; | 28 import org.jfree.chart.plot.Plot; |
28 import org.jfree.chart.ChartRenderingInfo; | 29 import org.jfree.chart.ChartRenderingInfo; |
30 import org.jfree.chart.util.LineUtilities; | |
29 | 31 |
30 import org.w3c.dom.Document; | 32 import org.w3c.dom.Document; |
31 | 33 |
32 import de.intevation.artifacts.Artifact; | 34 import de.intevation.artifacts.Artifact; |
33 | 35 |
39 import de.intevation.flys.artifacts.model.WQKms; | 41 import de.intevation.flys.artifacts.model.WQKms; |
40 | 42 |
41 import de.intevation.flys.model.Annotation; | 43 import de.intevation.flys.model.Annotation; |
42 | 44 |
43 /** | 45 /** |
44 * Custom annotations class that is drawn only if no collisions with other | 46 * Custom Annotations class that is drawn only if no collisions with other |
45 * already drawn CustomAnnotations in current plot are found. | 47 * already drawn CustomAnnotations in current plot are found. |
48 * Draws a given text and a line to it from either axis. | |
46 */ | 49 */ |
47 class CustomAnnotation extends XYTextAnnotation{ | 50 class CustomAnnotation extends XYTextAnnotation { |
51 | |
52 /** Logger for this class. */ | |
53 private static Logger logger = | |
54 Logger.getLogger(CustomAnnotation.class); | |
55 | |
56 /** Simplified view on axes. */ | |
57 public static enum SimpleAxis { | |
58 X_AXIS, /** Usually "horizontal". */ | |
59 Y_AXIS /** Usually "vertical". */ | |
60 } | |
61 | |
62 /** Which axis to stick to. */ | |
63 protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS; | |
64 | |
48 | 65 |
49 /** | 66 /** |
50 * Trivial constructor. | 67 * Trivial constructor. |
51 * | 68 * |
52 * @param text Text to display. | 69 * @param text Text to display. |
53 * @param x X-position in dataspace (typical horizontal, in km). | 70 * @param x X-position in dataspace (typical horizontal, in km). |
54 * @param y Y-position in dataspace (typical vertical, in m). | 71 * @param y Y-position in dataspace (typical vertical, in m). |
55 */ | 72 */ |
56 public CustomAnnotation(String text, float x, float y) { | 73 public CustomAnnotation(String text, float x, float y) { |
57 super(text, x, y); | 74 super(text, x, y); |
75 } | |
76 | |
77 | |
78 /** | |
79 * Sets the "sticky axis" (whether to draw annotations at the | |
80 * X- or the Y-Axis. | |
81 * | |
82 * @param stickyAxis axis to stick to. | |
83 */ | |
84 public void setStickyAxis(SimpleAxis stickyAxis) { | |
85 this.stickyAxis = stickyAxis; | |
86 } | |
87 | |
88 | |
89 /** | |
90 * Draws a small line at axis where this annotation resides. | |
91 * | |
92 * @param g2 the graphics device. | |
93 * @param dataArea the data area. | |
94 * @param domainAxis the domain axis. | |
95 * @param rangeAxis the range axis. | |
96 * @param domainEdge the domain edge. | |
97 * @param rangeEdge the range edge. | |
98 * @param orientation the plot orientation. | |
99 */ | |
100 protected void drawAxisMark( | |
101 java.awt.Graphics2D g2, | |
102 java.awt.geom.Rectangle2D dataArea, | |
103 ValueAxis domainAxis, | |
104 ValueAxis rangeAxis, | |
105 RectangleEdge domainEdge, | |
106 RectangleEdge rangeEdge, | |
107 PlotOrientation orientation) { | |
108 float j2DX1 = 0.0f; | |
109 float j2DX2 = 0.0f; | |
110 float j2DY1 = 0.0f; | |
111 float j2DY2 = 0.0f; | |
112 float x = (float) getX(); | |
113 float y = (float) getY(); | |
114 /* When dependent on X/Y-Axis and orientation, following | |
115 can be used as a base: | |
116 if (orientation == PlotOrientation.VERTICAL) { | |
117 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, | |
118 domainEdge); | |
119 j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea, | |
120 rangeEdge); | |
121 j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea, | |
122 domainEdge); | |
123 j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea, | |
124 rangeEdge); | |
125 } | |
126 else if (orientation == PlotOrientation.HORIZONTAL) { | |
127 j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea, | |
128 domainEdge); | |
129 j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea, | |
130 rangeEdge); | |
131 j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea, | |
132 domainEdge); | |
133 j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea, | |
134 rangeEdge); | |
135 } | |
136 | |
137 g2.setPaint(this.paint); | |
138 g2.setStroke(this.stroke); | |
139 */ | |
140 j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge); | |
141 j2DY2 = j2DY1 - 0.10f * (float) | |
142 (rangeAxis.getRange().getUpperBound() | |
143 - rangeAxis.getRange().getLowerBound()); | |
144 j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge); | |
145 j2DX2 = j2DX1; | |
146 | |
147 Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2); | |
148 | |
149 // line is clipped to avoid JRE bug 6574155, for more info | |
150 // see JFreeChart bug 2221495 | |
151 boolean visible = LineUtilities.clipLine(line, dataArea); | |
152 if (visible) { | |
153 g2.draw(line); | |
154 } | |
58 } | 155 } |
59 | 156 |
60 | 157 |
61 /** | 158 /** |
62 * Draw the Annotiation if it does not collide with other already drawn | 159 * Draw the Annotiation if it does not collide with other already drawn |
83 PlotRenderingInfo info) { | 180 PlotRenderingInfo info) { |
84 | 181 |
85 if (info == null) | 182 if (info == null) |
86 return; | 183 return; |
87 | 184 |
88 // Calculate bounding box as in super.draw(). | 185 // Calculate the bounding box. |
89 // TODO overwrite draw such that even if the annotation gets painted | |
90 // the bounding box has to be calculated only once. | |
91 ChartRenderingInfo chartInfo = info.getOwner(); | 186 ChartRenderingInfo chartInfo = info.getOwner(); |
92 | 187 |
93 PlotOrientation orientation = plot.getOrientation(); | 188 PlotOrientation orientation = plot.getOrientation(); |
94 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( | 189 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( |
95 plot.getDomainAxisLocation(), orientation); | 190 plot.getDomainAxisLocation(), orientation); |
96 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( | 191 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( |
97 plot.getRangeAxisLocation(), orientation); | 192 plot.getRangeAxisLocation(), orientation); |
98 float anchorX = (float) domainAxis.valueToJava2D( | 193 float anchorX = (float) domainAxis.valueToJava2D( |
99 getX(), dataArea, domainEdge); | 194 getX(), dataArea, domainEdge); |
100 float anchorY = (float) rangeAxis.valueToJava2D( | 195 float anchorY = (float) rangeAxis.valueToJava2D( |
101 getY(), dataArea, rangeEdge); | 196 getY(), dataArea, rangeEdge); |
102 if (orientation == PlotOrientation.HORIZONTAL) { | 197 if (orientation == PlotOrientation.HORIZONTAL) { |
103 float tempAnchor = anchorX; | 198 float tempAnchor = anchorX; |
104 anchorX = anchorY; | 199 anchorX = anchorY; |
105 anchorY = tempAnchor; | 200 anchorY = tempAnchor; |
106 } | 201 } |
107 | 202 |
203 // Always draw the small line at axis. | |
204 drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge, | |
205 rangeEdge, orientation); | |
206 | |
207 g2.setFont(getFont()); | |
108 Shape hotspot = TextUtilities.calculateRotatedStringBounds( | 208 Shape hotspot = TextUtilities.calculateRotatedStringBounds( |
109 getText(), g2, anchorX, anchorY, getTextAnchor(), | 209 getText(), g2, anchorX, anchorY, getTextAnchor(), |
110 getRotationAngle(), getRotationAnchor()); | 210 getRotationAngle(), getRotationAnchor()); |
111 Rectangle2D hotspotBox = hotspot.getBounds2D(); | 211 Rectangle2D hotspotBox = hotspot.getBounds2D(); |
112 | |
113 // Check for collisions with other XYAnnotations. | 212 // Check for collisions with other XYAnnotations. |
114 for (Iterator i = chartInfo.getEntityCollection().iterator(); | 213 for (Iterator i = chartInfo.getEntityCollection().iterator(); |
115 i.hasNext(); ) { | 214 i.hasNext(); ) { |
116 Object next = i.next(); | 215 Object next = i.next(); |
117 // Collision with other stuff than XYAnnotations are okay. | 216 // Collision with other stuff than XYAnnotations are okay. |
122 return; | 221 return; |
123 } | 222 } |
124 } | 223 } |
125 } | 224 } |
126 | 225 |
127 // Set URL of current annotation. This will let super.draw() add | 226 // Actuall drawing. |
128 // the relevant info to the PlotRenderingInfo. | 227 if (getBackgroundPaint() != null) { |
129 setURL(""); | 228 g2.setPaint(getBackgroundPaint()); |
130 super.draw(g2, plot, dataArea, domainAxis, rangeAxis, rendererIndex, info); | 229 g2.fill(hotspot); |
230 } | |
231 g2.setPaint(getPaint()); | |
232 TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY, | |
233 getTextAnchor(), getRotationAngle(), getRotationAnchor()); | |
234 // Draw outline. | |
235 if (false) { | |
236 g2.setStroke(getOutlineStroke()); | |
237 g2.setPaint(getOutlinePaint()); | |
238 g2.draw(hotspot); | |
239 } | |
240 | |
241 // Add info that we have drawn this Annotation. | |
242 addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL()); | |
131 } | 243 } |
132 } | 244 } |
133 | 245 |
134 | 246 |
135 /** | 247 /** |
139 */ | 251 */ |
140 public class LongitudinalSectionGenerator | 252 public class LongitudinalSectionGenerator |
141 extends XYChartGenerator | 253 extends XYChartGenerator |
142 implements FacetTypes | 254 implements FacetTypes |
143 { | 255 { |
144 /** The logger that is used in this generator.*/ | 256 /** The logger that is used in this generator. */ |
145 private static Logger logger = | 257 private static Logger logger = |
146 Logger.getLogger(LongitudinalSectionGenerator.class); | 258 Logger.getLogger(LongitudinalSectionGenerator.class); |
147 | 259 |
148 public static final String I18N_CHART_TITLE = | 260 public static final String I18N_CHART_TITLE = |
149 "chart.longitudinal.section.title"; | 261 "chart.longitudinal.section.title"; |
236 | 348 |
237 | 349 |
238 /** | 350 /** |
239 * Remove all annotations from plot and re-insert them at an approximately | 351 * Remove all annotations from plot and re-insert them at an approximately |
240 * okay position. The followed approach is naive but side-effect free. | 352 * okay position. The followed approach is naive but side-effect free. |
353 * | |
354 * @param plot the plot. | |
355 * @param axis the value axis. | |
241 */ | 356 */ |
242 protected void redoAnnotations(XYPlot plot, ValueAxis axis) { | 357 protected void redoAnnotations(XYPlot plot, ValueAxis axis) { |
243 plot.clearAnnotations(); | 358 plot.clearAnnotations(); |
359 // TODO Position calculation could/should be done in | |
360 // the CustomAnnotation-Implementation itself. | |
244 ValueAxis yAxis = plot.getRangeAxis(); | 361 ValueAxis yAxis = plot.getRangeAxis(); |
245 float posY = 140.f; | 362 float posY = 140.f; |
246 if (yAxis != null) { | 363 if (yAxis != null) { |
247 posY = (float) yAxis.getRange().getLowerBound(); | 364 posY = (float) yAxis.getRange().getLowerBound(); |
248 // Lets add some (1%) space between Text and Axis . | 365 posYLess = posY; |
249 posY += 0.1f * (yAxis.getRange().getUpperBound() | 366 // Add some (2%) space between Text and axis. |
367 posY += 0.02f * (yAxis.getRange().getUpperBound() | |
250 - yAxis.getRange().getLowerBound()); | 368 - yAxis.getRange().getLowerBound()); |
251 } | 369 } |
252 | 370 |
253 // Add all annotations. | 371 // Add all annotations. |
254 for (Annotation a: annotations) { | 372 for (Annotation a: annotations) { |
259 double rotation = 270.0f * (Math.PI / 180.0f); | 377 double rotation = 270.0f * (Math.PI / 180.0f); |
260 ta.setRotationAngle(rotation); | 378 ta.setRotationAngle(rotation); |
261 ta.setRotationAnchor(TextAnchor.CENTER_LEFT); | 379 ta.setRotationAnchor(TextAnchor.CENTER_LEFT); |
262 ta.setTextAnchor(TextAnchor.CENTER_LEFT); | 380 ta.setTextAnchor(TextAnchor.CENTER_LEFT); |
263 plot.getRenderer().addAnnotation(ta); | 381 plot.getRenderer().addAnnotation(ta); |
264 // TODO Merge XYLineAnnotation and CustomAnnotation. | |
265 XYLineAnnotation la = new XYLineAnnotation(posX, 0, posX, posY); | |
266 plot.getRenderer().addAnnotation(la); | |
267 } | 382 } |
268 } | 383 } |
269 | 384 |
270 | 385 |
271 /** | 386 /** |
330 return; | 445 return; |
331 } | 446 } |
332 } | 447 } |
333 | 448 |
334 | 449 |
450 /** | |
451 * Register annotations available for the diagram. | |
452 * | |
453 * @param o list of annotations (data of facet). | |
454 * @param theme ignored. | |
455 */ | |
335 protected void doAnnotationsOut(Object o, Document theme) { | 456 protected void doAnnotationsOut(Object o, Document theme) { |
336 logger.debug("LongitudinalSectionGenerator.doAnnotationsOut"); | 457 logger.debug("LongitudinalSectionGenerator.doAnnotationsOut"); |
337 this.annotations = (List<Annotation>) o; | 458 this.annotations = (List<Annotation>) o; |
338 } | 459 } |
339 | 460 |