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

http://dive4elements.wald.intevation.org