1 80 81 package org.jfree.chart.renderer.category; 82 83 import java.awt.Color ; 84 import java.awt.Graphics2D ; 85 import java.awt.Paint ; 86 import java.awt.geom.GeneralPath ; 87 import java.awt.geom.Rectangle2D ; 88 import java.io.Serializable ; 89 90 import org.jfree.chart.axis.CategoryAxis; 91 import org.jfree.chart.axis.ValueAxis; 92 import org.jfree.chart.entity.EntityCollection; 93 import org.jfree.chart.event.RendererChangeEvent; 94 import org.jfree.chart.labels.CategoryItemLabelGenerator; 95 import org.jfree.chart.plot.CategoryPlot; 96 import org.jfree.chart.plot.PlotOrientation; 97 import org.jfree.data.DataUtilities; 98 import org.jfree.data.Range; 99 import org.jfree.data.category.CategoryDataset; 100 import org.jfree.data.general.DatasetUtilities; 101 import org.jfree.ui.RectangleEdge; 102 import org.jfree.util.PublicCloneable; 103 104 108 public class StackedBarRenderer3D extends BarRenderer3D 109 implements Cloneable , PublicCloneable, 110 Serializable { 111 112 113 private static final long serialVersionUID = -5832945916493247123L; 114 115 116 private boolean renderAsPercentages; 117 118 126 public StackedBarRenderer3D() { 127 this(false); 128 } 129 130 136 public StackedBarRenderer3D(double xOffset, double yOffset) { 137 super(xOffset, yOffset); 138 } 139 140 148 public StackedBarRenderer3D(boolean renderAsPercentages) { 149 super(); 150 this.renderAsPercentages = renderAsPercentages; 151 } 152 153 163 public StackedBarRenderer3D(double xOffset, double yOffset, 164 boolean renderAsPercentages) { 165 super(xOffset, yOffset); 166 this.renderAsPercentages = renderAsPercentages; 167 } 168 169 178 public boolean getRenderAsPercentages() { 179 return this.renderAsPercentages; 180 } 181 182 191 public void setRenderAsPercentages(boolean asPercentages) { 192 this.renderAsPercentages = asPercentages; 193 notifyListeners(new RendererChangeEvent(this)); 194 } 195 196 204 public Range findRangeBounds(CategoryDataset dataset) { 205 if (this.renderAsPercentages) { 206 return new Range(0.0, 1.0); 207 } 208 else { 209 return DatasetUtilities.findStackedRangeBounds(dataset); 210 } 211 } 212 213 221 protected void calculateBarWidth(CategoryPlot plot, 222 Rectangle2D dataArea, 223 int rendererIndex, 224 CategoryItemRendererState state) { 225 226 CategoryAxis domainAxis = getDomainAxis(plot, rendererIndex); 228 CategoryDataset data = plot.getDataset(rendererIndex); 229 if (data != null) { 230 PlotOrientation orientation = plot.getOrientation(); 231 double space = 0.0; 232 if (orientation == PlotOrientation.HORIZONTAL) { 233 space = dataArea.getHeight(); 234 } 235 else if (orientation == PlotOrientation.VERTICAL) { 236 space = dataArea.getWidth(); 237 } 238 double maxWidth = space * getMaximumBarWidth(); 239 int columns = data.getColumnCount(); 240 double categoryMargin = 0.0; 241 if (columns > 1) { 242 categoryMargin = domainAxis.getCategoryMargin(); 243 } 244 245 double used = space * (1 - domainAxis.getLowerMargin() 246 - domainAxis.getUpperMargin() 247 - categoryMargin); 248 if (columns > 0) { 249 state.setBarWidth(Math.min(used / columns, maxWidth)); 250 } 251 else { 252 state.setBarWidth(Math.min(used, maxWidth)); 253 } 254 } 255 256 } 257 258 272 public void drawItem(Graphics2D g2, 273 CategoryItemRendererState state, 274 Rectangle2D dataArea, 275 CategoryPlot plot, 276 CategoryAxis domainAxis, 277 ValueAxis rangeAxis, 278 CategoryDataset dataset, 279 int row, 280 int column, 281 int pass) { 282 283 Number dataValue = dataset.getValue(row, column); 285 if (dataValue == null) { 286 return; 287 } 288 289 double value = dataValue.doubleValue(); 290 double total = 0.0; if (this.renderAsPercentages) { 292 total = DataUtilities.calculateColumnTotal(dataset, column); 293 value = value / total; 294 } 295 296 Rectangle2D adjusted = new Rectangle2D.Double ( 297 dataArea.getX(), dataArea.getY() + getYOffset(), 298 dataArea.getWidth() - getXOffset(), 299 dataArea.getHeight() - getYOffset() 300 ); 301 302 PlotOrientation orientation = plot.getOrientation(); 303 304 double barW0 = domainAxis.getCategoryMiddle( 305 column, getColumnCount(), adjusted, plot.getDomainAxisEdge() 306 ) - state.getBarWidth() / 2.0; 307 308 double positiveBase = getBase(); 309 double negativeBase = positiveBase; 310 for (int i = 0; i < row; i++) { 311 Number v = dataset.getValue(i, column); 312 if (v != null) { 313 double d = v.doubleValue(); 314 if (this.renderAsPercentages) { 315 d = d / total; 316 } 317 if (d > 0) { 318 positiveBase = positiveBase + d; 319 } 320 else { 321 negativeBase = negativeBase + d; 322 } 323 } 324 } 325 326 double translatedBase; 327 double translatedValue; 328 RectangleEdge location = plot.getRangeAxisEdge(); 329 if (value > 0.0) { 330 translatedBase = rangeAxis.valueToJava2D(positiveBase, adjusted, 331 location); 332 translatedValue = rangeAxis.valueToJava2D(positiveBase + value, 333 adjusted, location); 334 } 335 else { 336 translatedBase = rangeAxis.valueToJava2D(negativeBase, adjusted, 337 location); 338 translatedValue = rangeAxis.valueToJava2D(negativeBase + value, 339 adjusted, location); 340 } 341 double barL0 = Math.min(translatedBase, translatedValue); 342 double barLength = Math.max( 343 Math.abs(translatedValue - translatedBase), getMinimumBarLength() 344 ); 345 346 Rectangle2D bar = null; 347 if (orientation == PlotOrientation.HORIZONTAL) { 348 bar = new Rectangle2D.Double (barL0, barW0, barLength, 349 state.getBarWidth()); 350 } 351 else { 352 bar = new Rectangle2D.Double (barW0, barL0, state.getBarWidth(), 353 barLength); 354 } 355 Paint itemPaint = getItemPaint(row, column); 356 g2.setPaint(itemPaint); 357 g2.fill(bar); 358 359 if (pass == 0) { 360 double x0 = bar.getMinX(); 361 double x1 = x0 + getXOffset(); 362 double x2 = bar.getMaxX(); 363 double x3 = x2 + getXOffset(); 364 365 double y0 = bar.getMinY() - getYOffset(); 366 double y1 = bar.getMinY(); 367 double y2 = bar.getMaxY() - getYOffset(); 368 double y3 = bar.getMaxY(); 369 370 GeneralPath bar3dRight = null; 371 GeneralPath bar3dTop = null; 372 if (value > 0.0 || orientation == PlotOrientation.VERTICAL) { 373 bar3dRight = new GeneralPath (); 374 bar3dRight.moveTo((float) x2, (float) y3); 375 bar3dRight.lineTo((float) x2, (float) y1); 376 bar3dRight.lineTo((float) x3, (float) y0); 377 bar3dRight.lineTo((float) x3, (float) y2); 378 bar3dRight.closePath(); 379 380 if (itemPaint instanceof Color ) { 381 g2.setPaint(((Color ) itemPaint).darker()); 382 } 383 g2.fill(bar3dRight); 384 } 385 386 if (value > 0.0 || orientation == PlotOrientation.HORIZONTAL) { 387 bar3dTop = new GeneralPath (); 388 bar3dTop.moveTo((float) x0, (float) y1); 389 bar3dTop.lineTo((float) x1, (float) y0); 390 bar3dTop.lineTo((float) x3, (float) y0); 391 bar3dTop.lineTo((float) x2, (float) y1); 392 bar3dTop.closePath(); 393 g2.fill(bar3dTop); 394 } 395 396 if (isDrawBarOutline() && state.getBarWidth() > 3) { 397 g2.setStroke(getItemOutlineStroke(row, column)); 398 g2.setPaint(getItemOutlinePaint(row, column)); 399 g2.draw(bar); 400 if (bar3dRight != null) { 401 g2.draw(bar3dRight); 402 } 403 if (bar3dTop != null) { 404 g2.draw(bar3dTop); 405 } 406 } 407 408 EntityCollection entities = state.getEntityCollection(); 410 if (entities != null) { 411 addItemEntity(entities, dataset, row, column, bar); 412 } 413 } 414 else if (pass == 1) { 415 CategoryItemLabelGenerator generator 416 = getItemLabelGenerator(row, column); 417 if (generator != null && isItemLabelVisible(row, column)) { 418 drawItemLabel( 419 g2, dataset, row, column, plot, generator, bar, 420 (value < 0.0) 421 ); 422 } 423 } 424 425 } 426 427 434 public int getPassCount() { 435 return 2; 436 } 437 438 445 public boolean equals(Object obj) { 446 if (obj == this) { 447 return true; 448 } 449 if (!(obj instanceof StackedBarRenderer3D)) { 450 return false; 451 } 452 if (!super.equals(obj)) { 453 return false; 454 } 455 StackedBarRenderer3D that = (StackedBarRenderer3D) obj; 456 if (this.renderAsPercentages != that.renderAsPercentages) { 457 return false; 458 } 459 return true; 460 } 461 462 } 463 | Popular Tags |