| 1 61 62 package org.jfree.chart.renderer.xy; 63 64 import java.awt.Graphics2D ; 65 import java.awt.Paint ; 66 import java.awt.Shape ; 67 import java.awt.Stroke ; 68 import java.awt.geom.GeneralPath ; 69 import java.awt.geom.Line2D ; 70 import java.awt.geom.Rectangle2D ; 71 import java.io.IOException ; 72 import java.io.ObjectInputStream ; 73 import java.io.ObjectOutputStream ; 74 import java.io.Serializable ; 75 76 import org.jfree.chart.LegendItem; 77 import org.jfree.chart.axis.ValueAxis; 78 import org.jfree.chart.entity.EntityCollection; 79 import org.jfree.chart.event.RendererChangeEvent; 80 import org.jfree.chart.plot.CrosshairState; 81 import org.jfree.chart.plot.PlotOrientation; 82 import org.jfree.chart.plot.PlotRenderingInfo; 83 import org.jfree.chart.plot.XYPlot; 84 import org.jfree.data.xy.XYDataset; 85 import org.jfree.io.SerialUtilities; 86 import org.jfree.ui.RectangleEdge; 87 import org.jfree.util.BooleanList; 88 import org.jfree.util.BooleanUtilities; 89 import org.jfree.util.ObjectUtilities; 90 import org.jfree.util.PublicCloneable; 91 import org.jfree.util.ShapeUtilities; 92 93 96 public class XYLineAndShapeRenderer extends AbstractXYItemRenderer 97 implements XYItemRenderer, 98 Cloneable , 99 PublicCloneable, 100 Serializable { 101 102 103 private static final long serialVersionUID = -7435246895986425885L; 104 105 106 private Boolean linesVisible; 107 108 112 private BooleanList seriesLinesVisible; 113 114 115 private boolean baseLinesVisible; 116 117 118 private transient Shape legendLine; 119 120 123 private Boolean shapesVisible; 124 125 129 private BooleanList seriesShapesVisible; 130 131 132 private boolean baseShapesVisible; 133 134 135 private Boolean shapesFilled; 136 137 141 private BooleanList seriesShapesFilled; 142 143 144 private boolean baseShapesFilled; 145 146 147 private boolean drawOutlines; 148 149 153 private boolean useFillPaint; 154 155 159 private boolean useOutlinePaint; 160 161 165 private boolean drawSeriesLineAsPath; 166 167 170 public XYLineAndShapeRenderer() { 171 this(true, true); 172 } 173 174 180 public XYLineAndShapeRenderer(boolean lines, boolean shapes) { 181 this.linesVisible = null; 182 this.seriesLinesVisible = new BooleanList(); 183 this.baseLinesVisible = lines; 184 this.legendLine = new Line2D.Double (-7.0, 0.0, 7.0, 0.0); 185 186 this.shapesVisible = null; 187 this.seriesShapesVisible = new BooleanList(); 188 this.baseShapesVisible = shapes; 189 190 this.shapesFilled = null; 191 this.useFillPaint = false; this.seriesShapesFilled = new BooleanList(); 193 this.baseShapesFilled = true; 194 195 this.drawOutlines = true; 196 this.useOutlinePaint = false; 199 this.drawSeriesLineAsPath = false; 200 } 201 202 210 public boolean getDrawSeriesLineAsPath() { 211 return this.drawSeriesLineAsPath; 212 } 213 214 222 public void setDrawSeriesLineAsPath(boolean flag) { 223 if (this.drawSeriesLineAsPath != flag) { 224 this.drawSeriesLineAsPath = flag; 225 notifyListeners(new RendererChangeEvent(this)); 226 } 227 } 228 229 236 public int getPassCount() { 237 return 2; 238 } 239 240 242 251 public boolean getItemLineVisible(int series, int item) { 252 Boolean flag = this.linesVisible; 253 if (flag == null) { 254 flag = getSeriesLinesVisible(series); 255 } 256 if (flag != null) { 257 return flag.booleanValue(); 258 } 259 else { 260 return this.baseLinesVisible; 261 } 262 } 263 264 271 public Boolean getLinesVisible() { 272 return this.linesVisible; 273 } 274 275 283 public void setLinesVisible(Boolean visible) { 284 this.linesVisible = visible; 285 notifyListeners(new RendererChangeEvent(this)); 286 } 287 288 295 public void setLinesVisible(boolean visible) { 296 setLinesVisible(BooleanUtilities.valueOf(visible)); 297 } 298 299 307 public Boolean getSeriesLinesVisible(int series) { 308 return this.seriesLinesVisible.getBoolean(series); 309 } 310 311 317 public void setSeriesLinesVisible(int series, Boolean flag) { 318 this.seriesLinesVisible.setBoolean(series, flag); 319 notifyListeners(new RendererChangeEvent(this)); 320 } 321 322 328 public void setSeriesLinesVisible(int series, boolean visible) { 329 setSeriesLinesVisible(series, BooleanUtilities.valueOf(visible)); 330 } 331 332 337 public boolean getBaseLinesVisible() { 338 return this.baseLinesVisible; 339 } 340 341 346 public void setBaseLinesVisible(boolean flag) { 347 this.baseLinesVisible = flag; 348 notifyListeners(new RendererChangeEvent(this)); 349 } 350 351 356 public Shape getLegendLine() { 357 return this.legendLine; 358 } 359 360 366 public void setLegendLine(Shape line) { 367 if (line == null) { 368 throw new IllegalArgumentException ("Null 'line' argument."); 369 } 370 this.legendLine = line; 371 notifyListeners(new RendererChangeEvent(this)); 372 } 373 374 376 389 public boolean getItemShapeVisible(int series, int item) { 390 Boolean flag = this.shapesVisible; 391 if (flag == null) { 392 flag = getSeriesShapesVisible(series); 393 } 394 if (flag != null) { 395 return flag.booleanValue(); 396 } 397 else { 398 return this.baseShapesVisible; 399 } 400 } 401 402 408 public Boolean getShapesVisible() { 409 return this.shapesVisible; 410 } 411 412 418 public void setShapesVisible(Boolean visible) { 419 this.shapesVisible = visible; 420 notifyListeners(new RendererChangeEvent(this)); 421 } 422 423 429 public void setShapesVisible(boolean visible) { 430 setShapesVisible(BooleanUtilities.valueOf(visible)); 431 } 432 433 441 public Boolean getSeriesShapesVisible(int series) { 442 return this.seriesShapesVisible.getBoolean(series); 443 } 444 445 452 public void setSeriesShapesVisible(int series, boolean visible) { 453 setSeriesShapesVisible(series, BooleanUtilities.valueOf(visible)); 454 } 455 456 463 public void setSeriesShapesVisible(int series, Boolean flag) { 464 this.seriesShapesVisible.setBoolean(series, flag); 465 notifyListeners(new RendererChangeEvent(this)); 466 } 467 468 473 public boolean getBaseShapesVisible() { 474 return this.baseShapesVisible; 475 } 476 477 482 public void setBaseShapesVisible(boolean flag) { 483 this.baseShapesVisible = flag; 484 notifyListeners(new RendererChangeEvent(this)); 485 } 486 487 489 502 public boolean getItemShapeFilled(int series, int item) { 503 Boolean flag = this.shapesFilled; 504 if (flag == null) { 505 flag = getSeriesShapesFilled(series); 506 } 507 if (flag != null) { 508 return flag.booleanValue(); 509 } 510 else { 511 return this.baseShapesFilled; 512 } 513 } 514 515 521 public void setShapesFilled(boolean filled) { 522 setShapesFilled(BooleanUtilities.valueOf(filled)); 523 } 524 525 531 public void setShapesFilled(Boolean filled) { 532 this.shapesFilled = filled; 533 notifyListeners(new RendererChangeEvent(this)); 534 } 535 536 544 public Boolean getSeriesShapesFilled(int series) { 545 return this.seriesShapesFilled.getBoolean(series); 546 } 547 548 554 public void setSeriesShapesFilled(int series, boolean flag) { 555 setSeriesShapesFilled(series, BooleanUtilities.valueOf(flag)); 556 } 557 558 564 public void setSeriesShapesFilled(int series, Boolean flag) { 565 this.seriesShapesFilled.setBoolean(series, flag); 566 notifyListeners(new RendererChangeEvent(this)); 567 } 568 569 574 public boolean getBaseShapesFilled() { 575 return this.baseShapesFilled; 576 } 577 578 583 public void setBaseShapesFilled(boolean flag) { 584 this.baseShapesFilled = flag; 585 notifyListeners(new RendererChangeEvent(this)); 586 } 587 588 594 public boolean getDrawOutlines() { 595 return this.drawOutlines; 596 } 597 598 608 public void setDrawOutlines(boolean flag) { 609 this.drawOutlines = flag; 610 notifyListeners(new RendererChangeEvent(this)); 611 } 612 613 620 public boolean getUseFillPaint() { 621 return this.useFillPaint; 622 } 623 624 631 public void setUseFillPaint(boolean flag) { 632 this.useFillPaint = flag; 633 notifyListeners(new RendererChangeEvent(this)); 634 } 635 636 643 public boolean getUseOutlinePaint() { 644 return this.useOutlinePaint; 645 } 646 647 654 public void setUseOutlinePaint(boolean flag) { 655 this.useOutlinePaint = flag; 656 notifyListeners(new RendererChangeEvent(this)); 657 } 658 659 664 public static class State extends XYItemRendererState { 665 666 667 public GeneralPath seriesPath; 668 669 673 private boolean lastPointGood; 674 675 680 public State(PlotRenderingInfo info) { 681 super(info); 682 } 683 684 690 public boolean isLastPointGood() { 691 return this.lastPointGood; 692 } 693 694 700 public void setLastPointGood(boolean good) { 701 this.lastPointGood = good; 702 } 703 } 704 705 721 public XYItemRendererState initialise(Graphics2D g2, 722 Rectangle2D dataArea, 723 XYPlot plot, 724 XYDataset data, 725 PlotRenderingInfo info) { 726 727 State state = new State(info); 728 state.seriesPath = new GeneralPath (); 729 return state; 730 731 } 732 733 751 public void drawItem(Graphics2D g2, 752 XYItemRendererState state, 753 Rectangle2D dataArea, 754 PlotRenderingInfo info, 755 XYPlot plot, 756 ValueAxis domainAxis, 757 ValueAxis rangeAxis, 758 XYDataset dataset, 759 int series, 760 int item, 761 CrosshairState crosshairState, 762 int pass) { 763 764 if (!getItemVisible(series, item)) { 766 return; 767 } 768 769 if (isLinePass(pass)) { 771 if (item == 0) { 772 if (this.drawSeriesLineAsPath) { 773 State s = (State) state; 774 s.seriesPath.reset(); 775 s.lastPointGood = false; 776 } 777 } 778 779 if (getItemLineVisible(series, item)) { 780 if (this.drawSeriesLineAsPath) { 781 drawPrimaryLineAsPath(state, g2, plot, dataset, pass, 782 series, item, domainAxis, rangeAxis, dataArea); 783 } 784 else { 785 drawPrimaryLine(state, g2, plot, dataset, pass, series, 786 item, domainAxis, rangeAxis, dataArea); 787 } 788 } 789 } 790 else if (isItemPass(pass)) { 792 793 EntityCollection entities = null; 795 if (info != null) { 796 entities = info.getOwner().getEntityCollection(); 797 } 798 799 drawSecondaryPass(g2, plot, dataset, pass, series, item, 800 domainAxis, dataArea, rangeAxis, crosshairState, entities); 801 } 802 } 803 804 812 protected boolean isLinePass(int pass) { 813 return pass == 0; 814 } 815 816 824 protected boolean isItemPass(int pass) { 825 return pass == 1; 826 } 827 828 844 protected void drawPrimaryLine(XYItemRendererState state, 845 Graphics2D g2, 846 XYPlot plot, 847 XYDataset dataset, 848 int pass, 849 int series, 850 int item, 851 ValueAxis domainAxis, 852 ValueAxis rangeAxis, 853 Rectangle2D dataArea) { 854 if (item == 0) { 855 return; 856 } 857 858 double x1 = dataset.getXValue(series, item); 860 double y1 = dataset.getYValue(series, item); 861 if (Double.isNaN(y1) || Double.isNaN(x1)) { 862 return; 863 } 864 865 double x0 = dataset.getXValue(series, item - 1); 866 double y0 = dataset.getYValue(series, item - 1); 867 if (Double.isNaN(y0) || Double.isNaN(x0)) { 868 return; 869 } 870 871 RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 872 RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 873 874 double transX0 = domainAxis.valueToJava2D(x0, dataArea, xAxisLocation); 875 double transY0 = rangeAxis.valueToJava2D(y0, dataArea, yAxisLocation); 876 877 double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); 878 double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); 879 880 if (Double.isNaN(transX0) || Double.isNaN(transY0) 882 || Double.isNaN(transX1) || Double.isNaN(transY1)) { 883 return; 884 } 885 886 PlotOrientation orientation = plot.getOrientation(); 887 if (orientation == PlotOrientation.HORIZONTAL) { 888 state.workingLine.setLine(transY0, transX0, transY1, transX1); 889 } 890 else if (orientation == PlotOrientation.VERTICAL) { 891 state.workingLine.setLine(transX0, transY0, transX1, transY1); 892 } 893 894 if (state.workingLine.intersects(dataArea)) { 895 drawFirstPassShape(g2, pass, series, item, state.workingLine); 896 } 897 } 898 899 908 protected void drawFirstPassShape(Graphics2D g2, int pass, int series, 909 int item, Shape shape) { 910 g2.setStroke(getItemStroke(series, item)); 911 g2.setPaint(getItemPaint(series, item)); 912 g2.draw(shape); 913 } 914 915 916 934 protected void drawPrimaryLineAsPath(XYItemRendererState state, 935 Graphics2D g2, XYPlot plot, 936 XYDataset dataset, 937 int pass, 938 &n
|