All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jfree.chart.annotations.XYInversePointerAnnotation Maven / Gradle / Ivy

Go to download

JFreeChart is a class library, written in Java, for generating charts. Utilising the Java2D API, it supports a wide range of chart types including bar charts, pie charts, line charts, XY-plots, time series plots, Sankey charts and more.

There is a newer version: 1.5.5
Show newest version
/* ===========================================================
 * JFreeChart : a free chart library for the Java(tm) platform
 * ===========================================================
 *
 * (C) Copyright 2000-present, by David Gilbert and Contributors.
 *
 * Project Info:  http://www.jfree.org/jfreechart/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
 * Other names may be trademarks of their respective owners.]
 *
 * ------------------------
 * XYInversePointerAnnotation.java
 * ------------------------
 * (C) Copyright 2021-present, by Yuri Blankenstein and Contributors.
 *
 * Original Author:  Yuri Blankenstein (for ESI TNO);
 *
 */
package org.jfree.chart.annotations;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;

import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.util.GeomUtil;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.text.TextUtils;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.chart.util.PublicCloneable;

/**
 * An arrow and label that can be placed on an {@link XYPlot}. The arrow is
 * drawn at a user-definable angle but points towards the label of the
 * annotation.
 * 

* The arrow length (and its offset from the (x, y) location) is controlled by * the tip radius and the base radius attributes. Imagine two circles around the * (x, y) coordinate: the inner circle defined by the tip radius, and the outer * circle defined by the base radius. Now, draw the arrow starting at some point * on the outer circle (the point is determined by the angle), with the arrow * tip being drawn at a corresponding point on the inner circle. */ public class XYInversePointerAnnotation extends XYPointerAnnotation implements Cloneable, PublicCloneable, Serializable { /** For serialization. */ private static final long serialVersionUID = -4031161445009858551L; /** The default dot radius (in Java2D units). */ public static final double DEFAULT_DOT_RADIUS = 0; /** The radius of the dot at the start of the arrow. */ private double dotRadius; /** * Creates a new label and arrow annotation. * * @param label the label ({@code null} permitted). * @param x the x-coordinate (measured against the chart's domain axis). * @param y the y-coordinate (measured against the chart's range axis). * @param angle the angle of the arrow's line (in radians). */ public XYInversePointerAnnotation(String label, double x, double y, double angle) { super(label, x, y, angle); this.dotRadius = DEFAULT_DOT_RADIUS; } /** * Returns the radius of the dot at the start of the arrow. * * @return the radius of the dot at the start of the arrow * @see #setDotRadius(double) */ public double getDotRadius() { return dotRadius; } /** * Sets the radius of the dot at the start of the arrow, ≤ 0 will omit * the dot. * * @param dotRadius the radius of the dot at the start of the arrow * @see #getDotRadius() */ public void setDotRadius(double dotRadius) { this.dotRadius = dotRadius; fireAnnotationChanged(); } /** * Draws the annotation. * * @param g2 the graphics device. * @param plot the plot. * @param dataArea the data area. * @param domainAxis the domain axis. * @param rangeAxis the range axis. * @param rendererIndex the renderer index. * @param info the plot rendering info. */ @Override public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int rendererIndex, PlotRenderingInfo info) { PlotOrientation orientation = plot.getOrientation(); RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( plot.getDomainAxisLocation(), orientation); RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( plot.getRangeAxisLocation(), orientation); double j2DX = domainAxis.valueToJava2D(getX(), dataArea, domainEdge); double j2DY = rangeAxis.valueToJava2D(getY(), dataArea, rangeEdge); if (orientation == PlotOrientation.HORIZONTAL) { double temp = j2DX; j2DX = j2DY; j2DY = temp; } double startX = j2DX + Math.cos(getAngle()) * getBaseRadius(); double startY = j2DY + Math.sin(getAngle()) * getBaseRadius(); double endX = j2DX + Math.cos(getAngle()) * getTipRadius(); double endY = j2DY + Math.sin(getAngle()) * getTipRadius(); // Already calculate the label bounds to adjust the start point double labelX = j2DX + Math.cos(getAngle()) * (getBaseRadius() + getLabelOffset()); double labelY = j2DY + Math.sin(getAngle()) * (getBaseRadius() + getLabelOffset()); Shape hotspot = TextUtils.calculateRotatedStringBounds(getText(), g2, (float) labelX, (float) labelY, getTextAnchor(), getRotationAngle(), getRotationAnchor()); Point2D[] pointOnLabelBounds = GeomUtil.calculateIntersectionPoints( new Line2D.Double(startX, startY, endX, endY), GeomUtil.getLines(hotspot, null)); if (pointOnLabelBounds.length > 0) { // Adjust the start point to the intersection with the label bounds startX = pointOnLabelBounds[0].getX(); startY = pointOnLabelBounds[0].getY(); } double arrowBaseX = startX - Math.cos(getAngle()) * getArrowLength(); double arrowBaseY = startY - Math.sin(getAngle()) * getArrowLength(); double arrowLeftX = arrowBaseX + Math.cos(getAngle() + Math.PI / 2.0) * getArrowWidth(); double arrowLeftY = arrowBaseY + Math.sin(getAngle() + Math.PI / 2.0) * getArrowWidth(); double arrowRightX = arrowBaseX - Math.cos(getAngle() + Math.PI / 2.0) * getArrowWidth(); double arrowRightY = arrowBaseY - Math.sin(getAngle() + Math.PI / 2.0) * getArrowWidth(); GeneralPath arrow = new GeneralPath(); arrow.moveTo((float) startX, (float) startY); arrow.lineTo((float) arrowLeftX, (float) arrowLeftY); arrow.lineTo((float) arrowRightX, (float) arrowRightY); arrow.closePath(); g2.setStroke(getArrowStroke()); g2.setPaint(getArrowPaint()); Line2D line = new Line2D.Double(arrowBaseX, arrowBaseY, endX, endY); g2.draw(line); g2.fill(arrow); if (dotRadius > 0) { Ellipse2D.Double dot = new Ellipse2D.Double(endX - dotRadius, endY - dotRadius, 2 * dotRadius, 2 * dotRadius); g2.fill(dot); } // draw the label g2.setFont(getFont()); if (getBackgroundPaint() != null) { g2.setPaint(getBackgroundPaint()); g2.fill(hotspot); } g2.setPaint(getPaint()); TextUtils.drawRotatedString(getText(), g2, (float) labelX, (float) labelY, getTextAnchor(), getRotationAngle(), getRotationAnchor()); if (isOutlineVisible()) { g2.setStroke(getOutlineStroke()); g2.setPaint(getOutlinePaint()); g2.draw(hotspot); } String toolTip = getToolTipText(); String url = getURL(); if (toolTip != null || url != null) { addEntity(info, hotspot, rendererIndex, toolTip, url); } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); long temp; temp = Double.doubleToLongBits(dotRadius); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; XYInversePointerAnnotation other = (XYInversePointerAnnotation) obj; if (Double.doubleToLongBits(dotRadius) != Double .doubleToLongBits(other.dotRadius)) return false; return true; } /** * Returns a clone of the annotation. * * @return A clone. * * @throws CloneNotSupportedException if the annotation can't be cloned. */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy