1:
68:
69: package ;
70:
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: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95:
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: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117:
118:
123: public class SpiderWebPlot extends Plot implements Cloneable, Serializable {
124:
125:
126: private static final long serialVersionUID = -5376340422031599463L;
127:
128:
129: public static final double DEFAULT_HEAD = 0.01;
130:
131:
132: public static final double DEFAULT_AXIS_LABEL_GAP = 0.10;
133:
134:
135: public static final double DEFAULT_INTERIOR_GAP = 0.25;
136:
137:
138: public static final double MAX_INTERIOR_GAP = 0.40;
139:
140:
141: public static final double DEFAULT_START_ANGLE = 90.0;
142:
143:
144: public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
145: Font.PLAIN, 10);
146:
147:
148: public static final Paint DEFAULT_LABEL_PAINT = Color.black;
149:
150:
151: public static final Paint DEFAULT_LABEL_BACKGROUND_PAINT
152: = new Color(255, 255, 192);
153:
154:
155: public static final Paint DEFAULT_LABEL_OUTLINE_PAINT = Color.black;
156:
157:
158: public static final Stroke DEFAULT_LABEL_OUTLINE_STROKE
159: = new BasicStroke(0.5f);
160:
161:
162: public static final Paint DEFAULT_LABEL_SHADOW_PAINT = Color.lightGray;
163:
164:
168: public static final double DEFAULT_MAX_VALUE = -1.0;
169:
170:
171: protected double headPercent;
172:
173:
174: private double interiorGap;
175:
176:
177: private double axisLabelGap;
178:
179:
184: private transient Paint axisLinePaint;
185:
186:
191: private transient Stroke axisLineStroke;
192:
193:
194: private CategoryDataset dataset;
195:
196:
197: private double maxValue;
198:
199:
205: private TableOrder dataExtractOrder;
206:
207:
208: private double startAngle;
209:
210:
211: private Rotation direction;
212:
213:
214: private transient Shape legendItemShape;
215:
216:
217: private transient Paint seriesPaint;
218:
219:
220: private PaintList seriesPaintList;
221:
222:
223: private transient Paint baseSeriesPaint;
224:
225:
226: private transient Paint seriesOutlinePaint;
227:
228:
229: private PaintList seriesOutlinePaintList;
230:
231:
232: private transient Paint baseSeriesOutlinePaint;
233:
234:
235: private transient Stroke seriesOutlineStroke;
236:
237:
238: private StrokeList seriesOutlineStrokeList;
239:
240:
241: private transient Stroke baseSeriesOutlineStroke;
242:
243:
244: private Font labelFont;
245:
246:
247: private transient Paint labelPaint;
248:
249:
250: private CategoryItemLabelGenerator labelGenerator;
251:
252:
253: private boolean webFilled = true;
254:
255:
256: private CategoryToolTipGenerator toolTipGenerator;
257:
258:
259: private CategoryURLGenerator urlGenerator;
260:
261:
264: public SpiderWebPlot() {
265: this(null);
266: }
267:
268:
274: public SpiderWebPlot(CategoryDataset dataset) {
275: this(dataset, TableOrder.BY_ROW);
276: }
277:
278:
285: public SpiderWebPlot(CategoryDataset dataset, TableOrder extract) {
286: super();
287: if (extract == null) {
288: throw new IllegalArgumentException("Null 'extract' argument.");
289: }
290: this.dataset = dataset;
291: if (dataset != null) {
292: dataset.addChangeListener(this);
293: }
294:
295: this.dataExtractOrder = extract;
296: this.headPercent = DEFAULT_HEAD;
297: this.axisLabelGap = DEFAULT_AXIS_LABEL_GAP;
298: this.axisLinePaint = Color.black;
299: this.axisLineStroke = new BasicStroke(1.0f);
300:
301: this.interiorGap = DEFAULT_INTERIOR_GAP;
302: this.startAngle = DEFAULT_START_ANGLE;
303: this.direction = Rotation.CLOCKWISE;
304: this.maxValue = DEFAULT_MAX_VALUE;
305:
306: this.seriesPaint = null;
307: this.seriesPaintList = new PaintList();
308: this.baseSeriesPaint = null;
309:
310: this.seriesOutlinePaint = null;
311: this.seriesOutlinePaintList = new PaintList();
312: this.baseSeriesOutlinePaint = DEFAULT_OUTLINE_PAINT;
313:
314: this.seriesOutlineStroke = null;
315: this.seriesOutlineStrokeList = new StrokeList();
316: this.baseSeriesOutlineStroke = DEFAULT_OUTLINE_STROKE;
317:
318: this.labelFont = DEFAULT_LABEL_FONT;
319: this.labelPaint = DEFAULT_LABEL_PAINT;
320: this.labelGenerator = new StandardCategoryItemLabelGenerator();
321:
322: this.legendItemShape = DEFAULT_LEGEND_ITEM_CIRCLE;
323: }
324:
325:
330: public String getPlotType() {
331:
332: return ("Spider Web Plot");
333: }
334:
335:
342: public CategoryDataset getDataset() {
343: return this.dataset;
344: }
345:
346:
354: public void setDataset(CategoryDataset dataset) {
355:
356:
357: if (this.dataset != null) {
358: this.dataset.removeChangeListener(this);
359: }
360:
361:
362: this.dataset = dataset;
363: if (dataset != null) {
364: setDatasetGroup(dataset.getGroup());
365: dataset.addChangeListener(this);
366: }
367:
368:
369: datasetChanged(new DatasetChangeEvent(this, dataset));
370: }
371:
372:
379: public boolean isWebFilled() {
380: return this.webFilled;
381: }
382:
383:
391: public void setWebFilled(boolean flag) {
392: this.webFilled = flag;
393: notifyListeners(new PlotChangeEvent(this));
394: }
395:
396:
403: public TableOrder getDataExtractOrder() {
404: return this.dataExtractOrder;
405: }
406:
407:
418: public void setDataExtractOrder(TableOrder order) {
419: if (order == null) {
420: throw new IllegalArgumentException("Null 'order' argument");
421: }
422: this.dataExtractOrder = order;
423: notifyListeners(new PlotChangeEvent(this));
424: }
425:
426:
433: public double getHeadPercent() {
434: return this.headPercent;
435: }
436:
437:
445: public void setHeadPercent(double percent) {
446: this.headPercent = percent;
447: notifyListeners(new PlotChangeEvent(this));
448: }
449:
450:
460: public double getStartAngle() {
461: return this.startAngle;
462: }
463:
464:
476: public void setStartAngle(double angle) {
477: this.startAngle = angle;
478: notifyListeners(new PlotChangeEvent(this));
479: }
480:
481:
488: public double getMaxValue() {
489: return this.maxValue;
490: }
491:
492:
500: public void setMaxValue(double value) {
501: this.maxValue = value;
502: notifyListeners(new PlotChangeEvent(this));
503: }
504:
505:
513: public Rotation getDirection() {
514: return this.direction;
515: }
516:
517:
525: public void setDirection(Rotation direction) {
526: if (direction == null) {
527: throw new IllegalArgumentException("Null 'direction' argument.");
528: }
529: this.direction = direction;
530: notifyListeners(new PlotChangeEvent(this));
531: }
532:
533:
541: public double getInteriorGap() {
542: return this.interiorGap;
543: }
544:
545:
554: public void setInteriorGap(double percent) {
555: if ((percent < 0.0) || (percent > MAX_INTERIOR_GAP)) {
556: throw new IllegalArgumentException(
557: "Percentage outside valid range.");
558: }
559: if (this.interiorGap != percent) {
560: this.interiorGap = percent;
561: notifyListeners(new PlotChangeEvent(this));
562: }
563: }
564:
565:
572: public double getAxisLabelGap() {
573: return this.axisLabelGap;
574: }
575:
576:
584: public void setAxisLabelGap(double gap) {
585: this.axisLabelGap = gap;
586: notifyListeners(new PlotChangeEvent(this));
587: }
588:
589:
598: public Paint getAxisLinePaint() {
599: return this.axisLinePaint;
600: }
601:
602:
611: public void setAxisLinePaint(Paint paint) {
612: if (paint == null) {
613: throw new IllegalArgumentException("Null 'paint' argument.");
614: }
615: this.axisLinePaint = paint;
616: notifyListeners(new PlotChangeEvent(this));
617: }
618:
619:
628: public Stroke getAxisLineStroke() {
629: return this.axisLineStroke;
630: }
631:
632:
641: public void setAxisLineStroke(Stroke stroke) {
642: if (stroke == null) {
643: throw new IllegalArgumentException("Null 'stroke' argument.");
644: }
645: this.axisLineStroke = stroke;
646: notifyListeners(new PlotChangeEvent(this));
647: }
648:
649:
650:
651:
658: public Paint getSeriesPaint() {
659: return this.seriesPaint;
660: }
661:
662:
671: public void setSeriesPaint(Paint paint) {
672: this.seriesPaint = paint;
673: notifyListeners(new PlotChangeEvent(this));
674: }
675:
676:
685: public Paint getSeriesPaint(int series) {
686:
687:
688: if (this.seriesPaint != null) {
689: return this.seriesPaint;
690: }
691:
692:
693: Paint result = this.seriesPaintList.getPaint(series);
694: if (result == null) {
695: DrawingSupplier supplier = getDrawingSupplier();
696: if (supplier != null) {
697: Paint p = supplier.getNextPaint();
698: this.seriesPaintList.setPaint(series, p);
699: result = p;
700: }
701: else {
702: result = this.baseSeriesPaint;
703: }
704: }
705: return result;
706:
707: }
708:
709:
718: public void setSeriesPaint(int series, Paint paint) {
719: this.seriesPaintList.setPaint(series, paint);
720: notifyListeners(new PlotChangeEvent(this));
721: }
722:
723:
731: public Paint getBaseSeriesPaint() {
732: return this.baseSeriesPaint;
733: }
734:
735:
742: public void setBaseSeriesPaint(Paint paint) {
743: if (paint == null) {
744: throw new IllegalArgumentException("Null 'paint' argument.");
745: }
746: this.baseSeriesPaint = paint;
747: notifyListeners(new PlotChangeEvent(this));
748: }
749:
750:
751:
752:
757: public Paint getSeriesOutlinePaint() {
758: return this.seriesOutlinePaint;
759: }
760:
761:
768: public void setSeriesOutlinePaint(Paint paint) {
769: this.seriesOutlinePaint = paint;
770: notifyListeners(new PlotChangeEvent(this));
771: }
772:
773:
780: public Paint getSeriesOutlinePaint(int series) {
781:
782: if (this.seriesOutlinePaint != null) {
783: return this.seriesOutlinePaint;
784: }
785:
786: Paint result = this.seriesOutlinePaintList.getPaint(series);
787: if (result == null) {
788: result = this.baseSeriesOutlinePaint;
789: }
790: return result;
791: }
792:
793:
800: public void setSeriesOutlinePaint(int series, Paint paint) {
801: this.seriesOutlinePaintList.setPaint(series, paint);
802: notifyListeners(new PlotChangeEvent(this));
803: }
804:
805:
811: public Paint getBaseSeriesOutlinePaint() {
812: return this.baseSeriesOutlinePaint;
813: }
814:
815:
820: public void setBaseSeriesOutlinePaint(Paint paint) {
821: if (paint == null) {
822: throw new IllegalArgumentException("Null 'paint' argument.");
823: }
824: this.baseSeriesOutlinePaint = paint;
825: notifyListeners(new PlotChangeEvent(this));
826: }
827:
828:
829:
830:
835: public Stroke getSeriesOutlineStroke() {
836: return this.seriesOutlineStroke;
837: }
838:
839:
846: public void setSeriesOutlineStroke(Stroke stroke) {
847: this.seriesOutlineStroke = stroke;
848: notifyListeners(new PlotChangeEvent(this));
849: }
850:
851:
858: public Stroke getSeriesOutlineStroke(int series) {
859:
860:
861: if (this.seriesOutlineStroke != null) {
862: return this.seriesOutlineStroke;
863: }
864:
865:
866: Stroke result = this.seriesOutlineStrokeList.getStroke(series);
867: if (result == null) {
868: result = this.baseSeriesOutlineStroke;
869: }
870: return result;
871:
872: }
873:
874:
881: public void setSeriesOutlineStroke(int series, Stroke stroke) {
882: this.seriesOutlineStrokeList.setStroke(series, stroke);
883: notifyListeners(new PlotChangeEvent(this));
884: }
885:
886:
892: public Stroke getBaseSeriesOutlineStroke() {
893: return this.baseSeriesOutlineStroke;
894: }
895:
896:
901: public void setBaseSeriesOutlineStroke(Stroke stroke) {
902: if (stroke == null) {
903: throw new IllegalArgumentException("Null 'stroke' argument.");
904: }
905: this.baseSeriesOutlineStroke = stroke;
906: notifyListeners(new PlotChangeEvent(this));
907: }
908:
909:
916: public Shape getLegendItemShape() {
917: return this.legendItemShape;
918: }
919:
920:
928: public void setLegendItemShape(Shape shape) {
929: if (shape == null) {
930: throw new IllegalArgumentException("Null 'shape' argument.");
931: }
932: this.legendItemShape = shape;
933: notifyListeners(new PlotChangeEvent(this));
934: }
935:
936:
943: public Font getLabelFont() {
944: return this.labelFont;
945: }
946:
947:
955: public void setLabelFont(Font font) {
956: if (font == null) {
957: throw new IllegalArgumentException("Null 'font' argument.");
958: }
959: this.labelFont = font;
960: notifyListeners(new PlotChangeEvent(this));
961: }
962:
963:
970: public Paint getLabelPaint() {
971: return this.labelPaint;
972: }
973:
974:
982: public void setLabelPaint(Paint paint) {
983: if (paint == null) {
984: throw new IllegalArgumentException("Null 'paint' argument.");
985: }
986: this.labelPaint = paint;
987: notifyListeners(new PlotChangeEvent(this));
988: }
989:
990:
997: public CategoryItemLabelGenerator getLabelGenerator() {
998: return this.labelGenerator;
999: }
1000:
1001:
1009: public void setLabelGenerator(CategoryItemLabelGenerator generator) {
1010: if (generator == null) {
1011: throw new IllegalArgumentException("Null 'generator' argument.");
1012: }
1013: this.labelGenerator = generator;
1014: }
1015:
1016:
1025: public CategoryToolTipGenerator getToolTipGenerator() {
1026: return this.toolTipGenerator;
1027: }
1028:
1029:
1039: public void setToolTipGenerator(CategoryToolTipGenerator generator) {
1040: this.toolTipGenerator = generator;
1041: this.notifyListeners(new PlotChangeEvent(this));
1042: }
1043:
1044:
1053: public CategoryURLGenerator getURLGenerator() {
1054: return this.urlGenerator;
1055: }
1056:
1057:
1067: public void setURLGenerator(CategoryURLGenerator generator) {
1068: this.urlGenerator = generator;
1069: this.notifyListeners(new PlotChangeEvent(this));
1070: }
1071:
1072:
1077: public LegendItemCollection getLegendItems() {
1078: LegendItemCollection result = new LegendItemCollection();
1079:
1080: List keys = null;
1081:
1082: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1083: keys = this.dataset.getRowKeys();
1084: }
1085: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
1086: keys = this.dataset.getColumnKeys();
1087: }
1088:
1089: if (keys != null) {
1090: int series = 0;
1091: Iterator iterator = keys.iterator();
1092: Shape shape = getLegendItemShape();
1093:
1094: while (iterator.hasNext()) {
1095: String label = iterator.next().toString();
1096: String description = label;
1097:
1098: Paint paint = getSeriesPaint(series);
1099: Paint outlinePaint = getSeriesOutlinePaint(series);
1100: Stroke stroke = getSeriesOutlineStroke(series);
1101: LegendItem item = new LegendItem(label, description,
1102: null, null, shape, paint, stroke, outlinePaint);
1103: result.add(item);
1104: series++;
1105: }
1106: }
1107:
1108: return result;
1109: }
1110:
1111:
1120: protected Point2D getWebPoint(Rectangle2D bounds,
1121: double angle, double length) {
1122:
1123: double angrad = Math.toRadians(angle);
1124: double x = Math.cos(angrad) * length * bounds.getWidth() / 2;
1125: double y = -Math.sin(angrad) * length * bounds.getHeight() / 2;
1126:
1127: return new Point2D.Double(bounds.getX() + x + bounds.getWidth() / 2,
1128: bounds.getY() + y + bounds.getHeight() / 2);
1129: }
1130:
1131:
1141: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
1142: PlotState parentState,
1143: PlotRenderingInfo info)
1144: {
1145:
1146: RectangleInsets insets = getInsets();
1147: insets.trim(area);
1148:
1149: if (info != null) {
1150: info.setPlotArea(area);
1151: info.setDataArea(area);
1152: }
1153:
1154: drawBackground(g2, area);
1155: drawOutline(g2, area);
1156:
1157: Shape savedClip = g2.getClip();
1158:
1159: g2.clip(area);
1160: Composite originalComposite = g2.getComposite();
1161: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1162: getForegroundAlpha()));
1163:
1164: if (!DatasetUtilities.isEmptyOrNull(this.dataset)) {
1165: int seriesCount = 0, catCount = 0;
1166:
1167: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1168: seriesCount = this.dataset.getRowCount();
1169: catCount = this.dataset.getColumnCount();
1170: }
1171: else {
1172: seriesCount = this.dataset.getColumnCount();
1173: catCount = this.dataset.getRowCount();
1174: }
1175:
1176:
1177: if (this.maxValue == DEFAULT_MAX_VALUE)
1178: calculateMaxValue(seriesCount, catCount);
1179:
1180:
1181:
1182:
1183:
1184: double gapHorizontal = area.getWidth() * getInteriorGap();
1185: double gapVertical = area.getHeight() * getInteriorGap();
1186:
1187: double X = area.getX() + gapHorizontal / 2;
1188: double Y = area.getY() + gapVertical / 2;
1189: double W = area.getWidth() - gapHorizontal;
1190: double H = area.getHeight() - gapVertical;
1191:
1192: double headW = area.getWidth() * this.headPercent;
1193: double headH = area.getHeight() * this.headPercent;
1194:
1195:
1196: double min = Math.min(W, H) / 2;
1197: X = (X + X + W) / 2 - min;
1198: Y = (Y + Y + H) / 2 - min;
1199: W = 2 * min;
1200: H = 2 * min;
1201:
1202: Point2D centre = new Point2D.Double(X + W / 2, Y + H / 2);
1203: Rectangle2D radarArea = new Rectangle2D.Double(X, Y, W, H);
1204:
1205:
1206: for (int cat = 0; cat < catCount; cat++) {
1207: double angle = getStartAngle()
1208: + (getDirection().getFactor() * cat * 360 / catCount);
1209:
1210: Point2D endPoint = getWebPoint(radarArea, angle, 1);
1211:
1212: Line2D line = new Line2D.Double(centre, endPoint);
1213: g2.setPaint(this.axisLinePaint);
1214: g2.setStroke(this.axisLineStroke);
1215: g2.draw(line);
1216: drawLabel(g2, radarArea, 0.0, cat, angle, 360.0 / catCount);
1217: }
1218:
1219:
1220: for (int series = 0; series < seriesCount; series++) {
1221: drawRadarPoly(g2, radarArea, centre, info, series, catCount,
1222: headH, headW);
1223: }
1224: }
1225: else {
1226: drawNoDataMessage(g2, area);
1227: }
1228: g2.setClip(savedClip);
1229: g2.setComposite(originalComposite);
1230: drawOutline(g2, area);
1231: }
1232:
1233:
1240: private void calculateMaxValue(int seriesCount, int catCount) {
1241: double v = 0;
1242: Number nV = null;
1243:
1244: for (int seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
1245: for (int catIndex = 0; catIndex < catCount; catIndex++) {
1246: nV = getPlotValue(seriesIndex, catIndex);
1247: if (nV != null) {
1248: v = nV.doubleValue();
1249: if (v > this.maxValue) {
1250: this.maxValue = v;
1251: }
1252: }
1253: }
1254: }
1255: }
1256:
1257:
1269: protected void drawRadarPoly(Graphics2D g2,
1270: Rectangle2D plotArea,
1271: Point2D centre,
1272: PlotRenderingInfo info,
1273: int series, int catCount,
1274: double headH, double headW) {
1275:
1276: Polygon polygon = new Polygon();
1277:
1278: EntityCollection entities = null;
1279: if (info != null) {
1280: entities = info.getOwner().getEntityCollection();
1281: }
1282:
1283:
1284: for (int cat = 0; cat < catCount; cat++) {
1285:
1286: Number dataValue = getPlotValue(series, cat);
1287:
1288: if (dataValue != null) {
1289: double value = dataValue.doubleValue();
1290:
1291: if (value >= 0) {
1292:
1293:
1294:
1295: double angle = getStartAngle()
1296: + (getDirection().getFactor() * cat * 360 / catCount);
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309: Point2D point = getWebPoint(plotArea, angle,
1310: value / this.maxValue);
1311: polygon.addPoint((int) point.getX(), (int) point.getY());
1312:
1313:
1314:
1315: Paint paint = getSeriesPaint(series);
1316: Paint outlinePaint = getSeriesOutlinePaint(series);
1317: Stroke outlineStroke = getSeriesOutlineStroke(series);
1318:
1319: Ellipse2D head = new Ellipse2D.Double(point.getX()
1320: - headW / 2, point.getY() - headH / 2, headW,
1321: headH);
1322: g2.setPaint(paint);
1323: g2.fill(head);
1324: g2.setStroke(outlineStroke);
1325: g2.setPaint(outlinePaint);
1326: g2.draw(head);
1327:
1328: if (entities != null) {
1329: String tip = null;
1330: if (this.toolTipGenerator != null) {
1331: tip = this.toolTipGenerator.generateToolTip(
1332: this.dataset, series, cat);
1333: }
1334:
1335: String url = null;
1336: if (this.urlGenerator != null) {
1337: url = this.urlGenerator.generateURL(this.dataset,
1338: series, cat);
1339: }
1340:
1341: Shape area = new Rectangle((int) (point.getX() - headW),
1342: (int) (point.getY() - headH),
1343: (int) (headW * 2), (int) (headH * 2));
1344: CategoryItemEntity entity = new CategoryItemEntity(
1345: area, tip, url, this.dataset, series,
1346: this.dataset.getColumnKey(cat), cat);
1347: entities.add(entity);
1348: }
1349:
1350: }
1351: }
1352: }
1353:
1354:
1355: Paint paint = getSeriesPaint(series);
1356: g2.setPaint(paint);
1357: g2.setStroke(getSeriesOutlineStroke(series));
1358: g2.draw(polygon);
1359:
1360:
1361:
1362: if (this.webFilled) {
1363: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1364: 0.1f));
1365: g2.fill(polygon);
1366: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1367: getForegroundAlpha()));
1368: }
1369: }
1370:
1371:
1385: protected Number getPlotValue(int series, int cat) {
1386: Number value = null;
1387: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1388: value = this.dataset.getValue(series, cat);
1389: }
1390: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
1391: value = this.dataset.getValue(cat, series);
1392: }
1393: return value;
1394: }
1395:
1396:
1406: protected void drawLabel(Graphics2D g2, Rectangle2D plotArea, double value,
1407: int cat, double startAngle, double extent) {
1408: FontRenderContext frc = g2.getFontRenderContext();
1409:
1410: String label = null;
1411: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1412:
1413: label = this.labelGenerator.generateColumnLabel(this.dataset, cat);
1414: }
1415: else {
1416:
1417: label = this.labelGenerator.generateRowLabel(this.dataset, cat);
1418: }
1419:
1420: Rectangle2D labelBounds = getLabelFont().getStringBounds(label, frc);
1421: LineMetrics lm = getLabelFont().getLineMetrics(label, frc);
1422: double ascent = lm.getAscent();
1423:
1424: Point2D labelLocation = calculateLabelLocation(labelBounds, ascent,
1425: plotArea, startAngle);
1426:
1427: Composite saveComposite = g2.getComposite();
1428:
1429: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1430: 1.0f));
1431: g2.setPaint(getLabelPaint());
1432: g2.setFont(getLabelFont());
1433: g2.drawString(label, (float) labelLocation.getX(),
1434: (float) labelLocation.getY());
1435: g2.setComposite(saveComposite);
1436: }
1437:
1438:
1448: protected Point2D calculateLabelLocation(Rectangle2D labelBounds,
1449: double ascent,
1450: Rectangle2D plotArea,
1451: double startAngle)
1452: {
1453: Arc2D arc1 = new Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN);
1454: Point2D point1 = arc1.getEndPoint();
1455:
1456: double deltaX = -(point1.getX() - plotArea.getCenterX())
1457: * this.axisLabelGap;
1458: double deltaY = -(point1.getY() - plotArea.getCenterY())
1459: * this.axisLabelGap;
1460:
1461: double labelX = point1.getX() - deltaX;
1462: double labelY = point1.getY() - deltaY;
1463:
1464: if (labelX < plotArea.getCenterX()) {
1465: labelX -= labelBounds.getWidth();
1466: }
1467:
1468: if (labelX == plotArea.getCenterX()) {
1469: labelX -= labelBounds.getWidth() / 2;
1470: }
1471:
1472: if (labelY > plotArea.getCenterY()) {
1473: labelY += ascent;
1474: }
1475:
1476: return new Point2D.Double(labelX, labelY);
1477: }
1478:
1479:
1486: public boolean equals(Object obj) {
1487: if (obj == this) {
1488: return true;
1489: }
1490: if (!(obj instanceof SpiderWebPlot)) {
1491: return false;
1492: }
1493: if (!super.equals(obj)) {
1494: return false;
1495: }
1496: SpiderWebPlot that = (SpiderWebPlot) obj;
1497: if (!this.dataExtractOrder.equals(that.dataExtractOrder)) {
1498: return false;
1499: }
1500: if (this.headPercent != that.headPercent) {
1501: return false;
1502: }
1503: if (this.interiorGap != that.interiorGap) {
1504: return false;
1505: }
1506: if (this.startAngle != that.startAngle) {
1507: return false;
1508: }
1509: if (!this.direction.equals(that.direction)) {
1510: return false;
1511: }
1512: if (this.maxValue != that.maxValue) {
1513: return false;
1514: }
1515: if (this.webFilled != that.webFilled) {
1516: return false;
1517: }
1518: if (this.axisLabelGap != that.axisLabelGap) {
1519: return false;
1520: }
1521: if (!PaintUtilities.equal(this.axisLinePaint, that.axisLinePaint)) {
1522: return false;
1523: }
1524: if (!this.axisLineStroke.equals(that.axisLineStroke)) {
1525: return false;
1526: }
1527: if (!ShapeUtilities.equal(this.legendItemShape, that.legendItemShape)) {
1528: return false;
1529: }
1530: if (!PaintUtilities.equal(this.seriesPaint, that.seriesPaint)) {
1531: return false;
1532: }
1533: if (!this.seriesPaintList.equals(that.seriesPaintList)) {
1534: return false;
1535: }
1536: if (!PaintUtilities.equal(this.baseSeriesPaint, that.baseSeriesPaint)) {
1537: return false;
1538: }
1539: if (!PaintUtilities.equal(this.seriesOutlinePaint,
1540: that.seriesOutlinePaint)) {
1541: return false;
1542: }
1543: if (!this.seriesOutlinePaintList.equals(that.seriesOutlinePaintList)) {
1544: return false;
1545: }
1546: if (!PaintUtilities.equal(this.baseSeriesOutlinePaint,
1547: that.baseSeriesOutlinePaint)) {
1548: return false;
1549: }
1550: if (!ObjectUtilities.equal(this.seriesOutlineStroke,
1551: that.seriesOutlineStroke)) {
1552: return false;
1553: }
1554: if (!this.seriesOutlineStrokeList.equals(
1555: that.seriesOutlineStrokeList)) {
1556: return false;
1557: }
1558: if (!this.baseSeriesOutlineStroke.equals(
1559: that.baseSeriesOutlineStroke)) {
1560: return false;
1561: }
1562: if (!this.labelFont.equals(that.labelFont)) {
1563: return false;
1564: }
1565: if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
1566: return false;
1567: }
1568: if (!this.labelGenerator.equals(that.labelGenerator)) {
1569: return false;
1570: }
1571: if (!ObjectUtilities.equal(this.toolTipGenerator,
1572: that.toolTipGenerator)) {
1573: return false;
1574: }
1575: if (!ObjectUtilities.equal(this.urlGenerator,
1576: that.urlGenerator)) {
1577: return false;
1578: }
1579: return true;
1580: }
1581:
1582:
1590: public Object clone() throws CloneNotSupportedException {
1591: SpiderWebPlot clone = (SpiderWebPlot) super.clone();
1592: clone.legendItemShape = ShapeUtilities.clone(this.legendItemShape);
1593: clone.seriesPaintList = (PaintList) this.seriesPaintList.clone();
1594: clone.seriesOutlinePaintList
1595: = (PaintList) this.seriesOutlinePaintList.clone();
1596: clone.seriesOutlineStrokeList
1597: = (StrokeList) this.seriesOutlineStrokeList.clone();
1598: return clone;
1599: }
1600:
1601:
1608: private void writeObject(ObjectOutputStream stream) throws IOException {
1609: stream.defaultWriteObject();
1610:
1611: SerialUtilities.writeShape(this.legendItemShape, stream);
1612: SerialUtilities.writePaint(this.seriesPaint, stream);
1613: SerialUtilities.writePaint(this.baseSeriesPaint, stream);
1614: SerialUtilities.writePaint(this.seriesOutlinePaint, stream);
1615: SerialUtilities.writePaint(this.baseSeriesOutlinePaint, stream);
1616: SerialUtilities.writeStroke(this.seriesOutlineStroke, stream);
1617: SerialUtilities.writeStroke(this.baseSeriesOutlineStroke, stream);
1618: SerialUtilities.writePaint(this.labelPaint, stream);
1619: SerialUtilities.writePaint(this.axisLinePaint, stream);
1620: SerialUtilities.writeStroke(this.axisLineStroke, stream);
1621: }
1622:
1623:
1631: private void readObject(ObjectInputStream stream) throws IOException,
1632: ClassNotFoundException {
1633: stream.defaultReadObject();
1634:
1635: this.legendItemShape = SerialUtilities.readShape(stream);
1636: this.seriesPaint = SerialUtilities.readPaint(stream);
1637: this.baseSeriesPaint = SerialUtilities.readPaint(stream);
1638: this.seriesOutlinePaint = SerialUtilities.readPaint(stream);
1639: this.baseSeriesOutlinePaint = SerialUtilities.readPaint(stream);
1640: this.seriesOutlineStroke = SerialUtilities.readStroke(stream);
1641: this.baseSeriesOutlineStroke = SerialUtilities.readStroke(stream);
1642: this.labelPaint = SerialUtilities.readPaint(stream);
1643: this.axisLinePaint = SerialUtilities.readPaint(stream);
1644: this.axisLineStroke = SerialUtilities.readStroke(stream);
1645: if (this.dataset != null) {
1646: this.dataset.addChangeListener(this);
1647: }
1648: }
1649:
1650: }