I haven't tested it yet but the problems existed in the "1.0.0-pre2" and in I haven't seen anything about them in the changes.txt:
(I'll join the code & explain after having listed and described the problems)
- Plot shapes scale
- LegendTitle plot shape scales
- refreshTicks(...) in PeriodAxis class
- get/set the dateFormater in DateTickUnit and use it in DateAxis to auto generate new Ticks...
- Is InterpolatedXYItemRenderer class present in this release ?
2. Same goes than for the LegendTitle plot shape scales (not matching the plot's shapes' size !
3. The PeriodAxis class doesn't or did not have code for "refreshTicks" method... thus not returning any tick marks (I must confess I haven't been to the CVS to see if this was solved or not... I'll nevertheless include the code I've come up with based on other similar classes - where it is not absolutly correct, it serves my purpose and solves my problem)
4. This is very usefull if you need to generate some charts with different language settings, for example in batch mode : The charts are not all generated using the machine's locale and thus there should be a possibility to overide it and still auto generate the tick units and not fix them.
5. This would be a very nice thing to have in the api, not a class that you have to join (as an extra) to the library.
All the code added or modified by me is tagged with
// Added ##-##-#### LEROYSE
(The classname is in bold followed by the methods modified (if I haven't forgotten any...)
--------------------------------------------------------------------------------------
StandardXYItemRenderer.java
instance variable
getItemShape(row, col)
getLegendItem(datasetIndex, series)
setShapeScale(double scale)
Code: Select all
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------------
* StandardXYItemRenderer.java
* ---------------------------
* (C) Copyright 2001-2005, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): Mark Watson (www.markwatson.com);
* Jonathan Nash;
* Andreas Schneider;
* Norbert Kiesel (for TBD Networks);
* Christian W. Zuckschwerdt;
* Bill Kelemen;
* Nicolas Brodu (for Astrium and EADS Corporate Research
* Center);
*
* $Id: StandardXYItemRenderer.java,v 1.10 2005/03/10 11:23:55 mungady Exp $
*
* Changes:
* --------
* 19-Oct-2001 : Version 1, based on code by Mark Watson (DG);
* 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG);
* 21-Dec-2001 : Added working line instance to improve performance (DG);
* 22-Jan-2002 : Added code to lock crosshairs to data points. Based on code
* by Jonathan Nash (DG);
* 23-Jan-2002 : Added DrawInfo parameter to drawItem() method (DG);
* 28-Mar-2002 : Added a property change listener mechanism so that the
* renderer no longer needs to be immutable (DG);
* 02-Apr-2002 : Modified to handle null values (DG);
* 09-Apr-2002 : Modified draw method to return void. Removed the translated
* zero from the drawItem method. Override the initialise()
* method to calculate it (DG);
* 13-May-2002 : Added code from Andreas Schneider to allow changing
* shapes/colors per item (DG);
* 24-May-2002 : Incorporated tooltips into chart entities (DG);
* 25-Jun-2002 : Removed redundant code (DG);
* 05-Aug-2002 : Incorporated URLs for HTML image maps into chart entities (RA);
* 08-Aug-2002 : Added discontinuous lines option contributed by
* Norbert Kiesel (DG);
* 20-Aug-2002 : Added user definable default values to be returned by
* protected methods unless overridden by a subclass (DG);
* 23-Sep-2002 : Updated for changes in the XYItemRenderer interface (DG);
* 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 25-Mar-2003 : Implemented Serializable (DG);
* 01-May-2003 : Modified drawItem(...) method signature (DG);
* 15-May-2003 : Modified to take into account the plot orientation (DG);
* 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG);
* 30-Jul-2003 : Modified entity constructor (CZ);
* 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
* 24-Aug-2003 : Added null/NaN checks in drawItem (BK);
* 08-Sep-2003 : Fixed serialization (NB);
* 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
* 21-Jan-2004 : Override for getLegendItem() method (DG);
* 27-Jan-2004 : Moved working line into state object (DG);
* 10-Feb-2004 : Changed drawItem() method to make cut-and-paste overriding
* easier (DG);
* 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState. Renamed
* XYToolTipGenerator --> XYItemLabelGenerator (DG);
* 08-Jun-2004 : Modified to use getX() and getY() methods (DG);
* 15-Jul-2004 : Switched getX() with getXValue() and getY() with
* getYValue() (DG);
* 25-Aug-2004 : Created addEntity() method in superclass (DG);
* 08-Oct-2004 : Added 'gapThresholdType' as suggested by Mike Watts (DG);
* 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG);
* 23-Feb-2005 : Fixed getLegendItem() method to show lines. Fixed bug
* 1077108 (shape not visible for first item in series) (DG);
*
*/
package org.jfree.chart.renderer.xy;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import org.jfree.chart.LegendItem;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.CrosshairState;
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.urls.XYURLGenerator;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.util.BooleanList;
import org.jfree.util.BooleanUtilities;
import org.jfree.util.ObjectUtilities;
import org.jfree.util.PublicCloneable;
import org.jfree.util.ShapeUtilities;
import org.jfree.util.UnitType;
/**
* Standard item renderer for an {@link XYPlot}. This class can draw (a)
* shapes at each point, or (b) lines between points, or (c) both shapes and
* lines.
*/
public class StandardXYItemRenderer extends AbstractXYItemRenderer
implements XYItemRenderer,
Cloneable,
PublicCloneable,
Serializable {
/** Constant for the type of rendering (shapes only). */
public static final int SHAPES = 1;
/** Constant for the type of rendering (lines only). */
public static final int LINES = 2;
/** Constant for the type of rendering (shapes and lines). */
public static final int SHAPES_AND_LINES = SHAPES | LINES;
/** Constant for the type of rendering (images only). */
public static final int IMAGES = 4;
/** Constant for the type of rendering (discontinuous lines). */
public static final int DISCONTINUOUS = 8;
/** Constant for the type of rendering (discontinuous lines). */
public static final int DISCONTINUOUS_LINES = LINES | DISCONTINUOUS;
/** A flag indicating whether or not shapes are drawn at each XY point. */
private boolean plotShapes;
/** A flag indicating whether or not lines are drawn between XY points. */
private boolean plotLines;
/** A flag indicating whether or not images are drawn between XY points. */
private boolean plotImages;
/** A flag controlling whether or not discontinuous lines are used. */
private boolean plotDiscontinuous;
/** Specifies how the gap threshold value is interpreted. */
private UnitType gapThresholdType = UnitType.RELATIVE;
/** Threshold for deciding when to discontinue a line. */
private double gapThreshold = 1.0;
/** A flag that controls whether or not shapes are filled for ALL series. */
private Boolean shapesFilled;
/**
* A table of flags that control (per series) whether or not shapes are
* filled.
*/
private BooleanList seriesShapesFilled;
/** The default value returned by the getShapeFilled() method. */
private Boolean defaultShapesFilled;
/**
* A flag that controls whether or not each series is drawn as a single
* path.
*/
private boolean drawSeriesLineAsPath;
//XXX added 17-05-2005 LEROYSE
private double shapeScale = 1D;
/**
* Constructs a new renderer.
*/
public StandardXYItemRenderer() {
this(LINES, null);
}
/**
* Constructs a new renderer.
* <p>
* To specify the type of renderer, use one of the constants: SHAPES, LINES
* or SHAPES_AND_LINES.
*
* @param type the type.
*/
public StandardXYItemRenderer(int type) {
this(type, null);
}
/**
* Constructs a new renderer.
* <p>
* To specify the type of renderer, use one of the constants: SHAPES, LINES
* or SHAPES_AND_LINES.
*
* @param type the type of renderer.
* @param toolTipGenerator the item label generator (<code>null</code>
* permitted).
*/
public StandardXYItemRenderer(int type,
XYToolTipGenerator toolTipGenerator) {
this(type, toolTipGenerator, null);
}
/**
* Constructs a new renderer.
* <p>
* To specify the type of renderer, use one of the constants: SHAPES, LINES
* or SHAPES_AND_LINES.
*
* @param type the type of renderer.
* @param toolTipGenerator the item label generator (<code>null</code>
* permitted).
* @param urlGenerator the URL generator.
*/
public StandardXYItemRenderer(int type,
XYToolTipGenerator toolTipGenerator,
XYURLGenerator urlGenerator) {
super();
setToolTipGenerator(toolTipGenerator);
setURLGenerator(urlGenerator);
if ((type & SHAPES) != 0) {
this.plotShapes = true;
}
if ((type & LINES) != 0) {
this.plotLines = true;
}
if ((type & IMAGES) != 0) {
this.plotImages = true;
}
if ((type & DISCONTINUOUS) != 0) {
this.plotDiscontinuous = true;
}
this.shapesFilled = null;
this.seriesShapesFilled = new BooleanList();
this.defaultShapesFilled = Boolean.TRUE;
this.drawSeriesLineAsPath = false;
}
/**
* Returns true if shapes are being plotted by the renderer.
*
* @return <code>true</code> if shapes are being plotted by the renderer.
*/
public boolean getDefaultShapesVisible() {
return this.plotShapes;
}
/**
* Sets the flag that controls whether or not a shape is plotted at each
* data point.
*
* @param flag the flag.
*/
public void setDefaultShapesVisible(boolean flag) {
if (this.plotShapes != flag) {
this.plotShapes = flag;
notifyListeners(new RendererChangeEvent(this));
}
}
/**
* Returns true if shapes are being plotted by the renderer.
*
* @return <code>true</code> if shapes are being plotted by the renderer.
*/
public boolean getPlotShapes() {
return this.plotShapes;
}
/**
* Sets the flag that controls whether or not a shape is plotted at each
* data point.
*
* @param flag the flag.
*/
public void setPlotShapes(boolean flag) {
if (this.plotShapes != flag) {
this.plotShapes = flag;
notifyListeners(new RendererChangeEvent(this));
}
}
// SHAPES FILLED
/**
* Returns the flag used to control whether or not the shape for an item is
* filled.
* <p>
* The default implementation passes control to the
* <code>getSeriesShapesFilled</code> method. You can override this method
* if you require different behaviour.
*
* @param series the series index (zero-based).
* @param item the item index (zero-based).
*
* @return A boolean.
*/
public boolean getItemShapeFilled(int series, int item) {
return getSeriesShapesFilled(series);
}
/**
* Returns the flag used to control whether or not the shapes for a series
* are filled.
*
* @param series the series index (zero-based).
*
* @return A boolean.
*/
public boolean getSeriesShapesFilled(int series) {
// return the overall setting, if there is one...
if (this.shapesFilled != null) {
return this.shapesFilled.booleanValue();
}
// otherwise look up the paint table
Boolean flag = this.seriesShapesFilled.getBoolean(series);
if (flag != null) {
return flag.booleanValue();
}
else {
return this.defaultShapesFilled.booleanValue();
}
}
/* (non-Javadoc)
* @see org.jfree.chart.renderer.xy.XYItemRenderer#getItemShape(int, int)
*/
public Shape getItemShape(int row, int column)
{
Shape result = super.getItemShape(row, column);
//XXX added 01-03-2005 leroyse
AffineTransform transformer = new AffineTransform();
transformer.setToScale(shapeScale, shapeScale);
return transformer.createTransformedShape(result);
}
//XXX added 17-05-2005 LEROYSE
/**
* Method setShapeScale.
*
* @param scale
*/
public void setShapeScale(double scale)
{
this.shapeScale = scale;
}
/**
* Sets the 'shapes filled' for ALL series.
*
* @param filled the flag.
*/
public void setShapesFilled(boolean filled) {
// here we use BooleanUtilities to remain compatible with JDKs < 1.4
setShapesFilled(BooleanUtilities.valueOf(filled));
}
/**
* Sets the 'shapes filled' for ALL series.
*
* @param filled the flag (<code>null</code> permitted).
*/
public void setShapesFilled(Boolean filled) {
this.shapesFilled = filled;
}
/**
* Sets the 'shapes filled' flag for a series.
*
* @param series the series index (zero-based).
* @param flag the flag.
*/
public void setSeriesShapesFilled(int series, Boolean flag) {
this.seriesShapesFilled.setBoolean(series, flag);
}
/**
* Returns the default 'shape filled' attribute.
*
* @return The default flag.
*/
public Boolean getDefaultShapesFilled() {
return this.defaultShapesFilled;
}
/**
* Sets the default 'shapes filled' flag.
*
* @param flag the flag.
*/
public void setDefaultShapesFilled(Boolean flag) {
this.defaultShapesFilled = flag;
}
/**
* Returns true if lines are being plotted by the renderer.
*
* @return <code>true</code> if lines are being plotted by the renderer.
*/
public boolean getPlotLines() {
return this.plotLines;
}
/**
* Sets the flag that controls whether or not a line is plotted between
* each data point.
*
* @param flag the flag.
*/
public void setPlotLines(boolean flag) {
if (this.plotLines != flag) {
this.plotLines = flag;
notifyListeners(new RendererChangeEvent(this));
}
}
/**
* Returns the gap threshold type (relative or absolute).
*
* @return The type.
*/
public UnitType getGapThresholdType() {
return this.gapThresholdType;
}
/**
* Sets the gap threshold type.
*
* @param thresholdType the type (<code>null</code> not permitted).
*/
public void setGapThresholdType(UnitType thresholdType) {
if (thresholdType == null) {
throw new IllegalArgumentException(
"Null 'thresholdType' argument."
);
}
this.gapThresholdType = thresholdType;
notifyListeners(new RendererChangeEvent(this));
}
/**
* Returns the gap threshold for discontinuous lines.
*
* @return The gap threshold.
*/
public double getGapThreshold() {
return this.gapThreshold;
}
/**
* Sets the gap threshold for discontinuous lines.
*
* @param t the threshold.
*/
public void setGapThreshold(double t) {
this.gapThreshold = t;
notifyListeners(new RendererChangeEvent(this));
}
/**
* Returns true if images are being plotted by the renderer.
*
* @return <code>true</code> if images are being plotted by the renderer.
*/
public boolean getPlotImages() {
return this.plotImages;
}
/**
* Sets the flag that controls whether or not an image is drawn at each
* data point.
*
* @param flag the flag.
*/
public void setPlotImages(boolean flag) {
if (this.plotImages != flag) {
this.plotImages = flag;
notifyListeners(new RendererChangeEvent(this));
}
}
/**
* Returns true if lines should be discontinuous.
*
* @return <code>true</code> if lines should be discontinuous.
*/
public boolean getPlotDiscontinuous() {
return this.plotDiscontinuous;
}
/**
* Returns a flag that controls whether or not each series is drawn as a
* single path.
*
* @return A boolean.
*/
public boolean getDrawSeriesLineAsPath() {
return this.drawSeriesLineAsPath;
}
/**
* Sets the flag that controls whether or not each series is drawn as a
* single path.
*
* @param flag the flag.
*/
public void setDrawSeriesLineAsPath(boolean flag) {
this.drawSeriesLineAsPath = flag;
}
/**
* Returns a legend item for a series.
*
* @param datasetIndex the dataset index (zero-based).
* @param series the series index (zero-based).
*
* @return A legend item for the series.
*/
public LegendItem getLegendItem(int datasetIndex, int series) {
LegendItem result = null;
XYPlot plot = getPlot();
if (plot != null) {
XYDataset dataset = plot.getDataset(datasetIndex);
if (dataset != null) {
if (getItemVisible(series, 0)) {
String label = dataset.getSeriesName(series);
String description = label;
//XXX added 17-05-2005 LEROYSE
AffineTransform transformer = new AffineTransform();
transformer.setToScale(shapeScale, shapeScale);
Shape shape = transformer.createTransformedShape(getSeriesShape(series));
boolean shapeFilled = getSeriesShapesFilled(series);
Paint paint = getSeriesPaint(series);
Paint outlinePaint = getSeriesOutlinePaint(series);
Stroke outlineStroke = getSeriesOutlineStroke(series);
Paint linePaint = paint;
Stroke lineStroke = getSeriesStroke(series);
result = new LegendItem(
label, description, this.plotShapes, shape, shapeFilled,
paint, true, outlinePaint, outlineStroke,
this.plotLines,
new Line2D.Float(-7.0f, 0.0f, 7.0f, 0.0f),
lineStroke, linePaint
);
}
}
}
return result;
}
/**
* Records the state for the renderer. This is used to preserve state
* information between calls to the drawItem() method for a single chart
* drawing.
*/
public static class State extends XYItemRendererState {
/** The path for the current series. */
public GeneralPath seriesPath;
/** A flag that indicates if the last (x, y) point was 'good' (non-null). */
private boolean lastPointGood;
/**
* Creates a new state instance.
*
* @param info the plot rendering info.
*/
public State(PlotRenderingInfo info) {
super(info);
}
/**
* Returns a flag that indicates if the last point drawn (in the current series)
* was 'good' (non-null).
*
* @return A boolean.
*/
public boolean isLastPointGood() {
return this.lastPointGood;
}
/**
* Sets a flag that indicates if the last point drawn (in the current series)
* was 'good' (non-null).
*
* @param good the flag.
*/
public void setLastPointGood(boolean good) {
this.lastPointGood = good;
}
}
/**
* Initialises the renderer.
* <P>
* This method will be called before the first item is rendered, giving the
* renderer an opportunity to initialise any state information it wants to
* maintain. The renderer can do nothing if it chooses.
*
* @param g2 the graphics device.
* @param dataArea the area inside the axes.
* @param plot the plot.
* @param data the data.
* @param info an optional info collection object to return data back to
* the caller.
*
* @return The renderer state.
*/
public XYItemRendererState initialise(Graphics2D g2,
Rectangle2D dataArea,
XYPlot plot,
XYDataset data,
PlotRenderingInfo info) {
State state = new State(info);
state.seriesPath = new GeneralPath();
return state;
}
/**
* Draws the visual representation of a single data item.
*
* @param g2 the graphics device.
* @param state the renderer state.
* @param dataArea the area within which the data is being drawn.
* @param info collects information about the drawing.
* @param plot the plot (can be used to obtain standard color information
* etc).
* @param domainAxis the domain axis.
* @param rangeAxis the range axis.
* @param dataset the dataset.
* @param series the series index (zero-based).
* @param item the item index (zero-based).
* @param crosshairState crosshair information for the plot
* (<code>null</code> permitted).
* @param pass the pass index.
*/
public void drawItem(Graphics2D g2,
XYItemRendererState state,
Rectangle2D dataArea,
PlotRenderingInfo info,
XYPlot plot,
ValueAxis domainAxis,
ValueAxis rangeAxis,
XYDataset dataset,
int series,
int item,
CrosshairState crosshairState,
int pass) {
if (!getItemVisible(series, item)) {
return;
}
// setup for collecting optional entity info...
Shape entityArea = null;
EntityCollection entities = null;
if (info != null) {
entities = info.getOwner().getEntityCollection();
}
PlotOrientation orientation = plot.getOrientation();
Paint paint = getItemPaint(series, item);
Stroke seriesStroke = getItemStroke(series, item);
g2.setPaint(paint);
g2.setStroke(seriesStroke);
// get the data point...
double x1 = dataset.getXValue(series, item);
double y1 = dataset.getYValue(series, item);
if (Double.isNaN(x1) || Double.isNaN(y1)) {
return;
}
RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
if (getPlotLines()) {
if (item == 0) {
if (this.drawSeriesLineAsPath) {
State s = (State) state;
s.seriesPath.reset();
s.lastPointGood = false;
}
}
if (this.drawSeriesLineAsPath) {
State s = (State) state;
// update path to reflect latest point
if (!Double.isNaN(transX1) && !Double.isNaN(transY1)) {
float x = (float) transX1;
float y = (float) transY1;
if (orientation == PlotOrientation.HORIZONTAL) {
x = (float) transY1;
y = (float) transX1;
}
if (s.isLastPointGood()) {
// TODO: check threshold
s.seriesPath.lineTo(x, y);
}
else {
s.seriesPath.moveTo(x, y);
}
s.setLastPointGood(true);
}
else {
s.setLastPointGood(false);
}
if (item == dataset.getItemCount(series) - 1) {
// draw path
g2.setStroke(getSeriesStroke(series));
g2.setPaint(getSeriesPaint(series));
g2.draw(s.seriesPath);
}
}
else if (item != 0) {
// get the previous data point...
double x0 = dataset.getXValue(series, item - 1);
double y0 = dataset.getYValue(series, item - 1);
if (!Double.isNaN(x0) && !Double.isNaN(y0)) {
boolean drawLine = true;
if (getPlotDiscontinuous()) {
// only draw a line if the gap between the current and
// previous data point is within the threshold
int numX = dataset.getItemCount(series);
double minX = dataset.getXValue(series, 0);
double maxX = dataset.getXValue(series, numX - 1);
if (this.gapThresholdType == UnitType.ABSOLUTE) {
drawLine = Math.abs(x1 - x0) <= this.gapThreshold;
}
else {
drawLine = Math.abs(x1 - x0) <= ((maxX - minX)
/ numX * getGapThreshold());
}
}
if (drawLine) {
double transX0 = domainAxis.valueToJava2D(
x0, dataArea, xAxisLocation
);
double transY0 = rangeAxis.valueToJava2D(
y0, dataArea, yAxisLocation
);
// only draw if we have good values
if (Double.isNaN(transX0) || Double.isNaN(transY0)
|| Double.isNaN(transX1) || Double.isNaN(transY1)) {
return;
}
if (orientation == PlotOrientation.HORIZONTAL) {
state.workingLine.setLine(
transY0, transX0, transY1, transX1
);
}
else if (orientation == PlotOrientation.VERTICAL) {
state.workingLine.setLine(
transX0, transY0, transX1, transY1
);
}
if (state.workingLine.intersects(dataArea)) {
g2.draw(state.workingLine);
}
}
}
}
}
if (getPlotShapes()) {
Shape shape = getItemShape(series, item);
if (orientation == PlotOrientation.HORIZONTAL) {
shape = ShapeUtilities.createTranslatedShape(
shape, transY1, transX1
);
}
else if (orientation == PlotOrientation.VERTICAL) {
shape = ShapeUtilities.createTranslatedShape(
shape, transX1, transY1
);
}
if (shape.intersects(dataArea)) {
if (getItemShapeFilled(series, item)) {
g2.fill(shape);
}
else {
g2.draw(shape);
}
}
entityArea = shape;
}
if (getPlotImages()) {
Image image = getImage(plot, series, item, transX1, transY1);
if (image != null) {
Point hotspot = getImageHotspot(
plot, series, item, transX1, transY1, image
);
g2.drawImage(
image, (int) (transX1 - hotspot.getX()),
(int) (transY1 - hotspot.getY()), null
);
entityArea = new Rectangle2D.Double(
transX1 - hotspot.getX(), transY1 - hotspot.getY(),
image.getWidth(null), image.getHeight(null)
);
}
}
// draw the item label if there is one...
if (isItemLabelVisible(series, item)) {
drawItemLabel(
g2, orientation, dataset, series, item, transX1, transY1,
(y1 < 0.0)
);
}
updateCrosshairValues(
crosshairState, x1, y1, transX1, transY1, orientation
);
// add an entity for the item...
if (entities != null) {
addEntity(
entities, entityArea, dataset, series, item, transX1, transY1
);
}
}
/**
* Tests this renderer for equality with another object.
*
* @param obj the object (<code>null</code> permitted).
*
* @return A boolean.
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof StandardXYItemRenderer)) {
return false;
}
if (!super.equals(obj)) {
return false;
}
StandardXYItemRenderer that = (StandardXYItemRenderer) obj;
if (this.plotShapes != that.plotShapes) {
return false;
}
if (this.plotLines != that.plotLines) {
return false;
}
if (this.plotImages != that.plotImages) {
return false;
}
if (this.plotDiscontinuous != that.plotDiscontinuous) {
return false;
}
if (this.gapThresholdType != that.gapThresholdType) {
return false;
}
if (this.gapThreshold != that.gapThreshold) {
return false;
}
if (!ObjectUtilities.equal(this.shapesFilled, that.shapesFilled)) {
return false;
}
return true;
}
/**
* Returns a clone of the renderer.
*
* @return A clone.
*
* @throws CloneNotSupportedException if the renderer cannot be cloned.
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
////////////////////////////////////////////////////////////////////////////
// PROTECTED METHODS
// These provide the opportunity to subclass the standard renderer and
// create custom effects.
////////////////////////////////////////////////////////////////////////////
/**
* Returns the image used to draw a single data item.
*
* @param plot the plot (can be used to obtain standard color information
* etc).
* @param series the series index.
* @param item the item index.
* @param x the x value of the item.
* @param y the y value of the item.
*
* @return The image.
*/
protected Image getImage(Plot plot, int series, int item,
double x, double y) {
// should this be added to the plot as well ?
// return plot.getShape(series, item, x, y, scale);
// or should this be left to the user - like this:
return null;
}
/**
* Returns the hotspot of the image used to draw a single data item.
* The hotspot is the point relative to the top left of the image
* that should indicate the data item. The default is the center of the
* image.
*
* @param plot the plot (can be used to obtain standard color information
* etc).
* @param image the image (can be used to get size information about the
* image)
* @param series the series index
* @param item the item index
* @param x the x value of the item
* @param y the y value of the item
*
* @return The hotspot used to draw the data item.
*/
protected Point getImageHotspot(Plot plot, int series, int item,
double x, double y, Image image) {
int height = image.getHeight(null);
int width = image.getWidth(null);
return new Point(width / 2, height / 2);
}
}
Constructor
Code: Select all
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ----------------
* LegendTitle.java
* ----------------
* (C) Copyright 2002-2005, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: LegendTitle.java,v 1.15 2005/03/17 22:40:46 mungady Exp $
*
* Changes
* -------
* 25-Nov-2004 : First working version (DG);
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
* 08-Feb-2005 : Updated for changes in RectangleConstraint class (DG);
* 11-Feb-2005 : Implemented PublicCloneable (DG);
* 23-Feb-2005 : Replaced chart reference with LegendItemSource (DG);
* 16-Mar-2005 : Added itemFont attribute (DG);
* 17-Mar-2005 : Fixed missing fillShape setting (DG);
*
*/
package org.jfree.chart.title;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.LegendItemSource;
import org.jfree.chart.block.Arrangement;
import org.jfree.chart.block.Block;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.BorderArrangement;
import org.jfree.chart.block.CenterArrangement;
import org.jfree.chart.block.ColumnArrangement;
import org.jfree.chart.block.FlowArrangement;
import org.jfree.chart.block.LabelBlock;
import org.jfree.chart.block.RectangleConstraint;
import org.jfree.chart.event.TitleChangeEvent;
import org.jfree.io.SerialUtilities;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.Size2D;
import org.jfree.util.ArrayUtilities;
import org.jfree.util.PaintUtilities;
import org.jfree.util.PublicCloneable;
/**
* A chart title that displays a legend for the data in the chart.
* <P>
* The title can be populated with legend items manually, or you can assign a
* reference to the plot, in which case the legend items will be automatically
* created to match the dataset(s).
*/
public class LegendTitle extends Title
implements Cloneable, PublicCloneable, Serializable {
/** The default item font. */
public static final Font DEFAULT_ITEM_FONT
= new Font("SansSerif", Font.PLAIN, 12);
/** The sources for legend items. */
private LegendItemSource[] sources;
/** The background paint (possibly <code>null</code>). */
private transient Paint backgroundPaint;
/** The edge for the legend item graphic relative to the text. */
private RectangleEdge legendItemGraphicEdge;
/** The anchor point for the legend item graphic. */
private RectangleAnchor legendItemGraphicAnchor;
/** The legend item graphic location. */
private RectangleAnchor legendItemGraphicLocation;
/** The item font. */
private Font itemFont;
/**
* A container that holds and displays the legend items.
*/
private BlockContainer items;
private Arrangement hLayout;
private Arrangement vLayout;
/**
* An optional container for wrapping the legend items (allows for adding
* a title or other text to the legend).
*/
private BlockContainer wrapper;
/**
* Constructs a new (empty) legend for the specified source.
*
* @param source the source.
*/
public LegendTitle(LegendItemSource source) {
this(source, new FlowArrangement(), new ColumnArrangement());
}
/**
* Creates a new legend title with the specified arrangement.
*
* @param source the source.
* @param hLayout the horizontal item arrangement (<code>null</code> not
* permitted).
* @param vLayout the vertical item arrangement (<code>null</code> not
* permitted).
*/
public LegendTitle(LegendItemSource source,
Arrangement hLayout, Arrangement vLayout) {
this.sources = new LegendItemSource[] {source};
this.items = new BlockContainer(hLayout);
//XXX added 17-05-2005 LEROYSE (modified to meet our standards)
this.hLayout = vLayout;
this.vLayout = vLayout;
this.backgroundPaint = null;
this.legendItemGraphicEdge = RectangleEdge.LEFT;
this.legendItemGraphicAnchor = RectangleAnchor.CENTER;
this.legendItemGraphicLocation = RectangleAnchor.CENTER;
this.itemFont = DEFAULT_ITEM_FONT;
}
/**
* Returns the legend item sources.
*
* @return The sources.
*/
public LegendItemSource[] getSources() {
return this.sources;
}
/**
* Sets the legend item sources.
*
* @param sources the sources.
*/
public void setSources(LegendItemSource[] sources) {
this.sources = sources;
notifyListeners(new TitleChangeEvent(this));
}
/**
* Returns the background paint.
*
* @return The background paint (possibly <code>null</code>).
*/
public Paint getBackgroundPaint() {
return this.backgroundPaint;
}
/**
* Sets the background paint for the legend.
*
* @param paint the paint (<code>null</code> permitted).
*/
public void setBackgroundPaint(Paint paint) {
this.backgroundPaint = paint;
}
/**
* Returns the location of the shape within each legend item.
*
* @return The location (never <code>null</code>).
*/
public RectangleEdge getLegendItemGraphicEdge() {
return this.legendItemGraphicEdge;
}
/**
* Sets the location of the shape within each legend item.
*
* @param edge the edge (<code>null</code> not permitted).
*/
public void setLegendItemGraphicEdge(RectangleEdge edge) {
if (edge == null) {
throw new IllegalArgumentException("Null 'edge' argument.");
}
this.legendItemGraphicEdge = edge;
}
/**
* Returns the legend item graphic anchor.
*
* @return The graphic anchor (never <code>null</code>).
*/
public RectangleAnchor getLegendItemGraphicAnchor() {
return this.legendItemGraphicAnchor;
}
/**
* Sets the anchor point used for the graphic in each legend item.
*
* @param anchor the anchor point (<code>null</code> not permitted).
*/
public void setLegendItemGraphicAnchor(RectangleAnchor anchor) {
if (anchor == null) {
throw new IllegalArgumentException("Null 'anchor' point.");
}
this.legendItemGraphicAnchor = anchor;
}
/**
* Returns the legend item graphic location.
*
* @return The location (never <code>null</code>).
*/
public RectangleAnchor getLegendItemGraphicLocation() {
return this.legendItemGraphicLocation;
}
/**
* Sets the legend item graphic location.
*
* @param anchor the anchor (<code>null</code> not permitted).
*/
public void setLegendItemGraphicLocation(RectangleAnchor anchor) {
this.legendItemGraphicLocation = anchor;
}
/**
* Returns the item font.
*
* @return The font (never <code>null</code>).
*/
public Font getItemFont() {
return this.itemFont;
}
/**
* Sets the item font.
*
* @param font the font (<code>null</code> not permitted).
*/
public void setItemFont(Font font) {
if (font == null) {
throw new IllegalArgumentException("Null 'font' argument.");
}
this.itemFont = font;
notifyListeners(new TitleChangeEvent(this));
}
/**
* Fetches the latest legend items.
*/
protected void fetchLegendItems() {
this.items.clear();
RectangleEdge p = getPosition();
if (RectangleEdge.isTopOrBottom(p)) {
this.items.setArrangement(this.hLayout);
}
else {
this.items.setArrangement(this.vLayout);
}
for (int s = 0; s < this.sources.length; s++) {
LegendItemCollection legendItems = this.sources[s].getLegendItems();
if (legendItems != null) {
for (int i = 0; i < legendItems.getItemCount(); i++) {
LegendItem item = legendItems.get(i);
Block block = createLegendItemBlock(item);
this.items.add(block);
}
}
}
}
/**
* Creates a legend item block.
*
* @param item the legend item.
*
* @return The block.
*/
protected Block createLegendItemBlock(LegendItem item) {
BlockContainer result = null;
LegendGraphic lg = new LegendGraphic(
item.getShape(), item.getFillPaint()
);
lg.setShapeFilled(item.isShapeFilled());
lg.setLine(item.getLine());
lg.setLineStroke(item.getLineStroke());
lg.setLinePaint(item.getLinePaint());
lg.setLineVisible(item.isLineVisible());
lg.setShapeVisible(item.isShapeVisible());
lg.setShapeOutlineVisible(item.isShapeOutlineVisible());
lg.setOutlinePaint(item.getOutlinePaint());
lg.setOutlineStroke(item.getOutlineStroke());
lg.setWidth(20.0);
lg.setHeight(12.0);
BlockContainer legendItem = new BlockContainer(new BorderArrangement());
lg.setShapeAnchor(this.legendItemGraphicAnchor);
lg.setShapeLocation(this.getLegendItemGraphicLocation());
legendItem.add(lg, this.legendItemGraphicEdge);
legendItem.add(new LabelBlock(item.getLabel(), this.itemFont));
result = new BlockContainer(new CenterArrangement());
result.add(legendItem);
return result;
}
/**
* Returns the container that holds the legend items.
*
* @return The container for the legend items.
*/
public BlockContainer getItemContainer() {
return this.items;
}
/**
* Arranges the contents of the block, within the given constraints, and
* returns the block size.
*
* @param g2 the graphics device.
* @param constraint the constraint (<code>null</code> not permitted).
*
* @return The block size (in Java2D units, never <code>null</code>).
*/
public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
Size2D result = new Size2D();
fetchLegendItems();
if (this.items.isEmpty()) {
return result;
}
BlockContainer container = this.wrapper;
if (container == null) {
container = this.items;
}
RectangleConstraint c = toContentConstraint(constraint);
Size2D size = container.arrange(g2, c);
result.height = calculateTotalHeight(size.height);
result.width = calculateTotalWidth(size.width);
return result;
}
/**
* Draws the title on a Java 2D graphics device (such as the screen or a
* printer).
*
* @param g2 the graphics device.
* @param area the available area for the title.
*/
public void draw(Graphics2D g2, Rectangle2D area) {
Rectangle2D target = (Rectangle2D) area.clone();
target = trimMargin(target);
if (this.backgroundPaint != null) {
g2.setPaint(this.backgroundPaint);
g2.fill(target);
}
getBorder().draw(g2, target);
getBorder().getInsets().trim(target);
BlockContainer container = this.wrapper;
if (container == null) {
container = this.items;
}
target = trimPadding(target);
container.draw(g2, target);
}
/**
* Sets the wrapper container for the legend.
*
* @param wrapper the wrapper container.
*/
public void setWrapper(BlockContainer wrapper) {
this.wrapper = wrapper;
}
/**
* Tests this title for equality with an arbitrary object.
*
* @param obj the object (<code>null</code> permitted).
*
* @return A boolean.
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof LegendTitle)) {
return false;
}
if (!super.equals(obj)) {
return false;
}
LegendTitle that = (LegendTitle) obj;
if (!ArrayUtilities.equalReferencesInArrays(
this.sources, that.sources)) {
return false;
}
if (!PaintUtilities.equal(this.backgroundPaint, that.backgroundPaint)) {
return false;
}
if (this.legendItemGraphicEdge != that.legendItemGraphicEdge) {
return false;
}
if (this.legendItemGraphicAnchor != that.legendItemGraphicAnchor) {
return false;
}
if (this.legendItemGraphicLocation != that.legendItemGraphicLocation) {
return false;
}
if (!this.itemFont.equals(that.itemFont)) {
return false;
}
if (!this.hLayout.equals(that.hLayout)) {
return false;
}
if (!this.vLayout.equals(that.vLayout)) {
return false;
}
return true;
}
/**
* Provides serialization support.
*
* @param stream the output stream.
*
* @throws IOException if there is an I/O error.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
SerialUtilities.writePaint(this.backgroundPaint, stream);
}
/**
* Provides serialization support.
*
* @param stream the input stream.
*
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
this.backgroundPaint = SerialUtilities.readPaint(stream);
}
}
refreshTicks()
Code: Select all
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------
* PeriodAxis.java
* ---------------
* (C) Copyright 2004, 2005, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: PeriodAxis.java,v 1.8 2005/03/04 11:53:51 mungady Exp $
*
* Changes
* -------
* 01-Jun-2004 : Version 1 (DG);
* 16-Sep-2004 : Fixed bug in equals() method, added clone() method and
* PublicCloneable interface (DG);
* 25-Nov-2004 : Updates to support major and minor tick marks (DG);
* 25-Feb-2005 : Fixed some tick mark bugs (DG);
*
*/
package org.jfree.chart.axis;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.jfree.chart.event.AxisChangeEvent;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.ValueAxisPlot;
import org.jfree.data.Range;
import org.jfree.data.time.Day;
import org.jfree.data.time.Month;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.Year;
import org.jfree.io.SerialUtilities;
import org.jfree.text.TextUtilities;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;
import org.jfree.util.Log;
import org.jfree.util.LogContext;
import org.jfree.util.PublicCloneable;
/**
* An axis that displays a date scale based on a
* {@link org.jfree.data.time.RegularTimePeriod}.
*/
public class PeriodAxis extends ValueAxis implements Cloneable, PublicCloneable, Serializable
{
/** The first time period in the overall range. */
private RegularTimePeriod first;
/** The last time period in the overall range. */
private RegularTimePeriod last;
/**
* The time zone used to convert 'first' and 'last' to absolute milliseconds.
*/
private TimeZone timeZone;
/**
* The {@link RegularTimePeriod}subclass used to automatically determine the
* axis range.
*/
private Class autoRangeTimePeriodClass;
/**
* Indicates the {@link RegularTimePeriod}subclass that is used to determine
* the spacing of the major tick marks.
*/
private Class majorTickTimePeriodClass;
/**
* A flag that indicates whether or not tick marks are visible for the axis.
*/
private boolean minorTickMarksVisible;
/**
* Indicates the {@link RegularTimePeriod}subclass that is used to determine
* the spacing of the minor tick marks.
*/
private Class minorTickTimePeriodClass;
/** The length of the tick mark inside the data area (zero permitted). */
private float minorTickMarkInsideLength = 0.0f;
/** The length of the tick mark outside the data area (zero permitted). */
private float minorTickMarkOutsideLength = 2.0f;
/** The stroke used to draw tick marks. */
private transient Stroke minorTickMarkStroke = new BasicStroke(0.5f);
/** The paint used to draw tick marks. */
private transient Paint minorTickMarkPaint = Color.black;
/** Info for each labelling band. */
private PeriodAxisLabelInfo[] labelInfo;
/** Access to logging facilities. */
private static final LogContext LOGGER = Log.createContext(PeriodAxis.class);
/**
* Creates a new axis.
*
* @param label
* the axis label.
*/
public PeriodAxis(String label)
{
this(label, new Day(), new Day());
}
/**
* Creates a new axis.
*
* @param label
* the axis label (<code>null</code> permitted).
* @param first
* the first time period in the axis range (<code>null</code> not
* permitted).
* @param last
* the last time period in the axis range (<code>null</code> not
* permitted).
*/
public PeriodAxis(String label, RegularTimePeriod first, RegularTimePeriod last)
{
this(label, first, last, TimeZone.getDefault());
}