felix@1038: package de.intevation.flys.exports; felix@1038: felix@1038: import org.apache.log4j.Logger; felix@1038: felix@1038: import java.util.Iterator; felix@1038: felix@1038: import java.awt.Shape; felix@1038: import java.awt.geom.Rectangle2D; felix@1038: import java.awt.geom.Line2D; felix@1038: felix@1038: import org.jfree.chart.annotations.XYTextAnnotation; felix@1038: import org.jfree.chart.axis.ValueAxis; felix@1038: import org.jfree.chart.util.LineUtilities; felix@1038: import org.jfree.text.TextUtilities; felix@1038: import org.jfree.chart.plot.PlotOrientation; felix@1038: import org.jfree.chart.plot.XYPlot; felix@1038: import org.jfree.chart.entity.XYAnnotationEntity; felix@1038: import org.jfree.chart.plot.PlotRenderingInfo; felix@1038: import org.jfree.chart.ChartRenderingInfo; felix@1038: import org.jfree.chart.plot.Plot; felix@1038: felix@1038: import org.jfree.ui.RectangleEdge; felix@1038: felix@1038: felix@1038: /** felix@1038: * Custom Annotations class that is drawn only if no collisions with other felix@1038: * already drawn CustomAnnotations in current plot are found. felix@1038: * Draws a given text and a line to it from either axis. felix@1038: */ felix@1038: class StickyAxisAnnotation extends XYTextAnnotation { felix@1038: felix@1038: /** Logger for this class. */ felix@1038: private static Logger logger = felix@1038: Logger.getLogger(StickyAxisAnnotation.class); felix@1038: felix@1038: /** Simplified view on axes. */ felix@1038: public static enum SimpleAxis { felix@1038: X_AXIS, /** Usually "horizontal". */ felix@1038: Y_AXIS /** Usually "vertical". */ felix@1038: } felix@1038: felix@1038: /** Which axis to stick to. */ felix@1038: protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS; felix@1038: felix@1038: felix@1038: /** felix@1038: * Trivial constructor. felix@1038: * felix@1038: * @param text Text to display. felix@1038: * @param x X-position in dataspace (typical horizontal, in km). felix@1038: * @param y Y-position in dataspace (typical vertical, in m). felix@1038: */ felix@1038: public StickyAxisAnnotation(String text, float x, float y) { felix@1038: super(text, x, y); felix@1038: } felix@1038: felix@1038: felix@1038: /** felix@1038: * Sets the "sticky axis" (whether to draw annotations at the felix@1038: * X- or the Y-Axis. felix@1038: * felix@1038: * @param stickyAxis axis to stick to. felix@1038: */ felix@1038: public void setStickyAxis(SimpleAxis stickyAxis) { felix@1038: this.stickyAxis = stickyAxis; felix@1038: } felix@1038: felix@1038: felix@1038: /** felix@1038: * Draws a small line at axis where this annotation resides. felix@1038: * felix@1038: * @param g2 the graphics device. felix@1038: * @param dataArea the data area. felix@1038: * @param domainAxis the domain axis. felix@1038: * @param rangeAxis the range axis. felix@1038: * @param domainEdge the domain edge. felix@1038: * @param rangeEdge the range edge. felix@1038: * @param orientation the plot orientation. felix@1038: */ felix@1038: protected void drawAxisMark( felix@1038: java.awt.Graphics2D g2, felix@1038: java.awt.geom.Rectangle2D dataArea, felix@1038: ValueAxis domainAxis, felix@1038: ValueAxis rangeAxis, felix@1038: RectangleEdge domainEdge, felix@1038: RectangleEdge rangeEdge, felix@1038: PlotOrientation orientation) { felix@1038: float j2DX1 = 0.0f; felix@1038: float j2DX2 = 0.0f; felix@1038: float j2DY1 = 0.0f; felix@1038: float j2DY2 = 0.0f; felix@1038: float x = (float) getX(); felix@1038: float y = (float) getY(); felix@1038: /* When dependent on X/Y-Axis and orientation, following felix@1038: can be used as a base: felix@1038: if (orientation == PlotOrientation.VERTICAL) { felix@1038: j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, felix@1038: domainEdge); felix@1038: j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea, felix@1038: rangeEdge); felix@1038: j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea, felix@1038: domainEdge); felix@1038: j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea, felix@1038: rangeEdge); felix@1038: } felix@1038: else if (orientation == PlotOrientation.HORIZONTAL) { felix@1038: j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea, felix@1038: domainEdge); felix@1038: j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea, felix@1038: rangeEdge); felix@1038: j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea, felix@1038: domainEdge); felix@1038: j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea, felix@1038: rangeEdge); felix@1038: } felix@1038: felix@1038: g2.setPaint(this.paint); felix@1038: g2.setStroke(this.stroke); felix@1038: */ felix@1038: j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge); felix@1038: j2DY2 = j2DY1 - 0.10f * (float) felix@1038: (rangeAxis.getRange().getUpperBound() felix@1038: - rangeAxis.getRange().getLowerBound()); felix@1038: j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge); felix@1038: j2DX2 = j2DX1; felix@1038: felix@1038: Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2); felix@1038: felix@1038: // line is clipped to avoid JRE bug 6574155, for more info felix@1038: // see JFreeChart bug 2221495 felix@1038: boolean visible = LineUtilities.clipLine(line, dataArea); felix@1038: if (visible) { felix@1038: g2.draw(line); felix@1038: } felix@1038: } felix@1038: felix@1038: felix@1038: /** felix@1038: * Draw the Annotiation if it does not collide with other already drawn felix@1038: * Annotations. felix@1038: * felix@1038: * @param g2 the graphics device. felix@1038: * @param plot the plot. felix@1038: * @param dataArea the data area. felix@1038: * @param domainAxis the domain axis. felix@1038: * @param rangeAxis the range axis. felix@1038: * @param rendererIndex the render index. felix@1038: * @param info state information, escpecially collects info about felix@1038: * already drawn shapes (and thus annotations), used felix@1038: * for collision detection. felix@1038: */ felix@1038: @Override felix@1038: public void draw( felix@1038: java.awt.Graphics2D g2, felix@1038: XYPlot plot, felix@1038: java.awt.geom.Rectangle2D dataArea, felix@1038: ValueAxis domainAxis, felix@1038: ValueAxis rangeAxis, felix@1038: int rendererIndex, felix@1038: PlotRenderingInfo info) { felix@1038: felix@1038: if (info == null) felix@1038: return; felix@1038: felix@1038: // Calculate the bounding box. felix@1038: ChartRenderingInfo chartInfo = info.getOwner(); felix@1038: felix@1038: PlotOrientation orientation = plot.getOrientation(); felix@1038: RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( felix@1038: plot.getDomainAxisLocation(), orientation); felix@1038: RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( felix@1038: plot.getRangeAxisLocation(), orientation); felix@1038: float anchorX = (float) domainAxis.valueToJava2D( felix@1038: getX(), dataArea, domainEdge); felix@1038: float anchorY = (float) rangeAxis.valueToJava2D( felix@1038: getY(), dataArea, rangeEdge); felix@1038: if (orientation == PlotOrientation.HORIZONTAL) { felix@1038: float tempAnchor = anchorX; felix@1038: anchorX = anchorY; felix@1038: anchorY = tempAnchor; felix@1038: } felix@1038: felix@1038: // Always draw the small line at axis. felix@1038: drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge, felix@1038: rangeEdge, orientation); felix@1038: felix@1038: g2.setFont(getFont()); felix@1038: Shape hotspot = TextUtilities.calculateRotatedStringBounds( felix@1038: getText(), g2, anchorX, anchorY, getTextAnchor(), felix@1038: getRotationAngle(), getRotationAnchor()); felix@1038: Rectangle2D hotspotBox = hotspot.getBounds2D(); felix@1038: // Check for collisions with other XYAnnotations. felix@1038: for (Iterator i = chartInfo.getEntityCollection().iterator(); felix@1038: i.hasNext(); ) { felix@1038: Object next = i.next(); felix@1038: // Collision with other stuff than XYAnnotations are okay. felix@1038: if (next instanceof XYAnnotationEntity) { felix@1038: XYAnnotationEntity drawnShape = (XYAnnotationEntity) next; felix@1038: if (drawnShape.getArea().intersects(hotspotBox)) { felix@1038: // Found collision, early stop. felix@1038: return; felix@1038: } felix@1038: } felix@1038: } felix@1038: felix@1038: // Actuall drawing. felix@1038: if (getBackgroundPaint() != null) { felix@1038: g2.setPaint(getBackgroundPaint()); felix@1038: g2.fill(hotspot); felix@1038: } felix@1038: g2.setPaint(getPaint()); felix@1038: TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY, felix@1038: getTextAnchor(), getRotationAngle(), getRotationAnchor()); felix@1038: // Draw outline. felix@1038: if (false) { felix@1038: g2.setStroke(getOutlineStroke()); felix@1038: g2.setPaint(getOutlinePaint()); felix@1038: g2.draw(hotspot); felix@1038: } felix@1038: felix@1038: // Add info that we have drawn this Annotation. felix@1038: addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL()); felix@1038: } felix@1038: } felix@1038: felix@1038: