1 79 80 package org.jfree.chart.renderer.xy; 81 82 import java.awt.Font ; 83 import java.awt.GradientPaint ; 84 import java.awt.Graphics2D ; 85 import java.awt.Paint ; 86 import java.awt.Shape ; 87 import java.awt.Stroke ; 88 import java.awt.geom.Point2D ; 89 import java.awt.geom.Rectangle2D ; 90 import java.io.IOException ; 91 import java.io.ObjectInputStream ; 92 import java.io.ObjectOutputStream ; 93 import java.io.Serializable ; 94 95 import org.jfree.chart.LegendItem; 96 import org.jfree.chart.axis.ValueAxis; 97 import org.jfree.chart.entity.EntityCollection; 98 import org.jfree.chart.entity.XYItemEntity; 99 import org.jfree.chart.event.RendererChangeEvent; 100 import org.jfree.chart.labels.ItemLabelAnchor; 101 import org.jfree.chart.labels.ItemLabelPosition; 102 import org.jfree.chart.labels.XYItemLabelGenerator; 103 import org.jfree.chart.labels.XYSeriesLabelGenerator; 104 import org.jfree.chart.labels.XYToolTipGenerator; 105 import org.jfree.chart.plot.CrosshairState; 106 import org.jfree.chart.plot.PlotOrientation; 107 import org.jfree.chart.plot.PlotRenderingInfo; 108 import org.jfree.chart.plot.XYPlot; 109 import org.jfree.data.Range; 110 import org.jfree.data.general.DatasetUtilities; 111 import org.jfree.data.xy.IntervalXYDataset; 112 import org.jfree.data.xy.XYDataset; 113 import org.jfree.io.SerialUtilities; 114 import org.jfree.text.TextUtilities; 115 import org.jfree.ui.GradientPaintTransformer; 116 import org.jfree.ui.RectangleEdge; 117 import org.jfree.ui.StandardGradientPaintTransformer; 118 import org.jfree.util.ObjectUtilities; 119 import org.jfree.util.PublicCloneable; 120 import org.jfree.util.ShapeUtilities; 121 122 126 public class XYBarRenderer extends AbstractXYItemRenderer 127 implements XYItemRenderer, Cloneable , PublicCloneable, Serializable { 128 129 130 private static final long serialVersionUID = 770559577251370036L; 131 132 135 protected class XYBarRendererState extends XYItemRendererState { 136 137 138 private double g2Base; 139 140 145 public XYBarRendererState(PlotRenderingInfo info) { 146 super(info); 147 } 148 149 154 public double getG2Base() { 155 return this.g2Base; 156 } 157 158 163 public void setG2Base(double value) { 164 this.g2Base = value; 165 } 166 } 167 168 169 private double base; 170 171 175 private boolean useYInterval; 176 177 178 private double margin; 179 180 181 private boolean drawBarOutline; 182 183 187 private GradientPaintTransformer gradientPaintTransformer; 188 189 193 private transient Shape legendBar; 194 195 199 private ItemLabelPosition positiveItemLabelPositionFallback; 200 201 205 private ItemLabelPosition negativeItemLabelPositionFallback; 206 207 210 public XYBarRenderer() { 211 this(0.0); 212 } 213 214 219 public XYBarRenderer(double margin) { 220 super(); 221 this.margin = margin; 222 this.base = 0.0; 223 this.useYInterval = false; 224 this.gradientPaintTransformer = new StandardGradientPaintTransformer(); 225 this.drawBarOutline = true; 226 this.legendBar = new Rectangle2D.Double (-3.0, -5.0, 6.0, 10.0); 227 } 228 229 234 public double getBase() { 235 return this.base; 236 } 237 238 245 public void setBase(double base) { 246 this.base = base; 247 notifyListeners(new RendererChangeEvent(this)); 248 } 249 250 256 public boolean getUseYInterval() { 257 return this.useYInterval; 258 } 259 260 267 public void setUseYInterval(boolean use) { 268 this.useYInterval = use; 269 notifyListeners(new RendererChangeEvent(this)); 270 } 271 272 278 public double getMargin() { 279 return this.margin; 280 } 281 282 288 public void setMargin(double margin) { 289 this.margin = margin; 290 notifyListeners(new RendererChangeEvent(this)); 291 } 292 293 298 public boolean isDrawBarOutline() { 299 return this.drawBarOutline; 300 } 301 302 308 public void setDrawBarOutline(boolean draw) { 309 this.drawBarOutline = draw; 310 notifyListeners(new RendererChangeEvent(this)); 311 } 312 313 319 public GradientPaintTransformer getGradientPaintTransformer() { 320 return this.gradientPaintTransformer; 321 } 322 323 329 public void setGradientPaintTransformer( 330 GradientPaintTransformer transformer) { 331 this.gradientPaintTransformer = transformer; 332 notifyListeners(new RendererChangeEvent(this)); 333 } 334 335 341 public Shape getLegendBar() { 342 return this.legendBar; 343 } 344 345 350 public void setLegendBar(Shape bar) { 351 if (bar == null) { 352 throw new IllegalArgumentException ("Null 'bar' argument."); 353 } 354 this.legendBar = bar; 355 notifyListeners(new RendererChangeEvent(this)); 356 } 357 358 366 public ItemLabelPosition getPositiveItemLabelPositionFallback() { 367 return this.positiveItemLabelPositionFallback; 368 } 369 370 379 public void setPositiveItemLabelPositionFallback( 380 ItemLabelPosition position) { 381 this.positiveItemLabelPositionFallback = position; 382 notifyListeners(new RendererChangeEvent(this)); 383 } 384 385 393 public ItemLabelPosition getNegativeItemLabelPositionFallback() { 394 return this.negativeItemLabelPositionFallback; 395 } 396 397 406 public void setNegativeItemLabelPositionFallback( 407 ItemLabelPosition position) { 408 this.negativeItemLabelPositionFallback = position; 409 notifyListeners(new RendererChangeEvent(this)); 410 } 411 412 427 public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea, 428 XYPlot plot, XYDataset dataset, PlotRenderingInfo info) { 429 430 XYBarRendererState state = new XYBarRendererState(info); 431 ValueAxis rangeAxis 432 = plot.getRangeAxisForDataset(plot.indexOf(dataset)); 433 state.setG2Base(rangeAxis.valueToJava2D(this.base, dataArea, 434 plot.getRangeAxisEdge())); 435 return state; 436 437 } 438 439 448 public LegendItem getLegendItem(int datasetIndex, int series) { 449 LegendItem result = null; 450 XYPlot xyplot = getPlot(); 451 if (xyplot != null) { 452 XYDataset dataset = xyplot.getDataset(datasetIndex); 453 if (dataset != null) { 454 XYSeriesLabelGenerator lg = getLegendItemLabelGenerator(); 455 String label = lg.generateLabel(dataset, series); 456 String description = label; 457 String toolTipText = null; 458 if (getLegendItemToolTipGenerator() != null) { 459 toolTipText = getLegendItemToolTipGenerator().generateLabel( 460 dataset, series); 461 } 462 String urlText = null; 463 if (getLegendItemURLGenerator() != null) { 464 urlText = getLegendItemURLGenerator().generateLabel( 465 dataset, series); 466 } 467 Shape shape = this.legendBar; 468 Paint paint = getSeriesPaint(series); 469 Paint outlinePaint = getSeriesOutlinePaint(series); 470 Stroke outlineStroke = getSeriesOutlineStroke(series); 471 result = new LegendItem(label, description, toolTipText, 472 urlText, shape, paint, outlineStroke, outlinePaint); 473 } 474 } 475 return result; 476 } 477 478 496 public void drawItem(Graphics2D g2, 497 XYItemRendererState state, 498 Rectangle2D dataArea, 499 PlotRenderingInfo info, 500 XYPlot plot, 501 ValueAxis domainAxis, 502 ValueAxis rangeAxis, 503 XYDataset dataset, 504 int series, 505 int item, 506 CrosshairState crosshairState, 507 int pass) { 508 509 if (!getItemVisible(series, item)) { 510 return; 511 } 512 IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 513 514 double value0; 515 double value1; 516 if (this.useYInterval) { 517 value0 = intervalDataset.getStartYValue(series, item); 518 value1 = intervalDataset.getEndYValue(series, item); 519 } 520 else { 521 value0 = this.base; 522 value1 = intervalDataset.getYValue(series, item); 523 } 524 if (Double.isNaN(value0) || Double.isNaN(value1)) { 525 return; 526 } 527 528 double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, 529 plot.getRangeAxisEdge()); 530 double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, 531 plot.getRangeAxisEdge()); 532 533 RectangleEdge location = plot.getDomainAxisEdge(); 534 double startX = intervalDataset.getStartXValue(series, item); 535 if (Double.isNaN(startX)) { 536 return; 537 } 538 double translatedStartX = domainAxis.valueToJava2D(startX, dataArea, 539 location); 540 541 double endX = intervalDataset.getEndXValue(series, item); 542 if (Double.isNaN(endX)) { 543 return; 544 } 545 double translatedEndX = domainAxis.valueToJava2D(endX, dataArea, 546 location); 547 548 double translatedWidth = Math.max(1, Math.abs(translatedEndX 549 - translatedStartX)); 550 double translatedHeight = Math.abs(translatedValue1 - translatedValue0); 551 552 if (getMargin() > 0.0) { 553 double cut = translatedWidth * getMargin(); 554 translatedWidth = translatedWidth - cut; 555 translatedStartX = translatedStartX + cut / 2; 556 } 557 558 Rectangle2D bar = null; 559 PlotOrientation orientation = plot.getOrientation(); 560 if (orientation == PlotOrientation.HORIZONTAL) { 561 bar = new Rectangle2D.Double ( 562 Math.min(translatedValue0, translatedValue1), 563 Math.min(translatedStartX, translatedEndX), 564 translatedHeight, translatedWidth); 565 } 566 else if (orientation == PlotOrientation.VERTICAL) { 567 bar = new Rectangle2D.Double ( 568 Math.min(translatedStartX, translatedEndX), 569 Math.min(translatedValue0, translatedValue1), 570 translatedWidth, translatedHeight); 571 } 572 573 Paint itemPaint = getItemPaint(series, item); 574 if (getGradientPaintTransformer() 575 != null && itemPaint instanceof GradientPaint ) { 576 GradientPaint gp = (GradientPaint ) itemPaint; 577 itemPaint = getGradientPaintTransformer().transform(gp, bar); 578 } 579 g2.setPaint(itemPaint); 580 g2.fill(bar); 581 if (isDrawBarOutline() 582 && Math.abs(translatedEndX - translatedStartX) > 3) { 583 Stroke stroke = getItemOutlineStroke(series, item); 584 Paint paint = getItemOutlinePaint(series, item); 585 if (stroke != null && paint != null) { 586 g2.setStroke(stroke); 587 g2.setPaint(paint); 588 g2.draw(bar); 589 } 590 } 591 592 if (isItemLabelVisible(series, item)) { 593 XYItemLabelGenerator generator = getItemLabelGenerator(series, 594 item); 595 drawItemLabel(g2, dataset, series, item, plot, generator, bar, 596 value1 < 0.0); 597 } 598 599 double x1 = (startX + endX) / 2.0; 601 double y1 = dataset.getYValue(series, item); 602 double transX1 = domainAxis.valueToJava2D(x1, dataArea, location); 603 double transY1 = rangeAxis.valueToJava2D(y1, dataArea, 604 plot.getRangeAxisEdge()); 605 updateCrosshairValues(crosshairState, x1, y1, transX1, transY1, 606 plot.getOrientation()); 607 608 if (info != null) { 610 EntityCollection entities = info.getOwner().getEntityCollection(); 611 if (entities != null) { 612 String tip = null; 613 XYToolTipGenerator generator 614 = getToolTipGenerator(series, item); 615 if (generator != null) { 616 tip = generator.generateToolTip(dataset, series, item); 617 } 618 String url = null; 619 if (getURLGenerator() != null) { 620 url = getURLGenerator().generateURL(dataset, series, item); 621 } 622 XYItemEntity entity = new XYItemEntity(bar, dataset, series, 623 item, tip, url); 624 entities.add(entity); 625 } 626 } 627 628 } 629 630 643 protected void drawItemLabel(Graphics2D g2, XYDataset dataset, 644 int series, int item, XYPlot plot, XYItemLabelGenerator generator, 645 Rectangle2D bar, boolean negative) { 646 647 String label = generator.generateLabel(dataset, series, item); 648 if (label == null) { 649 return; } 651 652 Font labelFont = getItemLabelFont(series, item); 653 g2.setFont(labelFont); 654 Paint paint = getItemLabelPaint(series, item); 655 g2.setPaint(paint); 656 657 ItemLabelPosition position = null; 659 if (!negative) { 660 position = getPositiveItemLabelPosition(series, item); 661 } 662 else { 663 position = getNegativeItemLabelPosition(series, item); 664 } 665 666 Point2D anchorPoint = calculateLabelAnchorPoint( 668 position.getItemLabelAnchor(), bar, plot.getOrientation()); 669 670 if (isInternalAnchor(position.getItemLabelAnchor())) { 671 Shape bounds = TextUtilities.calculateRotatedStringBounds(label, 672 g2, (float) anchorPoint.getX(), (float) anchorPoint.getY(), 673 position.getTextAnchor(), position.getAngle(), 674 position.getRotationAnchor()); 675 676 if (bounds != null) { 677 if (!bar.contains(bounds.getBounds2D())) { 678 if (!negative) { 679 position = getPositiveItemLabelPositionFallback(); 680 } 681 else { 682 position = getNegativeItemLabelPositionFallback(); 683 } 684 if (position != null) { 685 anchorPoint = calculateLabelAnchorPoint( 686 position.getItemLabelAnchor(), bar, 687 plot.getOrientation()); 688 } 689 } 690 } 691 692 } 693 694 if (position != null) { 695 TextUtilities.drawRotatedString(label, g2, 696 (float) anchorPoint.getX(), (float) anchorPoint.getY(), 697 position.getTextAnchor(), position.getAngle(), 698 position.getRotationAnchor()); 699 } 700 } 701 702 711 private Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor, 712 Rectangle2D bar, PlotOrientation orientation) { 713 714 Point2D result = null; 715 double offset = getItemLabelAnchorOffset(); 716 double x0 = bar.getX() - offset; 717 double x1 = bar.getX(); 718 double x2 = bar.getX() + offset; 719 double x3 = bar.getCenterX(); 720 double x4 = bar.getMaxX() - offset; 721 double x5 = bar.getMaxX(); 722 double x6 = bar.getMaxX() + offset; 723 724 double y0 = bar.getMaxY() + offset; 725 double y1 = bar.getMaxY(); 726 double y2 = bar.getMaxY() - offset; 727 double y3 = bar.getCenterY(); 728 double y4 = bar.getMinY() + offset; 729 double y5 = bar.getMinY(); 730 double y6 = bar.getMinY() - offset; 731 732 if (anchor == ItemLabelAnchor.CENTER) { 733 result = new Point2D.Double (x3, y3); 734 } 735 else if (anchor == ItemLabelAnchor.INSIDE1) { 736 result = new Point2D.Double (x4, y4); 737 } 738 else if (anchor == ItemLabelAnchor.INSIDE2) { 739 result = new Point2D.Double (x4, y4); 740 } 741 else if (anchor == ItemLabelAnchor.INSIDE3) { 742 result = new Point2D.Double (x4, y3); 743 } 744 else if (anchor == ItemLabelAnchor.INSIDE4) { 745 result = new Point2D.Double (x4, y2); 746 } 747 else if (anchor == ItemLabelAnchor.INSIDE5) { 748 result = new Point2D.Double (x4, y2); 749 } 750 else if (anchor == ItemLabelAnchor.INSIDE6) { 751 result = new Point2D.Double (x3, y2); 752 } 753 else if (anchor == ItemLabelAnchor.INSIDE7) { 754 result = new Point2D.Double (x2, y2); 755 } 756 else if (anchor == ItemLabelAnchor.INSIDE8) { 757 result = new Point2D.Double (x2, y2); 758 } 759 else if (anchor == ItemLabelAnchor.INSIDE9) { 760 result = new Point2D.Double (x2, y3); 761 } 762 else if (anchor == ItemLabelAnchor.INSIDE10) { 763 result = new Point2D.Double (x2, y4); 764 } 765 else if (anchor == ItemLabelAnchor.INSIDE11) { 766 result = new Point2D.Double (x2, y4); 767 } 768 else if (anchor == ItemLabelAnchor.INSIDE12) { 769 result = new Point2D.Double (x3, y4); 770 } 771 else if (anchor == ItemLabelAnchor.OUTSIDE1) { 772 result = new Point2D.Double (x5, y6); 773 } 774 else if (anchor == ItemLabelAnchor.OUTSIDE2) { 775 result = new Point2D.Double (x6, y5); 776 } 777 else if (anchor == ItemLabelAnchor.OUTSIDE3) { 778 result = new Point2D.Double (x6, y3); 779 } 780 else if (anchor == ItemLabelAnchor.OUTSIDE4) { 781 result = new Point2D.Double (x6, y1); 782 } 783 else if (anchor == ItemLabelAnchor.OUTSIDE5) { 784 result = new Point2D.Double (x5, y0); 785 } 786 else if (anchor == ItemLabelAnchor.OUTSIDE6) { 787 result = new Point2D.Double (x3, y0); 788 } 789 else if (anchor == ItemLabelAnchor.OUTSIDE7) { 790 result = new Point2D.Double (x1, y0); 791 } 792 else if (anchor == ItemLabelAnchor.OUTSIDE8) { 793 result = new Point2D.Double (x0, y1); 794 } 795 else if (anchor == ItemLabelAnchor.OUTSIDE9) { 796 result = new Point2D.Double (x0, y3); 797 } 798 else if (anchor == ItemLabelAnchor.OUTSIDE10) { 799 result = new Point2D.Double (x0, y5); 800 } 801 else if (anchor == ItemLabelAnchor.OUTSIDE11) { 802 result = new Point2D.Double (x1, y6); 803 } 804 else if (anchor == ItemLabelAnchor.OUTSIDE12) { 805 result = new Point2D.Double (x3, y6); 806 } 807 808 return result; 809 810 } 811 812 819 private boolean isInternalAnchor(ItemLabelAnchor anchor) { 820 return anchor == ItemLabelAnchor.CENTER 821 || anchor == ItemLabelAnchor.INSIDE1 822 || anchor == ItemLabelAnchor.INSIDE2 823 || anchor == ItemLabelAnchor.INSIDE3 824 || anchor == ItemLabelAnchor.INSIDE4 825 || anchor == ItemLabelAnchor.INSIDE5 826 || anchor == ItemLabelAnchor.INSIDE6 827 || anchor == ItemLabelAnchor.INSIDE7 828 || anchor == ItemLabelAnchor.INSIDE8 829 || anchor == ItemLabelAnchor.INSIDE9 830 || anchor == ItemLabelAnchor.INSIDE10 831 || anchor == ItemLabelAnchor.INSIDE11 832 || anchor == ItemLabelAnchor.INSIDE12; 833 } 834 835 845 public Range findDomainBounds(XYDataset dataset) { 846 if (dataset != null) { 847 return DatasetUtilities.findDomainBounds(dataset, true); 848 } 849 else { 850 return null; 851 } 852 } 853 854 861 public Object clone() throws CloneNotSupportedException { 862 XYBarRenderer result = (XYBarRenderer) super.clone(); 863 if (this.gradientPaintTransformer != null) { 864 result.gradientPaintTransformer = (GradientPaintTransformer) 865 ObjectUtilities.clone(this.gradientPaintTransformer); 866 } 867 return result; 868 } 869 870 877 public boolean equals(Object obj) { 878 if (obj == this) { 879 return true; 880 } 881 if (!(obj instanceof XYBarRenderer)) { 882 return false; 883 } 884 if (!super.equals(obj)) { 885 return false; 886 } 887 XYBarRenderer that = (XYBarRenderer) obj; 888 if (this.base != that.base) { 889 return false; 890 } 891 if (this.drawBarOutline != that.drawBarOutline) { 892 return false; 893 } 894 if (this.margin != that.margin) { 895 return false; 896 } 897 if (this.useYInterval != that.useYInterval) { 898 return false; 899 } 900 if (!ObjectUtilities.equal( 901 this.gradientPaintTransformer, that.gradientPaintTransformer) 902 ) { 903 return false; 904 } 905 if (!ShapeUtilities.equal(this.legendBar, that.legendBar)) { 906 return false; 907 } 908 if (!ObjectUtilities.equal(this.positiveItemLabelPositionFallback, 909 that.positiveItemLabelPositionFallback)) { 910 return false; 911 } 912 if (!ObjectUtilities.equal(this.negativeItemLabelPositionFallback, 913 that.negativeItemLabelPositionFallback)) { 914 return false; 915 } 916 return true; 917 } 918 919 927 private void readObject(ObjectInputStream stream) 928 throws IOException , ClassNotFoundException { 929 stream.defaultReadObject(); 930 this.legendBar = SerialUtilities.readShape(stream); 931 } 932 933 940 private void writeObject(ObjectOutputStream stream) throws IOException { 941 stream.defaultWriteObject(); 942 SerialUtilities.writeShape(this.legendBar, stream); 943 } 944 945 } 946 | Popular Tags |