1:
67:
68: package ;
69:
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: import ;
91: import ;
92: import ;
93: import ;
94:
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: import ;
113: import ;
114: import ;
115: import ;
116:
117:
122: public class SpiderWebPlot extends Plot implements Cloneable, Serializable {
123:
124:
125: private static final long serialVersionUID = -5376340422031599463L;
126:
127:
128: public static final double DEFAULT_HEAD = 0.01;
129:
130:
131: public static final double DEFAULT_AXIS_LABEL_GAP = 0.10;
132:
133:
134: public static final double DEFAULT_INTERIOR_GAP = 0.25;
135:
136:
137: public static final double MAX_INTERIOR_GAP = 0.40;
138:
139:
140: public static final double DEFAULT_START_ANGLE = 90.0;
141:
142:
143: public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
144: Font.PLAIN, 10);
145:
146:
147: public static final Paint DEFAULT_LABEL_PAINT = Color.black;
148:
149:
150: public static final Paint DEFAULT_LABEL_BACKGROUND_PAINT
151: = new Color(255, 255, 192);
152:
153:
154: public static final Paint DEFAULT_LABEL_OUTLINE_PAINT = Color.black;
155:
156:
157: public static final Stroke DEFAULT_LABEL_OUTLINE_STROKE
158: = new BasicStroke(0.5f);
159:
160:
161: public static final Paint DEFAULT_LABEL_SHADOW_PAINT = Color.lightGray;
162:
163:
167: public static final double DEFAULT_MAX_VALUE = -1.0;
168:
169:
170: protected double headPercent;
171:
172:
173: private double interiorGap;
174:
175:
176: private double axisLabelGap;
177:
178:
183: private transient Paint axisLinePaint;
184:
185:
190: private transient Stroke axisLineStroke;
191:
192:
193: private CategoryDataset dataset;
194:
195:
196: private double maxValue;
197:
198:
204: private TableOrder dataExtractOrder;
205:
206:
207: private double startAngle;
208:
209:
210: private Rotation direction;
211:
212:
213: private transient Shape legendItemShape;
214:
215:
216: private transient Paint seriesPaint;
217:
218:
219: private PaintList seriesPaintList;
220:
221:
222: private transient Paint baseSeriesPaint;
223:
224:
225: private transient Paint seriesOutlinePaint;
226:
227:
228: private PaintList seriesOutlinePaintList;
229:
230:
231: private transient Paint baseSeriesOutlinePaint;
232:
233:
234: private transient Stroke seriesOutlineStroke;
235:
236:
237: private StrokeList seriesOutlineStrokeList;
238:
239:
240: private transient Stroke baseSeriesOutlineStroke;
241:
242:
243: private Font labelFont;
244:
245:
246: private transient Paint labelPaint;
247:
248:
249: private CategoryItemLabelGenerator labelGenerator;
250:
251:
252: private boolean webFilled = true;
253:
254:
255: private CategoryToolTipGenerator toolTipGenerator;
256:
257:
258: private CategoryURLGenerator urlGenerator;
259:
260:
263: public SpiderWebPlot() {
264: this(null);
265: }
266:
267:
273: public SpiderWebPlot(CategoryDataset dataset) {
274: this(dataset, TableOrder.BY_ROW);
275: }
276:
277:
284: public SpiderWebPlot(CategoryDataset dataset, TableOrder extract) {
285: super();
286: if (extract == null) {
287: throw new IllegalArgumentException("Null 'extract' argument.");
288: }
289: this.dataset = dataset;
290: if (dataset != null) {
291: dataset.addChangeListener(this);
292: }
293:
294: this.dataExtractOrder = extract;
295: this.headPercent = DEFAULT_HEAD;
296: this.axisLabelGap = DEFAULT_AXIS_LABEL_GAP;
297: this.axisLinePaint = Color.black;
298: this.axisLineStroke = new BasicStroke(1.0f);
299:
300: this.interiorGap = DEFAULT_INTERIOR_GAP;
301: this.startAngle = DEFAULT_START_ANGLE;
302: this.direction = Rotation.CLOCKWISE;
303: this.maxValue = DEFAULT_MAX_VALUE;
304:
305: this.seriesPaint = null;
306: this.seriesPaintList = new PaintList();
307: this.baseSeriesPaint = null;
308:
309: this.seriesOutlinePaint = null;
310: this.seriesOutlinePaintList = new PaintList();
311: this.baseSeriesOutlinePaint = DEFAULT_OUTLINE_PAINT;
312:
313: this.seriesOutlineStroke = null;
314: this.seriesOutlineStrokeList = new StrokeList();
315: this.baseSeriesOutlineStroke = DEFAULT_OUTLINE_STROKE;
316:
317: this.labelFont = DEFAULT_LABEL_FONT;
318: this.labelPaint = DEFAULT_LABEL_PAINT;
319: this.labelGenerator = new StandardCategoryItemLabelGenerator();
320:
321: this.legendItemShape = DEFAULT_LEGEND_ITEM_CIRCLE;
322: }
323:
324:
329: public String getPlotType() {
330:
331: return ("Spider Web Plot");
332: }
333:
334:
341: public CategoryDataset getDataset() {
342: return this.dataset;
343: }
344:
345:
353: public void setDataset(CategoryDataset dataset) {
354:
355:
356: if (this.dataset != null) {
357: this.dataset.removeChangeListener(this);
358: }
359:
360:
361: this.dataset = dataset;
362: if (dataset != null) {
363: setDatasetGroup(dataset.getGroup());
364: dataset.addChangeListener(this);
365: }
366:
367:
368: datasetChanged(new DatasetChangeEvent(this, dataset));
369: }
370:
371:
378: public boolean isWebFilled() {
379: return this.webFilled;
380: }
381:
382:
390: public void setWebFilled(boolean flag) {
391: this.webFilled = flag;
392: notifyListeners(new PlotChangeEvent(this));
393: }
394:
395:
402: public TableOrder getDataExtractOrder() {
403: return this.dataExtractOrder;
404: }
405:
406:
417: public void setDataExtractOrder(TableOrder order) {
418: if (order == null) {
419: throw new IllegalArgumentException("Null 'order' argument");
420: }
421: this.dataExtractOrder = order;
422: notifyListeners(new PlotChangeEvent(this));
423: }
424:
425:
432: public double getHeadPercent() {
433: return this.headPercent;
434: }
435:
436:
444: public void setHeadPercent(double percent) {
445: this.headPercent = percent;
446: notifyListeners(new PlotChangeEvent(this));
447: }
448:
449:
459: public double getStartAngle() {
460: return this.startAngle;
461: }
462:
463:
475: public void setStartAngle(double angle) {
476: this.startAngle = angle;
477: notifyListeners(new PlotChangeEvent(this));
478: }
479:
480:
487: public double getMaxValue() {
488: return this.maxValue;
489: }
490:
491:
499: public void setMaxValue(double value) {
500: this.maxValue = value;
501: notifyListeners(new PlotChangeEvent(this));
502: }
503:
504:
512: public Rotation getDirection() {
513: return this.direction;
514: }
515:
516:
524: public void setDirection(Rotation direction) {
525: if (direction == null) {
526: throw new IllegalArgumentException("Null 'direction' argument.");
527: }
528: this.direction = direction;
529: notifyListeners(new PlotChangeEvent(this));
530: }
531:
532:
540: public double getInteriorGap() {
541: return this.interiorGap;
542: }
543:
544:
553: public void setInteriorGap(double percent) {
554: if ((percent < 0.0) || (percent > MAX_INTERIOR_GAP)) {
555: throw new IllegalArgumentException(
556: "Percentage outside valid range.");
557: }
558: if (this.interiorGap != percent) {
559: this.interiorGap = percent;
560: notifyListeners(new PlotChangeEvent(this));
561: }
562: }
563:
564:
571: public double getAxisLabelGap() {
572: return this.axisLabelGap;
573: }
574:
575:
583: public void setAxisLabelGap(double gap) {
584: this.axisLabelGap = gap;
585: notifyListeners(new PlotChangeEvent(this));
586: }
587:
588:
597: public Paint getAxisLinePaint() {
598: return this.axisLinePaint;
599: }
600:
601:
610: public void setAxisLinePaint(Paint paint) {
611: if (paint == null) {
612: throw new IllegalArgumentException("Null 'paint' argument.");
613: }
614: this.axisLinePaint = paint;
615: notifyListeners(new PlotChangeEvent(this));
616: }
617:
618:
627: public Stroke getAxisLineStroke() {
628: return this.axisLineStroke;
629: }
630:
631:
640: public void setAxisLineStroke(Stroke stroke) {
641: if (stroke == null) {
642: throw new IllegalArgumentException("Null 'stroke' argument.");
643: }
644: this.axisLineStroke = stroke;
645: notifyListeners(new PlotChangeEvent(this));
646: }
647:
648:
649:
650:
657: public Paint getSeriesPaint() {
658: return this.seriesPaint;
659: }
660:
661:
670: public void setSeriesPaint(Paint paint) {
671: this.seriesPaint = paint;
672: notifyListeners(new PlotChangeEvent(this));
673: }
674:
675:
684: public Paint getSeriesPaint(int series) {
685:
686:
687: if (this.seriesPaint != null) {
688: return this.seriesPaint;
689: }
690:
691:
692: Paint result = this.seriesPaintList.getPaint(series);
693: if (result == null) {
694: DrawingSupplier supplier = getDrawingSupplier();
695: if (supplier != null) {
696: Paint p = supplier.getNextPaint();
697: this.seriesPaintList.setPaint(series, p);
698: result = p;
699: }
700: else {
701: result = this.baseSeriesPaint;
702: }
703: }
704: return result;
705:
706: }
707:
708:
717: public void setSeriesPaint(int series, Paint paint) {
718: this.seriesPaintList.setPaint(series, paint);
719: notifyListeners(new PlotChangeEvent(this));
720: }
721:
722:
730: public Paint getBaseSeriesPaint() {
731: return this.baseSeriesPaint;
732: }
733:
734:
741: public void setBaseSeriesPaint(Paint paint) {
742: if (paint == null) {
743: throw new IllegalArgumentException("Null 'paint' argument.");
744: }
745: this.baseSeriesPaint = paint;
746: notifyListeners(new PlotChangeEvent(this));
747: }
748:
749:
750:
751:
756: public Paint getSeriesOutlinePaint() {
757: return this.seriesOutlinePaint;
758: }
759:
760:
767: public void setSeriesOutlinePaint(Paint paint) {
768: this.seriesOutlinePaint = paint;
769: notifyListeners(new PlotChangeEvent(this));
770: }
771:
772:
779: public Paint getSeriesOutlinePaint(int series) {
780:
781: if (this.seriesOutlinePaint != null) {
782: return this.seriesOutlinePaint;
783: }
784:
785: Paint result = this.seriesOutlinePaintList.getPaint(series);
786: if (result == null) {
787: result = this.baseSeriesOutlinePaint;
788: }
789: return result;
790: }
791:
792:
799: public void setSeriesOutlinePaint(int series, Paint paint) {
800: this.seriesOutlinePaintList.setPaint(series, paint);
801: notifyListeners(new PlotChangeEvent(this));
802: }
803:
804:
810: public Paint getBaseSeriesOutlinePaint() {
811: return this.baseSeriesOutlinePaint;
812: }
813:
814:
819: public void setBaseSeriesOutlinePaint(Paint paint) {
820: if (paint == null) {
821: throw new IllegalArgumentException("Null 'paint' argument.");
822: }
823: this.baseSeriesOutlinePaint = paint;
824: notifyListeners(new PlotChangeEvent(this));
825: }
826:
827:
828:
829:
834: public Stroke getSeriesOutlineStroke() {
835: return this.seriesOutlineStroke;
836: }
837:
838:
845: public void setSeriesOutlineStroke(Stroke stroke) {
846: this.seriesOutlineStroke = stroke;
847: notifyListeners(new PlotChangeEvent(this));
848: }
849:
850:
857: public Stroke getSeriesOutlineStroke(int series) {
858:
859:
860: if (this.seriesOutlineStroke != null) {
861: return this.seriesOutlineStroke;
862: }
863:
864:
865: Stroke result = this.seriesOutlineStrokeList.getStroke(series);
866: if (result == null) {
867: result = this.baseSeriesOutlineStroke;
868: }
869: return result;
870:
871: }
872:
873:
880: public void setSeriesOutlineStroke(int series, Stroke stroke) {
881: this.seriesOutlineStrokeList.setStroke(series, stroke);
882: notifyListeners(new PlotChangeEvent(this));
883: }
884:
885:
891: public Stroke getBaseSeriesOutlineStroke() {
892: return this.baseSeriesOutlineStroke;
893: }
894:
895:
900: public void setBaseSeriesOutlineStroke(Stroke stroke) {
901: if (stroke == null) {
902: throw new IllegalArgumentException("Null 'stroke' argument.");
903: }
904: this.baseSeriesOutlineStroke = stroke;
905: notifyListeners(new PlotChangeEvent(this));
906: }
907:
908:
915: public Shape getLegendItemShape() {
916: return this.legendItemShape;
917: }
918:
919:
927: public void setLegendItemShape(Shape shape) {
928: if (shape == null) {
929: throw new IllegalArgumentException("Null 'shape' argument.");
930: }
931: this.legendItemShape = shape;
932: notifyListeners(new PlotChangeEvent(this));
933: }
934:
935:
942: public Font getLabelFont() {
943: return this.labelFont;
944: }
945:
946:
954: public void setLabelFont(Font font) {
955: if (font == null) {
956: throw new IllegalArgumentException("Null 'font' argument.");
957: }
958: this.labelFont = font;
959: notifyListeners(new PlotChangeEvent(this));
960: }
961:
962:
969: public Paint getLabelPaint() {
970: return this.labelPaint;
971: }
972:
973:
981: public void setLabelPaint(Paint paint) {
982: if (paint == null) {
983: throw new IllegalArgumentException("Null 'paint' argument.");
984: }
985: this.labelPaint = paint;
986: notifyListeners(new PlotChangeEvent(this));
987: }
988:
989:
996: public CategoryItemLabelGenerator getLabelGenerator() {
997: return this.labelGenerator;
998: }
999:
1000:
1008: public void setLabelGenerator(CategoryItemLabelGenerator generator) {
1009: if (generator == null) {
1010: throw new IllegalArgumentException("Null 'generator' argument.");
1011: }
1012: this.labelGenerator = generator;
1013: }
1014:
1015:
1024: public CategoryToolTipGenerator getToolTipGenerator() {
1025: return this.toolTipGenerator;
1026: }
1027:
1028:
1038: public void setToolTipGenerator(CategoryToolTipGenerator generator) {
1039: this.toolTipGenerator = generator;
1040: this.notifyListeners(new PlotChangeEvent(this));
1041: }
1042:
1043:
1052: public CategoryURLGenerator getURLGenerator() {
1053: return this.urlGenerator;
1054: }
1055:
1056:
1066: public void setURLGenerator(CategoryURLGenerator generator) {
1067: this.urlGenerator = generator;
1068: this.notifyListeners(new PlotChangeEvent(this));
1069: }
1070:
1071:
1076: public LegendItemCollection getLegendItems() {
1077: LegendItemCollection result = new LegendItemCollection();
1078:
1079: List keys = null;
1080:
1081: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1082: keys = this.dataset.getRowKeys();
1083: }
1084: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
1085: keys = this.dataset.getColumnKeys();
1086: }
1087:
1088: if (keys != null) {
1089: int series = 0;
1090: Iterator iterator = keys.iterator();
1091: Shape shape = getLegendItemShape();
1092:
1093: while (iterator.hasNext()) {
1094: String label = iterator.next().toString();
1095: String description = label;
1096:
1097: Paint paint = getSeriesPaint(series);
1098: Paint outlinePaint = getSeriesOutlinePaint(series);
1099: Stroke stroke = getSeriesOutlineStroke(series);
1100: LegendItem item = new LegendItem(label, description,
1101: null, null, shape, paint, stroke, outlinePaint);
1102: item.setDataset(getDataset());
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(
1342: (int) (point.getX() - headW),
1343: (int) (point.getY() - headH),
1344: (int) (headW * 2), (int) (headH * 2));
1345: CategoryItemEntity entity = new CategoryItemEntity(
1346: area, tip, url, this.dataset,
1347: this.dataset.getRowKey(series),
1348: this.dataset.getColumnKey(cat));
1349: entities.add(entity);
1350: }
1351:
1352: }
1353: }
1354: }
1355:
1356:
1357: Paint paint = getSeriesPaint(series);
1358: g2.setPaint(paint);
1359: g2.setStroke(getSeriesOutlineStroke(series));
1360: g2.draw(polygon);
1361:
1362:
1363:
1364: if (this.webFilled) {
1365: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1366: 0.1f));
1367: g2.fill(polygon);
1368: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1369: getForegroundAlpha()));
1370: }
1371: }
1372:
1373:
1387: protected Number getPlotValue(int series, int cat) {
1388: Number value = null;
1389: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1390: value = this.dataset.getValue(series, cat);
1391: }
1392: else if (this.dataExtractOrder == TableOrder.BY_COLUMN) {
1393: value = this.dataset.getValue(cat, series);
1394: }
1395: return value;
1396: }
1397:
1398:
1408: protected void drawLabel(Graphics2D g2, Rectangle2D plotArea, double value,
1409: int cat, double startAngle, double extent) {
1410: FontRenderContext frc = g2.getFontRenderContext();
1411:
1412: String label = null;
1413: if (this.dataExtractOrder == TableOrder.BY_ROW) {
1414:
1415: label = this.labelGenerator.generateColumnLabel(this.dataset, cat);
1416: }
1417: else {
1418:
1419: label = this.labelGenerator.generateRowLabel(this.dataset, cat);
1420: }
1421:
1422: Rectangle2D labelBounds = getLabelFont().getStringBounds(label, frc);
1423: LineMetrics lm = getLabelFont().getLineMetrics(label, frc);
1424: double ascent = lm.getAscent();
1425:
1426: Point2D labelLocation = calculateLabelLocation(labelBounds, ascent,
1427: plotArea, startAngle);
1428:
1429: Composite saveComposite = g2.getComposite();
1430:
1431: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1432: 1.0f));
1433: g2.setPaint(getLabelPaint());
1434: g2.setFont(getLabelFont());
1435: g2.drawString(label, (float) labelLocation.getX(),
1436: (float) labelLocation.getY());
1437: g2.setComposite(saveComposite);
1438: }
1439:
1440:
1450: protected Point2D calculateLabelLocation(Rectangle2D labelBounds,
1451: double ascent,
1452: Rectangle2D plotArea,
1453: double startAngle)
1454: {
1455: Arc2D arc1 = new Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN);
1456: Point2D point1 = arc1.getEndPoint();
1457:
1458: double deltaX = -(point1.getX() - plotArea.getCenterX())
1459: * this.axisLabelGap;
1460: double deltaY = -(point1.getY() - plotArea.getCenterY())
1461: * this.axisLabelGap;
1462:
1463: double labelX = point1.getX() - deltaX;
1464: double labelY = point1.getY() - deltaY;
1465:
1466: if (labelX < plotArea.getCenterX()) {
1467: labelX -= labelBounds.getWidth();
1468: }
1469:
1470: if (labelX == plotArea.getCenterX()) {
1471: labelX -= labelBounds.getWidth() / 2;
1472: }
1473:
1474: if (labelY > plotArea.getCenterY()) {
1475: labelY += ascent;
1476: }
1477:
1478: return new Point2D.Double(labelX, labelY);
1479: }
1480:
1481:
1488: public boolean equals(Object obj) {
1489: if (obj == this) {
1490: return true;
1491: }
1492: if (!(obj instanceof SpiderWebPlot)) {
1493: return false;
1494: }
1495: if (!super.equals(obj)) {
1496: return false;
1497: }
1498: SpiderWebPlot that = (SpiderWebPlot) obj;
1499: if (!this.dataExtractOrder.equals(that.dataExtractOrder)) {
1500: return false;
1501: }
1502: if (this.headPercent != that.headPercent) {
1503: return false;
1504: }
1505: if (this.interiorGap != that.interiorGap) {
1506: return false;
1507: }
1508: if (this.startAngle != that.startAngle) {
1509: return false;
1510: }
1511: if (!this.direction.equals(that.direction)) {
1512: return false;
1513: }
1514: if (this.maxValue != that.maxValue) {
1515: return false;
1516: }
1517: if (this.webFilled != that.webFilled) {
1518: return false;
1519: }
1520: if (this.axisLabelGap != that.axisLabelGap) {
1521: return false;
1522: }
1523: if (!PaintUtilities.equal(this.axisLinePaint, that.axisLinePaint)) {
1524: return false;
1525: }
1526: if (!this.axisLineStroke.equals(that.axisLineStroke)) {
1527: return false;
1528: }
1529: if (!ShapeUtilities.equal(this.legendItemShape, that.legendItemShape)) {
1530: return false;
1531: }
1532: if (!PaintUtilities.equal(this.seriesPaint, that.seriesPaint)) {
1533: return false;
1534: }
1535: if (!this.seriesPaintList.equals(that.seriesPaintList)) {
1536: return false;
1537: }
1538: if (!PaintUtilities.equal(this.baseSeriesPaint, that.baseSeriesPaint)) {
1539: return false;
1540: }
1541: if (!PaintUtilities.equal(this.seriesOutlinePaint,
1542: that.seriesOutlinePaint)) {
1543: return false;
1544: }
1545: if (!this.seriesOutlinePaintList.equals(that.seriesOutlinePaintList)) {
1546: return false;
1547: }
1548: if (!PaintUtilities.equal(this.baseSeriesOutlinePaint,
1549: that.baseSeriesOutlinePaint)) {
1550: return false;
1551: }
1552: if (!ObjectUtilities.equal(this.seriesOutlineStroke,
1553: that.seriesOutlineStroke)) {
1554: return false;
1555: }
1556: if (!this.seriesOutlineStrokeList.equals(
1557: that.seriesOutlineStrokeList)) {
1558: return false;
1559: }
1560: if (!this.baseSeriesOutlineStroke.equals(
1561: that.baseSeriesOutlineStroke)) {
1562: return false;
1563: }
1564: if (!this.labelFont.equals(that.labelFont)) {
1565: return false;
1566: }
1567: if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
1568: return false;
1569: }
1570: if (!this.labelGenerator.equals(that.labelGenerator)) {
1571: return false;
1572: }
1573: if (!ObjectUtilities.equal(this.toolTipGenerator,
1574: that.toolTipGenerator)) {
1575: return false;
1576: }
1577: if (!ObjectUtilities.equal(this.urlGenerator,
1578: that.urlGenerator)) {
1579: return false;
1580: }
1581: return true;
1582: }
1583:
1584:
1592: public Object clone() throws CloneNotSupportedException {
1593: SpiderWebPlot clone = (SpiderWebPlot) super.clone();
1594: clone.legendItemShape = ShapeUtilities.clone(this.legendItemShape);
1595: clone.seriesPaintList = (PaintList) this.seriesPaintList.clone();
1596: clone.seriesOutlinePaintList
1597: = (PaintList) this.seriesOutlinePaintList.clone();
1598: clone.seriesOutlineStrokeList
1599: = (StrokeList) this.seriesOutlineStrokeList.clone();
1600: return clone;
1601: }
1602:
1603:
1610: private void writeObject(ObjectOutputStream stream) throws IOException {
1611: stream.defaultWriteObject();
1612:
1613: SerialUtilities.writeShape(this.legendItemShape, stream);
1614: SerialUtilities.writePaint(this.seriesPaint, stream);
1615: SerialUtilities.writePaint(this.baseSeriesPaint, stream);
1616: SerialUtilities.writePaint(this.seriesOutlinePaint, stream);
1617: SerialUtilities.writePaint(this.baseSeriesOutlinePaint, stream);
1618: SerialUtilities.writeStroke(this.seriesOutlineStroke, stream);
1619: SerialUtilities.writeStroke(this.baseSeriesOutlineStroke, stream);
1620: SerialUtilities.writePaint(this.labelPaint, stream);
1621: SerialUtilities.writePaint(this.axisLinePaint, stream);
1622: SerialUtilities.writeStroke(this.axisLineStroke, stream);
1623: }
1624:
1625:
1633: private void readObject(ObjectInputStream stream) throws IOException,
1634: ClassNotFoundException {
1635: stream.defaultReadObject();
1636:
1637: this.legendItemShape = SerialUtilities.readShape(stream);
1638: this.seriesPaint = SerialUtilities.readPaint(stream);
1639: this.baseSeriesPaint = SerialUtilities.readPaint(stream);
1640: this.seriesOutlinePaint = SerialUtilities.readPaint(stream);
1641: this.baseSeriesOutlinePaint = SerialUtilities.readPaint(stream);
1642: this.seriesOutlineStroke = SerialUtilities.readStroke(stream);
1643: this.baseSeriesOutlineStroke = SerialUtilities.readStroke(stream);
1644: this.labelPaint = SerialUtilities.readPaint(stream);
1645: this.axisLinePaint = SerialUtilities.readPaint(stream);
1646: this.axisLineStroke = SerialUtilities.readStroke(stream);
1647: if (this.dataset != null) {
1648: this.dataset.addChangeListener(this);
1649: }
1650: }
1651:
1652: }