1:
63:
64: package ;
65:
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90:
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112:
113:
118: public class SpiderWebPlot extends Plot implements Cloneable, Serializable {
119:
120:
121: private static final long serialVersionUID = -5376340422031599463L;
122:
123:
124: public static final double DEFAULT_HEAD = 0.01;
125:
126:
127: public static final double DEFAULT_AXIS_LABEL_GAP = 0.10;
128:
129:
130: public static final double DEFAULT_INTERIOR_GAP = 0.25;
131:
132:
133: public static final double MAX_INTERIOR_GAP = 0.40;
134:
135:
136: public static final double DEFAULT_START_ANGLE = 90.0;
137:
138:
139: public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
140: Font.PLAIN, 10);
141:
142:
143: public static final Paint DEFAULT_LABEL_PAINT = Color.black;
144:
145:
146: public static final Paint DEFAULT_LABEL_BACKGROUND_PAINT
147: = new Color(255, 255, 192);
148:
149:
150: public static final Paint DEFAULT_LABEL_OUTLINE_PAINT = Color.black;
151:
152:
153: public static final Stroke DEFAULT_LABEL_OUTLINE_STROKE
154: = new BasicStroke(0.5f);
155:
156:
157: public static final Paint DEFAULT_LABEL_SHADOW_PAINT = Color.lightGray;
158:
159:
163: public static final double DEFAULT_MAX_VALUE = -1.0;
164:
165:
166: protected double headPercent;
167:
168:
169: private double interiorGap;
170:
171:
172: private double axisLabelGap;
173:
174:
175: private CategoryDataset dataset;
176:
177:
178: private double maxValue;
179:
180:
186: private TableOrder dataExtractOrder;
187:
188:
189: private double startAngle;
190:
191:
192: private Rotation direction;
193:
194:
195: private transient Shape legendItemShape;
196:
197:
198: private transient Paint seriesPaint;
199:
200:
201: private PaintList seriesPaintList;
202:
203:
204: private transient Paint baseSeriesPaint;
205:
206:
207: private transient Paint seriesOutlinePaint;
208:
209:
210: private PaintList seriesOutlinePaintList;
211:
212:
213: private transient Paint baseSeriesOutlinePaint;
214:
215:
216: private transient Stroke seriesOutlineStroke;
217:
218:
219: private StrokeList seriesOutlineStrokeList;
220:
221:
222: private transient Stroke baseSeriesOutlineStroke;
223:
224:
225: private Font labelFont;
226:
227:
228: private transient Paint labelPaint;
229:
230:
231: private CategoryItemLabelGenerator labelGenerator;
232:
233:
234: private boolean webFilled = true;
235:
236:
237: private CategoryToolTipGenerator toolTipGenerator;
238:
239:
240: private CategoryURLGenerator urlGenerator;
241:
242:
245: public SpiderWebPlot() {
246: this(null);
247: }
248:
249:
255: public SpiderWebPlot(CategoryDataset dataset) {
256: this(dataset, TableOrder.BY_ROW);
257: }
258:
259:
266: public SpiderWebPlot(CategoryDataset dataset, TableOrder extract) {
267: super();
268: if (extract == null) {
269: throw new IllegalArgumentException("Null 'extract' argument.");
270: }
271: this.dataset = dataset;
272: if (dataset != null) {
273: dataset.addChangeListener(this);
274: }
275:
276: this.dataExtractOrder = extract;
277: this.headPercent = DEFAULT_HEAD;
278: this.axisLabelGap = DEFAULT_AXIS_LABEL_GAP;
279:
280: this.interiorGap = DEFAULT_INTERIOR_GAP;
281: this.startAngle = DEFAULT_START_ANGLE;
282: this.direction = Rotation.CLOCKWISE;
283: this.maxValue = DEFAULT_MAX_VALUE;
284:
285: this.seriesPaint = null;
286: this.seriesPaintList = new PaintList();
287: this.baseSeriesPaint = null;
288:
289: this.seriesOutlinePaint = null;
290: this.seriesOutlinePaintList = new PaintList();
291: this.baseSeriesOutlinePaint = DEFAULT_OUTLINE_PAINT;
292:
293: this.seriesOutlineStroke = null;
294: this.seriesOutlineStrokeList = new StrokeList();
295: this.baseSeriesOutlineStroke = DEFAULT_OUTLINE_STROKE;
296:
297: this.labelFont = DEFAULT_LABEL_FONT;
298: this.labelPaint = DEFAULT_LABEL_PAINT;
299: this.labelGenerator = new StandardCategoryItemLabelGenerator();
300:
301: this.legendItemShape = DEFAULT_LEGEND_ITEM_CIRCLE;
302: }
303:
304:
309: public String getPlotType() {
310:
311: return ("Spider Web Plot");
312: }
313:
314:
319: public CategoryDataset getDataset() {
320: return this.dataset;
321: }
322:
323:
329: public void setDataset(CategoryDataset dataset) {
330:
331:
332: if (this.dataset != null) {
333: this.dataset.removeChangeListener(this);
334: }
335:
336:
337: this.dataset = dataset;
338: if (dataset != null) {
339: setDatasetGroup(dataset.getGroup());
340: dataset.addChangeListener(this);
341: }
342:
343:
344: datasetChanged(new DatasetChangeEvent(this, dataset));
345: }
346:
347:
352: public boolean isWebFilled() {
353: return this.webFilled;
354: }
355:
356:
362: public void setWebFilled(boolean flag) {
363: this.webFilled = flag;
364: notifyListeners(new PlotChangeEvent(this));
365: }
366:
367:
374: public TableOrder getDataExtractOrder() {
375: return this.dataExtractOrder;
376: }
377:
378:
389: public void setDataExtractOrder(TableOrder order) {
390: if (order == null) {
391: throw new IllegalArgumentException("Null 'order' argument");
392: }
393: this.dataExtractOrder = order;
394: notifyListeners(new PlotChangeEvent(this));
395: }
396:
397:
402: public double getHeadPercent() {
403: return this.headPercent;
404: }
405:
406:
412: public void setHeadPercent(double percent) {
413: this.headPercent = percent;
414: notifyListeners(new PlotChangeEvent(this));
415: }
416:
417:
425: public double getStartAngle() {
426: return this.startAngle;
427: }
428:
429:
439: public void setStartAngle(double angle) {
440: this.startAngle = angle;
441: notifyListeners(new PlotChangeEvent(this));
442: }
443:
444:
449: public double getMaxValue() {
450: return this.maxValue;
451: }
452:
453:
459: public void setMaxValue(double value) {
460: this.maxValue = value;
461: notifyListeners(new PlotChangeEvent(this));
462: }
463:
464:
470: public Rotation getDirection() {
471: return this.direction;
472: }
473:
474:
480: public void setDirection(Rotation direction) {
481: if (direction == null) {
482: throw new IllegalArgumentException("Null 'direction' argument.");
483: }
484: this.direction = direction;
485: notifyListeners(new PlotChangeEvent(this));
486: }
487:
488:
494: public double getInteriorGap() {
495: return this.interiorGap;
496: }
497:
498:
505: public void setInteriorGap(double percent) {
506: if ((percent < 0.0) || (percent > MAX_INTERIOR_GAP)) {
507: throw new IllegalArgumentException(
508: "Percentage outside valid range.");
509: }
510: if (this.interiorGap != percent) {
511: this.interiorGap = percent;
512: notifyListeners(new PlotChangeEvent(this));
513: }
514: }
515:
516:
521: public double getAxisLabelGap() {
522: return this.axisLabelGap;
523: }
524:
525:
531: public void setAxisLabelGap(double gap) {
532: this.axisLabelGap = gap;
533: notifyListeners(new PlotChangeEvent(this));
534: }
535:
536:
537:
538:
543: public Paint getSeriesPaint() {
544: return this.seriesPaint;
545: }
546:
547:
554: public void setSeriesPaint(Paint paint) {
555: this.seriesPaint = paint;
556: notifyListeners(new PlotChangeEvent(this));
557: }
558:
559:
566: public Paint getSeriesPaint(int series) {
567:
568:
569: if (this.seriesPaint != null) {
570: return this.seriesPaint;
571: }
572:
573:
574: Paint result = this.seriesPaintList.getPaint(series);
575: if (result == null) {
576: DrawingSupplier supplier = getDrawingSupplier();
577: if (supplier != null) {
578: Paint p = supplier.getNextPaint();
579: this.seriesPaintList.setPaint(series, p);
580: result = p;
581: }
582: else {
583: result = this.baseSeriesPaint;
584: }
585: }
586: return result;
587:
588: }
589:
590:
597: public void setSeriesPaint(int series, Paint paint) {
598: this.seriesPaintList.setPaint(series, paint);
599: notifyListeners(new PlotChangeEvent(this));
600: }
601:
602:
608: public Paint getBaseSeriesPaint() {
609: return this.baseSeriesPaint;
610: }
611:
612:
617: public void setBaseSeriesPaint(Paint paint) {
618: if (paint == null) {
619: throw new IllegalArgumentException("Null 'paint' argument.");
620: }
621: this.baseSeriesPaint = paint;
622: notifyListeners(new PlotChangeEvent(this));
623: }
624:
625:
626:
627:
632: public Paint getSeriesOutlinePaint() {
633: return this.seriesOutlinePaint;
634: }
635:
636:
643: public void setSeriesOutlinePaint(Paint paint) {
644: this.seriesOutlinePaint = paint;
645: notifyListeners(new PlotChangeEvent(this));
646: }
647:
648:
655: public Paint getSeriesOutlinePaint(int series) {
656:
657: if (this.seriesOutlinePaint != null) {
658: return this.seriesOutlinePaint;
659: }
660:
661: Paint result = this.seriesOutlinePaintList.getPaint(series);
662: if (result == null) {
663: result = this.baseSeriesOutlinePaint;
664: }
665: return result;
666: }
667:
668:
675: public void setSeriesOutlinePaint(int series, Paint paint) {
676: this.seriesOutlinePaintList.setPaint(series, paint);
677: notifyListeners(new PlotChangeEvent(this));
678: }
679:
680:
686: public Paint getBaseSeriesOutlinePaint() {
687: return this.baseSeriesOutlinePaint;
688: }
689:
690:
695: public void setBaseSeriesOutlinePaint(Paint paint) {
696: if (paint == null) {
697: throw new IllegalArgumentException("Null 'paint' argument.");
698: }
699: this.baseSeriesOutlinePaint = paint;
700: notifyListeners(new PlotChangeEvent(this));
701: }
702:
703:
704:
705:
710: public Stroke getSeriesOutlineStroke() {
711: return this.seriesOutlineStroke;
712: }
713:
714:
721: public void setSeriesOutlineStroke(Stroke stroke) {
722: this.seriesOutlineStroke = stroke;
723: notifyListeners(new PlotChangeEvent(this));
724: }
725:
726:
733: public Stroke getSeriesOutlineStroke(int series) {
734:
735:
736: if (this.seriesOutlineStroke != null) {
737: return this.seriesOutlineStroke;
738: }
739:
740:
741: Stroke result = this.seriesOutlineStrokeList.getStroke(series);
742: if (result == null) {
743: result = this.baseSeriesOutlineStroke;
744: }
745: return result;
746:
747: }
748:
749:
756: public void setSeriesOutlineStroke(int series, Stroke stroke) {
757: this.seriesOutlineStrokeList.setStroke(series, stroke);
758: notifyListeners(new PlotChangeEvent(this));
759: }
760:
761:
767: public Stroke getBaseSeriesOutlineStroke() {
768: return this.baseSeriesOutlineStroke;
769: }
770:
771:
776: public void setBaseSeriesOutlineStroke(Stroke stroke) {
777: if (stroke == null) {
778: throw new IllegalArgumentException("Null 'stroke' argument.");
779: }
780: this.baseSeriesOutlineStroke = stroke;
781: notifyListeners(new PlotChangeEvent(this));
782: }
783:
784:
789: public Shape getLegendItemShape() {
790: return this.legendItemShape;
791: }
792:
793:
798: public void setLegendItemShape(Shape shape) {
799: if (shape == null) {
800: throw new IllegalArgumentException("Null 'shape' argument.");
801: }
802: this.legendItemShape = shape;
803: notifyListeners(new PlotChangeEvent(this));
804: }
805:
806:
811: public Font getLabelFont() {
812: return this.labelFont;
813: }
814:
815:
821: public void setLabelFont(Font font) {
822: if (font == null) {
823: throw new IllegalArgumentException("Null 'font' argument.");
824: }
825: this.labelFont = font;
826: notifyListeners(new PlotChangeEvent(this));
827: }
828:
829:
834: public Paint getLabelPaint() {
835: return this.labelPaint;
836: }
837:
838:
844: public void setLabelPaint(Paint paint) {
845: if (paint == null) {
846: throw new IllegalArgumentException("Null 'paint' argument.");
847: }
848: this.labelPaint = paint;
849: notifyListeners(new PlotChangeEvent(this));
850: }
851:
852:
857: public CategoryItemLabelGenerator getLabelGenerator() {
858: return this.labelGenerator;
859: }
860:
861:
867: public void setLabelGenerator(CategoryItemLabelGenerator generator) {
868: if (generator == null) {
869: throw new IllegalArgumentException("Null 'generator' argument.");
870: }
871: this.labelGenerator = generator;
872: }
873:
874:
883: public CategoryToolTipGenerator getToolTipGenerator() {
884: return this.toolTipGenerator;
885: }
886:
887:
897: public void setToolTipGenerator(CategoryToolTipGenerator generator) {
898: this.toolTipGenerator = generator;
899: this.notifyListeners(new PlotChangeEvent(this));
900: }
901:
902:
911: public CategoryURLGenerator getURLGenerator() {
912: return this.urlGenerator;
913: }
914:
915:
925: public void setURLGenerator(CategoryURLGenerator generator) {
926: this.urlGenerator = generator;
927: this.notifyListeners(new PlotChangeEvent(this));
928: }
929:
930:
935: public LegendItemCollection getLegendItems() {
936: LegendItemCollection result = new LegendItemCollection();
937:
938: List keys = null;
939:
940: if (this.dataExtractOrder == TableOrder.BY_ROW) {
941: keys = this.dataset.getRowKeys();
942: }
943: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
944: keys = this.dataset.getColumnKeys();
945: }
946:
947: if (keys != null) {
948: int series = 0;
949: Iterator iterator = keys.iterator();
950: Shape shape = getLegendItemShape();
951:
952: while (iterator.hasNext()) {
953: String label = iterator.next().toString();
954: String description = label;
955:
956: Paint paint = getSeriesPaint(series);
957: Paint outlinePaint = getSeriesOutlinePaint(series);
958: Stroke stroke = getSeriesOutlineStroke(series);
959: LegendItem item = new LegendItem(label, description,
960: null, null, shape, paint, stroke, outlinePaint);
961: result.add(item);
962: series++;
963: }
964: }
965:
966: return result;
967: }
968:
969:
978: protected Point2D getWebPoint(Rectangle2D bounds,
979: double angle, double length) {
980:
981: double angrad = Math.toRadians(angle);
982: double x = Math.cos(angrad) * length * bounds.getWidth() / 2;
983: double y = -Math.sin(angrad) * length * bounds.getHeight() / 2;
984:
985: return new Point2D.Double(bounds.getX() + x + bounds.getWidth() / 2,
986: bounds.getY() + y + bounds.getHeight() / 2);
987: }
988:
989:
999: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
1000: PlotState parentState,
1001: PlotRenderingInfo info)
1002: {
1003:
1004: RectangleInsets insets = getInsets();
1005: insets.trim(area);
1006:
1007: if (info != null) {
1008: info.setPlotArea(area);
1009: info.setDataArea(area);
1010: }
1011:
1012: drawBackground(g2, area);
1013: drawOutline(g2, area);
1014:
1015: Shape savedClip = g2.getClip();
1016:
1017: g2.clip(area);
1018: Composite originalComposite = g2.getComposite();
1019: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1020: getForegroundAlpha()));
1021:
1022: if (!DatasetUtilities.isEmptyOrNull(this.dataset)) {
1023: int seriesCount = 0, catCount = 0;
1024:
1025: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1026: seriesCount = this.dataset.getRowCount();
1027: catCount = this.dataset.getColumnCount();
1028: }
1029: else {
1030: seriesCount = this.dataset.getColumnCount();
1031: catCount = this.dataset.getRowCount();
1032: }
1033:
1034:
1035: if (this.maxValue == DEFAULT_MAX_VALUE)
1036: calculateMaxValue(seriesCount, catCount);
1037:
1038:
1039:
1040:
1041:
1042: double gapHorizontal = area.getWidth() * getInteriorGap();
1043: double gapVertical = area.getHeight() * getInteriorGap();
1044:
1045: double X = area.getX() + gapHorizontal / 2;
1046: double Y = area.getY() + gapVertical / 2;
1047: double W = area.getWidth() - gapHorizontal;
1048: double H = area.getHeight() - gapVertical;
1049:
1050: double headW = area.getWidth() * this.headPercent;
1051: double headH = area.getHeight() * this.headPercent;
1052:
1053:
1054: double min = Math.min(W, H) / 2;
1055: X = (X + X + W) / 2 - min;
1056: Y = (Y + Y + H) / 2 - min;
1057: W = 2 * min;
1058: H = 2 * min;
1059:
1060: Point2D centre = new Point2D.Double(X + W / 2, Y + H / 2);
1061: Rectangle2D radarArea = new Rectangle2D.Double(X, Y, W, H);
1062:
1063:
1064:
1065: for (int series = 0; series < seriesCount; series++) {
1066: drawRadarPoly(g2, radarArea, centre, info, series, catCount,
1067: headH, headW);
1068: }
1069: }
1070: else {
1071: drawNoDataMessage(g2, area);
1072: }
1073: g2.clip(savedClip);
1074: g2.setComposite(originalComposite);
1075: drawOutline(g2, area);
1076: }
1077:
1078:
1085: private void calculateMaxValue(int seriesCount, int catCount) {
1086: double v = 0;
1087: Number nV = null;
1088:
1089: for (int seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
1090: for (int catIndex = 0; catIndex < catCount; catIndex++) {
1091: nV = getPlotValue(seriesIndex, catIndex);
1092: if (nV != null) {
1093: v = nV.doubleValue();
1094: if (v > this.maxValue) {
1095: this.maxValue = v;
1096: }
1097: }
1098: }
1099: }
1100: }
1101:
1102:
1114: protected void drawRadarPoly(Graphics2D g2,
1115: Rectangle2D plotArea,
1116: Point2D centre,
1117: PlotRenderingInfo info,
1118: int series, int catCount,
1119: double headH, double headW) {
1120:
1121: Polygon polygon = new Polygon();
1122:
1123: EntityCollection entities = null;
1124: if (info != null) {
1125: entities = info.getOwner().getEntityCollection();
1126: }
1127:
1128:
1129: for (int cat = 0; cat < catCount; cat++) {
1130: Number dataValue = getPlotValue(series, cat);
1131:
1132: if (dataValue != null) {
1133: double value = dataValue.doubleValue();
1134:
1135: if (value >= 0) {
1136:
1137:
1138:
1139: double angle = getStartAngle()
1140: + (getDirection().getFactor() * cat * 360 / catCount);
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153: Point2D point = getWebPoint(plotArea, angle,
1154: value / this.maxValue);
1155: polygon.addPoint((int) point.getX(), (int) point.getY());
1156:
1157:
1158:
1159: Paint paint = getSeriesPaint(series);
1160: Paint outlinePaint = getSeriesOutlinePaint(series);
1161: Stroke outlineStroke = getSeriesOutlineStroke(series);
1162:
1163: Ellipse2D head = new Ellipse2D.Double(point.getX()
1164: - headW / 2, point.getY() - headH / 2, headW,
1165: headH);
1166: g2.setPaint(paint);
1167: g2.fill(head);
1168: g2.setStroke(outlineStroke);
1169: g2.setPaint(outlinePaint);
1170: g2.draw(head);
1171:
1172: if (entities != null) {
1173: String tip = null;
1174: if (this.toolTipGenerator != null) {
1175: tip = this.toolTipGenerator.generateToolTip(
1176: this.dataset, series, cat);
1177: }
1178:
1179: String url = null;
1180: if (this.urlGenerator != null) {
1181: url = this.urlGenerator.generateURL(this.dataset,
1182: series, cat);
1183: }
1184:
1185: Shape area = new Rectangle((int) (point.getX() - headW),
1186: (int) (point.getY() - headH),
1187: (int) (headW * 2), (int) (headH * 2));
1188: CategoryItemEntity entity = new CategoryItemEntity(
1189: area, tip, url, this.dataset, series,
1190: dataset.getColumnKey(cat), cat);
1191: entities.add(entity);
1192: }
1193:
1194:
1195:
1196:
1197: if (series == 0) {
1198: Point2D endPoint = getWebPoint(plotArea, angle, 1);
1199:
1200: Line2D line = new Line2D.Double(centre, endPoint);
1201: g2.draw(line);
1202: drawLabel(g2, plotArea, value, cat, angle,
1203: 360.0 / catCount);
1204: }
1205: }
1206: }
1207: }
1208:
1209:
1210: Paint paint = getSeriesPaint(series);
1211: g2.setPaint(paint);
1212: g2.draw(polygon);
1213:
1214:
1215:
1216: if (this.webFilled) {
1217: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1218: 0.1f));
1219: g2.fill(polygon);
1220: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1221: getForegroundAlpha()));
1222: }
1223: }
1224:
1225:
1236: Number getPlotValue(int series, int cat) {
1237: Number value = null;
1238: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1239: value = this.dataset.getValue(series, cat);
1240: }
1241: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
1242: value = this.dataset.getValue(cat, series);
1243: }
1244: return value;
1245: }
1246:
1247:
1257: protected void drawLabel(Graphics2D g2, Rectangle2D plotArea, double value,
1258: int cat, double startAngle, double extent) {
1259: FontRenderContext frc = g2.getFontRenderContext();
1260:
1261: String label = null;
1262: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1263:
1264: label = this.labelGenerator.generateColumnLabel(this.dataset, cat);
1265: }
1266: else {
1267:
1268: label = this.labelGenerator.generateRowLabel(this.dataset, cat);
1269: }
1270:
1271: Rectangle2D labelBounds = getLabelFont().getStringBounds(label, frc);
1272: LineMetrics lm = getLabelFont().getLineMetrics(label, frc);
1273: double ascent = lm.getAscent();
1274:
1275: Point2D labelLocation = calculateLabelLocation(labelBounds, ascent,
1276: plotArea, startAngle);
1277:
1278: Composite saveComposite = g2.getComposite();
1279:
1280: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1281: 1.0f));
1282: g2.setPaint(getLabelPaint());
1283: g2.setFont(getLabelFont());
1284: g2.drawString(label, (float) labelLocation.getX(),
1285: (float) labelLocation.getY());
1286: g2.setComposite(saveComposite);
1287: }
1288:
1289:
1299: protected Point2D calculateLabelLocation(Rectangle2D labelBounds,
1300: double ascent,
1301: Rectangle2D plotArea,
1302: double startAngle)
1303: {
1304: Arc2D arc1 = new Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN);
1305: Point2D point1 = arc1.getEndPoint();
1306:
1307: double deltaX = -(point1.getX() - plotArea.getCenterX())
1308: * this.axisLabelGap;
1309: double deltaY = -(point1.getY() - plotArea.getCenterY())
1310: * this.axisLabelGap;
1311:
1312: double labelX = point1.getX() - deltaX;
1313: double labelY = point1.getY() - deltaY;
1314:
1315: if (labelX < plotArea.getCenterX()) {
1316: labelX -= labelBounds.getWidth();
1317: }
1318:
1319: if (labelX == plotArea.getCenterX()) {
1320: labelX -= labelBounds.getWidth() / 2;
1321: }
1322:
1323: if (labelY > plotArea.getCenterY()) {
1324: labelY += ascent;
1325: }
1326:
1327: return new Point2D.Double(labelX, labelY);
1328: }
1329:
1330:
1337: public boolean equals(Object obj) {
1338: if (obj == this) {
1339: return true;
1340: }
1341: if (!(obj instanceof SpiderWebPlot)) {
1342: return false;
1343: }
1344: if (!super.equals(obj)) {
1345: return false;
1346: }
1347: SpiderWebPlot that = (SpiderWebPlot) obj;
1348: if (!this.dataExtractOrder.equals(that.dataExtractOrder)) {
1349: return false;
1350: }
1351: if (this.headPercent != that.headPercent) {
1352: return false;
1353: }
1354: if (this.interiorGap != that.interiorGap) {
1355: return false;
1356: }
1357: if (this.startAngle != that.startAngle) {
1358: return false;
1359: }
1360: if (!this.direction.equals(that.direction)) {
1361: return false;
1362: }
1363: if (this.maxValue != that.maxValue) {
1364: return false;
1365: }
1366: if (this.webFilled != that.webFilled) {
1367: return false;
1368: }
1369: if (!ShapeUtilities.equal(this.legendItemShape, that.legendItemShape)) {
1370: return false;
1371: }
1372: if (!PaintUtilities.equal(this.seriesPaint, that.seriesPaint)) {
1373: return false;
1374: }
1375: if (!this.seriesPaintList.equals(that.seriesPaintList)) {
1376: return false;
1377: }
1378: if (!PaintUtilities.equal(this.baseSeriesPaint, that.baseSeriesPaint)) {
1379: return false;
1380: }
1381: if (!PaintUtilities.equal(this.seriesOutlinePaint,
1382: that.seriesOutlinePaint)) {
1383: return false;
1384: }
1385: if (!this.seriesOutlinePaintList.equals(that.seriesOutlinePaintList)) {
1386: return false;
1387: }
1388: if (!PaintUtilities.equal(this.baseSeriesOutlinePaint,
1389: that.baseSeriesOutlinePaint)) {
1390: return false;
1391: }
1392: if (!ObjectUtilities.equal(this.seriesOutlineStroke,
1393: that.seriesOutlineStroke)) {
1394: return false;
1395: }
1396: if (!this.seriesOutlineStrokeList.equals(
1397: that.seriesOutlineStrokeList)) {
1398: return false;
1399: }
1400: if (!this.baseSeriesOutlineStroke.equals(
1401: that.baseSeriesOutlineStroke)) {
1402: return false;
1403: }
1404: if (!this.labelFont.equals(that.labelFont)) {
1405: return false;
1406: }
1407: if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
1408: return false;
1409: }
1410: if (!this.labelGenerator.equals(that.labelGenerator)) {
1411: return false;
1412: }
1413: if (!ObjectUtilities.equal(this.toolTipGenerator,
1414: that.toolTipGenerator)) {
1415: return false;
1416: }
1417: if (!ObjectUtilities.equal(this.urlGenerator,
1418: that.urlGenerator)) {
1419: return false;
1420: }
1421: return true;
1422: }
1423:
1424:
1431: private void writeObject(ObjectOutputStream stream) throws IOException {
1432: stream.defaultWriteObject();
1433:
1434: SerialUtilities.writeShape(this.legendItemShape, stream);
1435: SerialUtilities.writePaint(this.seriesPaint, stream);
1436: SerialUtilities.writePaint(this.baseSeriesPaint, stream);
1437: SerialUtilities.writePaint(this.seriesOutlinePaint, stream);
1438: SerialUtilities.writePaint(this.baseSeriesOutlinePaint, stream);
1439: SerialUtilities.writeStroke(this.seriesOutlineStroke, stream);
1440: SerialUtilities.writeStroke(this.baseSeriesOutlineStroke, stream);
1441: SerialUtilities.writePaint(this.labelPaint, stream);
1442: }
1443:
1444:
1452: private void readObject(ObjectInputStream stream) throws IOException,
1453: ClassNotFoundException {
1454: stream.defaultReadObject();
1455:
1456: this.legendItemShape = SerialUtilities.readShape(stream);
1457: this.seriesPaint = SerialUtilities.readPaint(stream);
1458: this.baseSeriesPaint = SerialUtilities.readPaint(stream);
1459: this.seriesOutlinePaint = SerialUtilities.readPaint(stream);
1460: this.baseSeriesOutlinePaint = SerialUtilities.readPaint(stream);
1461: this.seriesOutlineStroke = SerialUtilities.readStroke(stream);
1462: this.baseSeriesOutlineStroke = SerialUtilities.readStroke(stream);
1463: this.labelPaint = SerialUtilities.readPaint(stream);
1464:
1465: if (dataset != null) {
1466: dataset.addChangeListener(this);
1467: }
1468: }
1469:
1470: }