# HG changeset patch # User Felix Wolfsteller # Date 1313584346 0 # Node ID 75cf1b11c97ede67994ac1782e27e5b643ab2a0b # Parent e6aff80b59ff42fb4860e69e854b9173c93f367a Improved CustomAnnotation rendering. flys-artifacts/trunk@2498 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r e6aff80b59ff -r 75cf1b11c97e flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Wed Aug 17 09:16:20 2011 +0000 +++ b/flys-artifacts/ChangeLog Wed Aug 17 12:32:26 2011 +0000 @@ -1,4 +1,14 @@ -2011-08-16 Felix Wolfsteller +2011-08-17 Felix Wolfsteller + + Improved CustomAnnotations and rendering thereof, now including an + "axis mark" (little line at axis), also prepared possibility to put + annotations on Y-axis. + + * src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java: + Improved CustomAnnotation to include marks on the axis and better spacing + from it. + +2011-08-17 Felix Wolfsteller Implemented proof-of-concept collision-detection when drawing CustomAnnotations (text only). diff -r e6aff80b59ff -r 75cf1b11c97e flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java Wed Aug 17 09:16:20 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java Wed Aug 17 12:32:26 2011 +0000 @@ -8,6 +8,7 @@ import java.awt.Shape; import java.awt.geom.Rectangle2D; +import java.awt.geom.Line2D; import org.jfree.chart.annotations.XYLineAnnotation; import org.jfree.chart.annotations.XYTextAnnotation; @@ -26,6 +27,7 @@ import org.jfree.ui.RectangleEdge; import org.jfree.chart.plot.Plot; import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.util.LineUtilities; import org.w3c.dom.Document; @@ -41,10 +43,25 @@ import de.intevation.flys.model.Annotation; /** - * Custom annotations class that is drawn only if no collisions with other + * Custom Annotations class that is drawn only if no collisions with other * already drawn CustomAnnotations in current plot are found. + * Draws a given text and a line to it from either axis. */ -class CustomAnnotation extends XYTextAnnotation{ +class CustomAnnotation extends XYTextAnnotation { + + /** Logger for this class. */ + private static Logger logger = + Logger.getLogger(CustomAnnotation.class); + + /** Simplified view on axes. */ + public static enum SimpleAxis { + X_AXIS, /** Usually "horizontal". */ + Y_AXIS /** Usually "vertical". */ + } + + /** Which axis to stick to. */ + protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS; + /** * Trivial constructor. @@ -59,6 +76,86 @@ /** + * Sets the "sticky axis" (whether to draw annotations at the + * X- or the Y-Axis. + * + * @param stickyAxis axis to stick to. + */ + public void setStickyAxis(SimpleAxis stickyAxis) { + this.stickyAxis = stickyAxis; + } + + + /** + * Draws a small line at axis where this annotation resides. + * + * @param g2 the graphics device. + * @param dataArea the data area. + * @param domainAxis the domain axis. + * @param rangeAxis the range axis. + * @param domainEdge the domain edge. + * @param rangeEdge the range edge. + * @param orientation the plot orientation. + */ + protected void drawAxisMark( + java.awt.Graphics2D g2, + java.awt.geom.Rectangle2D dataArea, + ValueAxis domainAxis, + ValueAxis rangeAxis, + RectangleEdge domainEdge, + RectangleEdge rangeEdge, + PlotOrientation orientation) { + float j2DX1 = 0.0f; + float j2DX2 = 0.0f; + float j2DY1 = 0.0f; + float j2DY2 = 0.0f; + float x = (float) getX(); + float y = (float) getY(); + /* When dependent on X/Y-Axis and orientation, following + can be used as a base: + if (orientation == PlotOrientation.VERTICAL) { + j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, + domainEdge); + j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea, + rangeEdge); + j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea, + domainEdge); + j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea, + rangeEdge); + } + else if (orientation == PlotOrientation.HORIZONTAL) { + j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea, + domainEdge); + j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea, + rangeEdge); + j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea, + domainEdge); + j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea, + rangeEdge); + } + + g2.setPaint(this.paint); + g2.setStroke(this.stroke); + */ + j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge); + j2DY2 = j2DY1 - 0.10f * (float) + (rangeAxis.getRange().getUpperBound() + - rangeAxis.getRange().getLowerBound()); + j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge); + j2DX2 = j2DX1; + + Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2); + + // line is clipped to avoid JRE bug 6574155, for more info + // see JFreeChart bug 2221495 + boolean visible = LineUtilities.clipLine(line, dataArea); + if (visible) { + g2.draw(line); + } + } + + + /** * Draw the Annotiation if it does not collide with other already drawn * Annotations. * @@ -85,16 +182,14 @@ if (info == null) return; - // Calculate bounding box as in super.draw(). - // TODO overwrite draw such that even if the annotation gets painted - // the bounding box has to be calculated only once. + // Calculate the bounding box. ChartRenderingInfo chartInfo = info.getOwner(); PlotOrientation orientation = plot.getOrientation(); RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( - plot.getDomainAxisLocation(), orientation); + plot.getDomainAxisLocation(), orientation); RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( - plot.getRangeAxisLocation(), orientation); + plot.getRangeAxisLocation(), orientation); float anchorX = (float) domainAxis.valueToJava2D( getX(), dataArea, domainEdge); float anchorY = (float) rangeAxis.valueToJava2D( @@ -103,13 +198,17 @@ float tempAnchor = anchorX; anchorX = anchorY; anchorY = tempAnchor; - } + } + // Always draw the small line at axis. + drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge, + rangeEdge, orientation); + + g2.setFont(getFont()); Shape hotspot = TextUtilities.calculateRotatedStringBounds( getText(), g2, anchorX, anchorY, getTextAnchor(), getRotationAngle(), getRotationAnchor()); Rectangle2D hotspotBox = hotspot.getBounds2D(); - // Check for collisions with other XYAnnotations. for (Iterator i = chartInfo.getEntityCollection().iterator(); i.hasNext(); ) { @@ -124,10 +223,23 @@ } } - // Set URL of current annotation. This will let super.draw() add - // the relevant info to the PlotRenderingInfo. - setURL(""); - super.draw(g2, plot, dataArea, domainAxis, rangeAxis, rendererIndex, info); + // Actuall drawing. + if (getBackgroundPaint() != null) { + g2.setPaint(getBackgroundPaint()); + g2.fill(hotspot); + } + g2.setPaint(getPaint()); + TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY, + getTextAnchor(), getRotationAngle(), getRotationAnchor()); + // Draw outline. + if (false) { + g2.setStroke(getOutlineStroke()); + g2.setPaint(getOutlinePaint()); + g2.draw(hotspot); + } + + // Add info that we have drawn this Annotation. + addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL()); } } @@ -141,7 +253,7 @@ extends XYChartGenerator implements FacetTypes { - /** The logger that is used in this generator.*/ + /** The logger that is used in this generator. */ private static Logger logger = Logger.getLogger(LongitudinalSectionGenerator.class); @@ -238,15 +350,21 @@ /** * Remove all annotations from plot and re-insert them at an approximately * okay position. The followed approach is naive but side-effect free. + * + * @param plot the plot. + * @param axis the value axis. */ protected void redoAnnotations(XYPlot plot, ValueAxis axis) { plot.clearAnnotations(); + // TODO Position calculation could/should be done in + // the CustomAnnotation-Implementation itself. ValueAxis yAxis = plot.getRangeAxis(); float posY = 140.f; if (yAxis != null) { posY = (float) yAxis.getRange().getLowerBound(); - // Lets add some (1%) space between Text and Axis . - posY += 0.1f * (yAxis.getRange().getUpperBound() + posYLess = posY; + // Add some (2%) space between Text and axis. + posY += 0.02f * (yAxis.getRange().getUpperBound() - yAxis.getRange().getLowerBound()); } @@ -261,9 +379,6 @@ ta.setRotationAnchor(TextAnchor.CENTER_LEFT); ta.setTextAnchor(TextAnchor.CENTER_LEFT); plot.getRenderer().addAnnotation(ta); - // TODO Merge XYLineAnnotation and CustomAnnotation. - XYLineAnnotation la = new XYLineAnnotation(posX, 0, posX, posY); - plot.getRenderer().addAnnotation(la); } } @@ -332,6 +447,12 @@ } + /** + * Register annotations available for the diagram. + * + * @param o list of annotations (data of facet). + * @param theme ignored. + */ protected void doAnnotationsOut(Object o, Document theme) { logger.debug("LongitudinalSectionGenerator.doAnnotationsOut"); this.annotations = (List) o;