1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
  6. *
  7. * Project Info: http://www.jfree.org/jfreechart/index.html
  8. *
  9. * This library is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation; either version 2.1 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  17. * License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this library; if not, write to the Free Software Foundation,
  21. * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  22. *
  23. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  24. * in the United States and other countries.]
  25. *
  26. * -----------------
  27. * AreaRenderer.java
  28. * -----------------
  29. * (C) Copyright 2002-2005, by Jon Iles and Contributors.
  30. *
  31. * Original Author: Jon Iles;
  32. * Contributor(s): David Gilbert (for Object Refinery Limited);
  33. * Christian W. Zuckschwerdt;
  34. *
  35. * $Id: AreaRenderer.java,v 1.4 2005/03/09 22:09:05 mungady Exp $
  36. *
  37. * Changes:
  38. * --------
  39. * 21-May-2002 : Version 1, contributed by John Iles (DG);
  40. * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG);
  41. * 11-Jun-2002 : Updated Javadoc comments (DG);
  42. * 25-Jun-2002 : Removed unnecessary imports (DG);
  43. * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  44. * 10-Oct-2002 : Added constructors and basic entity support (DG);
  45. * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
  46. * CategoryToolTipGenerator interface (DG);
  47. * 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
  48. * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis
  49. * for category spacing. Renamed AreaCategoryItemRenderer
  50. * --> AreaRenderer (DG);
  51. * 17-Jan-2003 : Moved plot classes into a separate package (DG);
  52. * 25-Mar-2003 : Implemented Serializable (DG);
  53. * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in
  54. * drawItem() method (DG);
  55. * 12-May-2003 : Modified to take into account the plot orientation (DG);
  56. * 30-Jul-2003 : Modified entity constructor (CZ);
  57. * 13-Aug-2003 : Implemented Cloneable (DG);
  58. * 07-Oct-2003 : Added renderer state (DG);
  59. * 05-Nov-2004 : Modified drawItem() signature (DG);
  60. *
  61. */
  62. package org.jfree.chart.renderer.category;
  63. import java.awt.Graphics2D;
  64. import java.awt.Paint;
  65. import java.awt.Shape;
  66. import java.awt.Stroke;
  67. import java.awt.geom.GeneralPath;
  68. import java.awt.geom.Rectangle2D;
  69. import java.io.Serializable;
  70. import org.jfree.chart.LegendItem;
  71. import org.jfree.chart.axis.CategoryAxis;
  72. import org.jfree.chart.axis.ValueAxis;
  73. import org.jfree.chart.entity.CategoryItemEntity;
  74. import org.jfree.chart.entity.EntityCollection;
  75. import org.jfree.chart.event.RendererChangeEvent;
  76. import org.jfree.chart.labels.CategoryToolTipGenerator;
  77. import org.jfree.chart.plot.CategoryPlot;
  78. import org.jfree.chart.plot.PlotOrientation;
  79. import org.jfree.chart.renderer.AreaRendererEndType;
  80. import org.jfree.data.category.CategoryDataset;
  81. import org.jfree.ui.RectangleEdge;
  82. import org.jfree.util.PublicCloneable;
  83. /**
  84. * A category item renderer that draws area charts. You can use this renderer
  85. * with the {@link org.jfree.chart.plot.CategoryPlot} class.
  86. *
  87. * @author Jon Iles
  88. */
  89. public class AreaRenderer extends AbstractCategoryItemRenderer
  90. implements Cloneable, PublicCloneable, Serializable {
  91. /** A flag that controls how the ends of the areas are drawn. */
  92. private AreaRendererEndType endType;
  93. /**
  94. * Creates a new renderer.
  95. */
  96. public AreaRenderer() {
  97. super();
  98. this.endType = AreaRendererEndType.TAPER;
  99. }
  100. /**
  101. * Returns a token that controls how the renderer draws the end points.
  102. *
  103. * @return The end type (never <code>null</code>).
  104. */
  105. public AreaRendererEndType getEndType() {
  106. return this.endType;
  107. }
  108. /**
  109. * Sets a token that controls how the renderer draws the end points, and
  110. * sends a {@link RendererChangeEvent} to all registered listeners.
  111. *
  112. * @param type the end type (<code>null</code> not permitted).
  113. */
  114. public void setEndType(AreaRendererEndType type) {
  115. if (type == null) {
  116. throw new IllegalArgumentException("Null 'type' argument.");
  117. }
  118. this.endType = type;
  119. notifyListeners(new RendererChangeEvent(this));
  120. }
  121. /**
  122. * Returns a legend item for a series.
  123. *
  124. * @param datasetIndex the dataset index (zero-based).
  125. * @param series the series index (zero-based).
  126. *
  127. * @return The legend item.
  128. */
  129. public LegendItem getLegendItem(int datasetIndex, int series) {
  130. CategoryPlot cp = getPlot();
  131. if (cp == null) {
  132. return null;
  133. }
  134. CategoryDataset dataset;
  135. dataset = cp.getDataset(datasetIndex);
  136. String label = dataset.getRowKey(series).toString();
  137. String description = label;
  138. Shape shape = new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0);
  139. Paint paint = getSeriesPaint(series);
  140. Paint outlinePaint = getSeriesOutlinePaint(series);
  141. Stroke outlineStroke = getSeriesOutlineStroke(series);
  142. return new LegendItem(
  143. label, description, shape, paint, outlineStroke, outlinePaint
  144. );
  145. }
  146. /**
  147. * Draw a single data item.
  148. *
  149. * @param g2 the graphics device.
  150. * @param state the renderer state.
  151. * @param dataArea the data plot area.
  152. * @param plot the plot.
  153. * @param domainAxis the domain axis.
  154. * @param rangeAxis the range axis.
  155. * @param dataset the dataset.
  156. * @param row the row index (zero-based).
  157. * @param column the column index (zero-based).
  158. * @param pass the pass index.
  159. */
  160. public void drawItem(Graphics2D g2,
  161. CategoryItemRendererState state,
  162. Rectangle2D dataArea,
  163. CategoryPlot plot,
  164. CategoryAxis domainAxis,
  165. ValueAxis rangeAxis,
  166. CategoryDataset dataset,
  167. int row,
  168. int column,
  169. int pass) {
  170. // plot non-null values only...
  171. Number value = dataset.getValue(row, column);
  172. if (value != null) {
  173. PlotOrientation orientation = plot.getOrientation();
  174. RectangleEdge axisEdge = plot.getDomainAxisEdge();
  175. int count = dataset.getColumnCount();
  176. float x0 = (float) domainAxis.getCategoryStart(
  177. column, count, dataArea, axisEdge
  178. );
  179. float x1 = (float) domainAxis.getCategoryMiddle(
  180. column, count, dataArea, axisEdge
  181. );
  182. float x2 = (float) domainAxis.getCategoryEnd(
  183. column, count, dataArea, axisEdge
  184. );
  185. x0 = Math.round(x0);
  186. x1 = Math.round(x1);
  187. x2 = Math.round(x2);
  188. if (this.endType == AreaRendererEndType.TRUNCATE) {
  189. if (column == 0) {
  190. x0 = x1;
  191. }
  192. else if (column == getColumnCount() - 1) {
  193. x2 = x1;
  194. }
  195. }
  196. double yy1 = value.doubleValue();
  197. double yy0 = 0.0;
  198. if (column > 0) {
  199. Number n0 = dataset.getValue(row, column - 1);
  200. if (n0 != null) {
  201. yy0 = (n0.doubleValue() + yy1) / 2.0;
  202. }
  203. }
  204. double yy2 = 0.0;
  205. if (column < dataset.getColumnCount() - 1) {
  206. Number n2 = dataset.getValue(row, column + 1);
  207. if (n2 != null) {
  208. yy2 = (n2.doubleValue() + yy1) / 2.0;
  209. }
  210. }
  211. RectangleEdge edge = plot.getRangeAxisEdge();
  212. float y0 = (float) rangeAxis.valueToJava2D(yy0, dataArea, edge);
  213. float y1 = (float) rangeAxis.valueToJava2D(yy1, dataArea, edge);
  214. float y2 = (float) rangeAxis.valueToJava2D(yy2, dataArea, edge);
  215. float yz = (float) rangeAxis.valueToJava2D(0.0, dataArea, edge);
  216. g2.setPaint(getItemPaint(row, column));
  217. g2.setStroke(getItemStroke(row, column));
  218. GeneralPath area = new GeneralPath();
  219. if (orientation == PlotOrientation.VERTICAL) {
  220. area.moveTo(x0, yz);
  221. area.lineTo(x0, y0);
  222. area.lineTo(x1, y1);
  223. area.lineTo(x2, y2);
  224. area.lineTo(x2, yz);
  225. }
  226. else if (orientation == PlotOrientation.HORIZONTAL) {
  227. area.moveTo(yz, x0);
  228. area.lineTo(y0, x0);
  229. area.lineTo(y1, x1);
  230. area.lineTo(y2, x2);
  231. area.lineTo(yz, x2);
  232. }
  233. area.closePath();
  234. g2.setPaint(getItemPaint(row, column));
  235. g2.fill(area);
  236. // draw the item labels if there are any...
  237. if (isItemLabelVisible(row, column)) {
  238. drawItemLabel(
  239. g2, orientation, dataset, row, column, x1, y1,
  240. (value.doubleValue() < 0.0)
  241. );
  242. }
  243. // collect entity and tool tip information...
  244. if (state.getInfo() != null) {
  245. EntityCollection entities
  246. = state.getInfo().getOwner().getEntityCollection();
  247. if (entities != null) {
  248. String tip = null;
  249. CategoryToolTipGenerator generator
  250. = getToolTipGenerator(row, column);
  251. if (generator != null) {
  252. tip = generator.generateToolTip(dataset, row, column);
  253. }
  254. String url = null;
  255. if (getItemURLGenerator(row, column) != null) {
  256. url = getItemURLGenerator(row, column).generateURL(
  257. dataset, row, column
  258. );
  259. }
  260. Comparable columnKey = dataset.getColumnKey(column);
  261. CategoryItemEntity entity = new CategoryItemEntity(
  262. area, tip, url, dataset, row, columnKey, column
  263. );
  264. entities.add(entity);
  265. }
  266. }
  267. }
  268. }
  269. /**
  270. * Returns an independent copy of the renderer.
  271. *
  272. * @return A clone.
  273. *
  274. * @throws CloneNotSupportedException should not happen.
  275. */
  276. public Object clone() throws CloneNotSupportedException {
  277. return super.clone();
  278. }
  279. }