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 int series, 939 int item, 940 ValueAxis domainAxis, 941 ValueAxis rangeAxis, 942 Rectangle2D dataArea) { 943 944 945 RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 946 RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 947 948 double x1 = dataset.getXValue(series, item); 950 double y1 = dataset.getYValue(series, item); 951 double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); 952 double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); 953 954 State s = (State) state; 955 if (!Double.isNaN(transX1) && !Double.isNaN(transY1)) { 957 float x = (float) transX1; 958 float y = (float) transY1; 959 PlotOrientation orientation = plot.getOrientation(); 960 if (orientation == PlotOrientation.HORIZONTAL) { 961 x = (float) transY1; 962 y = (float) transX1; 963 } 964 if (s.isLastPointGood()) { 965 s.seriesPath.lineTo(x, y); 966 } 967 else { 968 s.seriesPath.moveTo(x, y); 969 } 970 s.setLastPointGood(true); 971 } 972 else { 973 s.setLastPointGood(false); 974 } 975 if (item == dataset.getItemCount(series) - 1) { 977 drawFirstPassShape(g2, pass, series, item, s.seriesPath); 979 } 980 } 981 982 1000 protected void drawSecondaryPass(Graphics2D g2, XYPlot plot, 1001 XYDataset dataset, 1002 int pass, int series, int item, 1003 ValueAxis domainAxis, 1004 Rectangle2D dataArea, 1005 ValueAxis rangeAxis, 1006 CrosshairState crosshairState, 1007 EntityCollection entities) { 1008 1009 Shape entityArea = null; 1010 1011 double x1 = dataset.getXValue(series, item); 1013 double y1 = dataset.getYValue(series, item); 1014 if (Double.isNaN(y1) || Double.isNaN(x1)) { 1015 return; 1016 } 1017 1018 PlotOrientation orientation = plot.getOrientation(); 1019 RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 1020 RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 1021 double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); 1022 double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); 1023 1024 if (getItemShapeVisible(series, item)) { 1025 Shape shape = getItemShape(series, item); 1026 if (orientation == PlotOrientation.HORIZONTAL) { 1027 shape = ShapeUtilities.createTranslatedShape(shape, transY1, 1028 transX1); 1029 } 1030 else if (orientation == PlotOrientation.VERTICAL) { 1031 shape = ShapeUtilities.createTranslatedShape(shape, transX1, 1032 transY1); 1033 } 1034 entityArea = shape; 1035 if (shape.intersects(dataArea)) { 1036 if (getItemShapeFilled(series, item)) { 1037 if (this.useFillPaint) { 1038 g2.setPaint(getItemFillPaint(series, item)); 1039 } 1040 else { 1041 g2.setPaint(getItemPaint(series, item)); 1042 } 1043 g2.fill(shape); 1044 } 1045 if (this.drawOutlines) { 1046 if (getUseOutlinePaint()) { 1047 g2.setPaint(getItemOutlinePaint(series, item)); 1048 } 1049 else { 1050 g2.setPaint(getItemPaint(series, item)); 1051 } 1052 g2.setStroke(getItemOutlineStroke(series, item)); 1053 g2.draw(shape); 1054 } 1055 } 1056 } 1057 1058 if (isItemLabelVisible(series, item)) { 1060 double xx = transX1; 1061 double yy = transY1; 1062 if (orientation == PlotOrientation.HORIZONTAL) { 1063 xx = transY1; 1064 yy = transX1; 1065 } 1066 drawItemLabel(g2, orientation, dataset, series, item, xx, yy, 1067 (y1 < 0.0)); 1068 } 1069 1070 updateCrosshairValues(crosshairState, x1, y1, transX1, transY1, 1071 plot.getOrientation()); 1072 1073 if (entities != null) { 1075 addEntity(entities, entityArea, dataset, series, item, transX1, 1076 transY1); 1077 } 1078 } 1079 1080 1081 1089 public LegendItem getLegendItem(int datasetIndex, int series) { 1090 1091 XYPlot plot = getPlot(); 1092 if (plot == null) { 1093 return null; 1094 } 1095 1096 LegendItem result = null; 1097 XYDataset dataset = plot.getDataset(datasetIndex); 1098 if (dataset != null) { 1099 if (getItemVisible(series, 0)) { 1100 String label = getLegendItemLabelGenerator().generateLabel( 1101 dataset, series); 1102 String description = label; 1103 String toolTipText = null; 1104 if (getLegendItemToolTipGenerator() != null) { 1105 toolTipText = getLegendItemToolTipGenerator().generateLabel( 1106 dataset, series); 1107 } 1108 String urlText = null; 1109 if (getLegendItemURLGenerator() != null) { 1110 urlText = getLegendItemURLGenerator().generateLabel( 1111 dataset, series); 1112 } 1113 boolean shapeIsVisible = getItemShapeVisible(series, 0); 1114 Shape shape = getSeriesShape(series); 1115 boolean shapeIsFilled = getItemShapeFilled(series, 0); 1116 Paint fillPaint = (this.useFillPaint 1117 ? getSeriesFillPaint(series) : getSeriesPaint(series)); 1118 boolean shapeOutlineVisible = this.drawOutlines; 1119 Paint outlinePaint = (this.useOutlinePaint 1120 ? getSeriesOutlinePaint(series) 1121 : getSeriesPaint(series)); 1122 Stroke outlineStroke = getSeriesOutlineStroke(series); 1123 boolean lineVisible = getItemLineVisible(series, 0); 1124 Stroke lineStroke = getSeriesStroke(series); 1125 Paint linePaint = getSeriesPaint(series); 1126 result = new LegendItem(label, description, toolTipText, 1127 urlText, shapeIsVisible, shape, shapeIsFilled, 1128 fillPaint, shapeOutlineVisible, outlinePaint, 1129 outlineStroke, lineVisible, this.legendLine, 1130 lineStroke, linePaint); 1131 result.setSeriesIndex(series); 1132 result.setDatasetIndex(datasetIndex); 1133 } 1134 } 1135 1136 return result; 1137 1138 } 1139 1140 1147 public Object clone() throws CloneNotSupportedException { 1148 return super.clone(); 1149 } 1150 1151 1158 public boolean equals(Object obj) { 1159 1160 if (obj == this) { 1161 return true; 1162 } 1163 if (!(obj instanceof XYLineAndShapeRenderer)) { 1164 return false; 1165 } 1166 if (!super.equals(obj)) { 1167 return false; 1168 } 1169 XYLineAndShapeRenderer that = (XYLineAndShapeRenderer) obj; 1170 if (!ObjectUtilities.equal(this.linesVisible, that.linesVisible)) { 1171 return false; 1172 } 1173 if (!ObjectUtilities.equal( 1174 this.seriesLinesVisible, that.seriesLinesVisible) 1175 ) { 1176 return false; 1177 } 1178 if (this.baseLinesVisible != that.baseLinesVisible) { 1179 return false; 1180 } 1181 if (!ShapeUtilities.equal(this.legendLine, that.legendLine)) { 1182 return false; 1183 } 1184 if (!ObjectUtilities.equal(this.shapesVisible, that.shapesVisible)) { 1185 return false; 1186 } 1187 if (!ObjectUtilities.equal( 1188 this.seriesShapesVisible, that.seriesShapesVisible) 1189 ) { 1190 return false; 1191 } 1192 if (this.baseShapesVisible != that.baseShapesVisible) { 1193 return false; 1194 } 1195 if (!ObjectUtilities.equal(this.shapesFilled, that.shapesFilled)) { 1196 return false; 1197 } 1198 if (!ObjectUtilities.equal( 1199 this.seriesShapesFilled, that.seriesShapesFilled) 1200 ) { 1201 return false; 1202 } 1203 if (this.baseShapesFilled != that.baseShapesFilled) { 1204 return false; 1205 } 1206 if (this.drawOutlines != that.drawOutlines) { 1207 return false; 1208 } 1209 if (this.useOutlinePaint != that.useOutlinePaint) { 1210 return false; 1211 } 1212 1213 return true; 1214 1215 } 1216 1217 1225 private void readObject(ObjectInputStream stream) 1226 throws IOException , ClassNotFoundException { 1227 stream.defaultReadObject(); 1228 this.legendLine = SerialUtilities.readShape(stream); 1229 } 1230 1231 1238 private void writeObject(ObjectOutputStream stream) throws IOException { 1239 stream.defaultWriteObject(); 1240 SerialUtilities.writeShape(this.legendLine, stream); 1241 } 1242 1243} 1244 | Popular Tags |