1:
150:
151: package ;
152:
153: import ;
154: import ;
155: import ;
156: import ;
157: import ;
158: import ;
159: import ;
160: import ;
161: import ;
162: import ;
163: import ;
164: import ;
165: import ;
166: import ;
167: import ;
168: import ;
169: import ;
170: import ;
171: import ;
172: import ;
173: import ;
174: import ;
175: import ;
176:
177: import ;
178: import ;
179: import ;
180: import ;
181: import ;
182: import ;
183: import ;
184: import ;
185: import ;
186: import ;
187: import ;
188: import ;
189: import ;
190: import ;
191: import ;
192: import ;
193: import ;
194: import ;
195: import ;
196: import ;
197: import ;
198: import ;
199: import ;
200: import ;
201: import ;
202: import ;
203: import ;
204: import ;
205: import ;
206: import ;
207:
208:
224: public class PiePlot extends Plot implements Cloneable, Serializable {
225:
226:
227: private static final long serialVersionUID = -795612466005590431L;
228:
229:
230: public static final double DEFAULT_INTERIOR_GAP = 0.1;
231:
232:
233: public static final double MAX_INTERIOR_GAP = 0.40;
234:
235:
236: public static final double DEFAULT_START_ANGLE = 90.0;
237:
238:
239: public static final Font DEFAULT_LABEL_FONT = new Font("SansSerif",
240: Font.PLAIN, 10);
241:
242:
243: public static final Paint DEFAULT_LABEL_PAINT = Color.black;
244:
245:
246: public static final Paint DEFAULT_LABEL_BACKGROUND_PAINT = new Color(255,
247: 255, 192);
248:
249:
250: public static final Paint DEFAULT_LABEL_OUTLINE_PAINT = Color.black;
251:
252:
253: public static final Stroke DEFAULT_LABEL_OUTLINE_STROKE = new BasicStroke(
254: 0.5f);
255:
256:
257: public static final Paint DEFAULT_LABEL_SHADOW_PAINT = new Color(151, 151,
258: 151, 128);
259:
260:
261: public static final double DEFAULT_MINIMUM_ARC_ANGLE_TO_DRAW = 0.00001;
262:
263:
264: private PieDataset dataset;
265:
266:
267: private int pieIndex;
268:
269:
273: private double interiorGap;
274:
275:
276: private boolean circular;
277:
278:
279: private double startAngle;
280:
281:
282: private Rotation direction;
283:
284:
291: private transient Paint sectionPaint;
292:
293:
294: private PaintMap sectionPaintMap;
295:
296:
297: private transient Paint baseSectionPaint;
298:
299:
303: private boolean sectionOutlinesVisible;
304:
305:
312: private transient Paint sectionOutlinePaint;
313:
314:
315: private PaintMap sectionOutlinePaintMap;
316:
317:
318: private transient Paint baseSectionOutlinePaint;
319:
320:
327: private transient Stroke sectionOutlineStroke;
328:
329:
330: private StrokeMap sectionOutlineStrokeMap;
331:
332:
333: private transient Stroke baseSectionOutlineStroke;
334:
335:
336: private transient Paint shadowPaint = Color.gray;
337:
338:
339: private double shadowXOffset = 4.0f;
340:
341:
342: private double shadowYOffset = 4.0f;
343:
344:
345: private Map explodePercentages;
346:
347:
348: private PieSectionLabelGenerator labelGenerator;
349:
350:
351: private Font labelFont;
352:
353:
354: private transient Paint labelPaint;
355:
356:
360: private transient Paint labelBackgroundPaint;
361:
362:
366: private transient Paint labelOutlinePaint;
367:
368:
372: private transient Stroke labelOutlineStroke;
373:
374:
378: private transient Paint labelShadowPaint;
379:
380:
385: private boolean simpleLabels = true;
386:
387:
393: private RectangleInsets labelPadding;
394:
395:
400: private RectangleInsets simpleLabelOffset;
401:
402:
403: private double maximumLabelWidth = 0.20;
404:
405:
409: private double labelGap = 0.05;
410:
411:
412: private boolean labelLinksVisible;
413:
414:
415: private double labelLinkMargin = 0.05;
416:
417:
418: private transient Paint labelLinkPaint = Color.black;
419:
420:
421: private transient Stroke labelLinkStroke = new BasicStroke(0.5f);
422:
423:
428: private AbstractPieLabelDistributor labelDistributor;
429:
430:
431: private PieToolTipGenerator toolTipGenerator;
432:
433:
434: private PieURLGenerator urlGenerator;
435:
436:
437: private PieSectionLabelGenerator legendLabelGenerator;
438:
439:
440: private PieSectionLabelGenerator legendLabelToolTipGenerator;
441:
442:
447: private PieURLGenerator legendLabelURLGenerator;
448:
449:
452: private boolean ignoreNullValues;
453:
454:
457: private boolean ignoreZeroValues;
458:
459:
460: private transient Shape legendItemShape;
461:
462:
473: private double minimumArcAngleToDraw;
474:
475:
476: protected static ResourceBundle localizationResources =
477: ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
478:
479:
482: public PiePlot() {
483: this(null);
484: }
485:
486:
491: public PiePlot(PieDataset dataset) {
492: super();
493: setBackgroundPaint(new Color(230, 230, 230));
494: this.dataset = dataset;
495: if (dataset != null) {
496: dataset.addChangeListener(this);
497: }
498: this.pieIndex = 0;
499:
500: this.interiorGap = DEFAULT_INTERIOR_GAP;
501: this.circular = true;
502: this.startAngle = DEFAULT_START_ANGLE;
503: this.direction = Rotation.CLOCKWISE;
504: this.minimumArcAngleToDraw = DEFAULT_MINIMUM_ARC_ANGLE_TO_DRAW;
505:
506: this.sectionPaint = null;
507: this.sectionPaintMap = new PaintMap();
508: this.baseSectionPaint = Color.gray;
509:
510: this.sectionOutlinesVisible = true;
511: this.sectionOutlinePaint = null;
512: this.sectionOutlinePaintMap = new PaintMap();
513: this.baseSectionOutlinePaint = DEFAULT_OUTLINE_PAINT;
514:
515: this.sectionOutlineStroke = null;
516: this.sectionOutlineStrokeMap = new StrokeMap();
517: this.baseSectionOutlineStroke = DEFAULT_OUTLINE_STROKE;
518:
519: this.explodePercentages = new TreeMap();
520:
521: this.labelGenerator = new StandardPieSectionLabelGenerator();
522: this.labelFont = DEFAULT_LABEL_FONT;
523: this.labelPaint = DEFAULT_LABEL_PAINT;
524: this.labelBackgroundPaint = DEFAULT_LABEL_BACKGROUND_PAINT;
525: this.labelOutlinePaint = DEFAULT_LABEL_OUTLINE_PAINT;
526: this.labelOutlineStroke = DEFAULT_LABEL_OUTLINE_STROKE;
527: this.labelShadowPaint = DEFAULT_LABEL_SHADOW_PAINT;
528: this.labelLinksVisible = true;
529: this.labelDistributor = new PieLabelDistributor(0);
530:
531: this.simpleLabels = false;
532: this.simpleLabelOffset = new RectangleInsets(UnitType.RELATIVE, 0.18,
533: 0.18, 0.18, 0.18);
534: this.labelPadding = new RectangleInsets(2, 2, 2, 2);
535:
536: this.toolTipGenerator = null;
537: this.urlGenerator = null;
538: this.legendLabelGenerator = new StandardPieSectionLabelGenerator();
539: this.legendLabelToolTipGenerator = null;
540: this.legendLabelURLGenerator = null;
541: this.legendItemShape = Plot.DEFAULT_LEGEND_ITEM_CIRCLE;
542:
543: this.ignoreNullValues = false;
544: this.ignoreZeroValues = false;
545: }
546:
547:
554: public PieDataset getDataset() {
555: return this.dataset;
556: }
557:
558:
565: public void setDataset(PieDataset dataset) {
566:
567:
568: PieDataset existing = this.dataset;
569: if (existing != null) {
570: existing.removeChangeListener(this);
571: }
572:
573:
574: this.dataset = dataset;
575: if (dataset != null) {
576: setDatasetGroup(dataset.getGroup());
577: dataset.addChangeListener(this);
578: }
579:
580:
581: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
582: datasetChanged(event);
583: }
584:
585:
593: public int getPieIndex() {
594: return this.pieIndex;
595: }
596:
597:
605: public void setPieIndex(int index) {
606: this.pieIndex = index;
607: }
608:
609:
617: public double getStartAngle() {
618: return this.startAngle;
619: }
620:
621:
631: public void setStartAngle(double angle) {
632: this.startAngle = angle;
633: notifyListeners(new PlotChangeEvent(this));
634: }
635:
636:
644: public Rotation getDirection() {
645: return this.direction;
646: }
647:
648:
656: public void setDirection(Rotation direction) {
657: if (direction == null) {
658: throw new IllegalArgumentException("Null 'direction' argument.");
659: }
660: this.direction = direction;
661: notifyListeners(new PlotChangeEvent(this));
662:
663: }
664:
665:
673: public double getInteriorGap() {
674: return this.interiorGap;
675: }
676:
677:
687: public void setInteriorGap(double percent) {
688:
689: if ((percent < 0.0) || (percent > MAX_INTERIOR_GAP)) {
690: throw new IllegalArgumentException(
691: "Invalid 'percent' (" + percent + ") argument.");
692: }
693:
694: if (this.interiorGap != percent) {
695: this.interiorGap = percent;
696: notifyListeners(new PlotChangeEvent(this));
697: }
698:
699: }
700:
701:
709: public boolean isCircular() {
710: return this.circular;
711: }
712:
713:
721: public void setCircular(boolean flag) {
722: setCircular(flag, true);
723: }
724:
725:
734: public void setCircular(boolean circular, boolean notify) {
735: this.circular = circular;
736: if (notify) {
737: notifyListeners(new PlotChangeEvent(this));
738: }
739: }
740:
741:
749: public boolean getIgnoreNullValues() {
750: return this.ignoreNullValues;
751: }
752:
753:
764: public void setIgnoreNullValues(boolean flag) {
765: this.ignoreNullValues = flag;
766: notifyListeners(new PlotChangeEvent(this));
767: }
768:
769:
777: public boolean getIgnoreZeroValues() {
778: return this.ignoreZeroValues;
779: }
780:
781:
792: public void setIgnoreZeroValues(boolean flag) {
793: this.ignoreZeroValues = flag;
794: notifyListeners(new PlotChangeEvent(this));
795: }
796:
797:
798:
799:
811: protected Paint lookupSectionPaint(Comparable key) {
812: return lookupSectionPaint(key, false);
813: }
814:
815:
838: protected Paint lookupSectionPaint(Comparable key, boolean autoPopulate) {
839:
840:
841: Paint result = getSectionPaint();
842: if (result != null) {
843: return result;
844: }
845:
846:
847: result = this.sectionPaintMap.getPaint(key);
848: if (result != null) {
849: return result;
850: }
851:
852:
853: if (autoPopulate) {
854: DrawingSupplier ds = getDrawingSupplier();
855: if (ds != null) {
856: result = ds.getNextPaint();
857: this.sectionPaintMap.put(key, result);
858: }
859: else {
860: result = this.baseSectionPaint;
861: }
862: }
863: else {
864: result = this.baseSectionPaint;
865: }
866: return result;
867: }
868:
869:
879: public Paint getSectionPaint() {
880: return this.sectionPaint;
881: }
882:
883:
895: public void setSectionPaint(Paint paint) {
896: this.sectionPaint = paint;
897: notifyListeners(new PlotChangeEvent(this));
898: }
899:
900:
914: protected Comparable getSectionKey(int section) {
915: Comparable key = null;
916: if (this.dataset != null) {
917: if (section >= 0 && section < this.dataset.getItemCount()) {
918: key = this.dataset.getKey(section);
919: }
920: }
921: if (key == null) {
922: key = new Integer(section);
923: }
924: return key;
925: }
926:
927:
943: public Paint getSectionPaint(Comparable key) {
944:
945: return this.sectionPaintMap.getPaint(key);
946: }
947:
948:
962: public void setSectionPaint(Comparable key, Paint paint) {
963:
964: this.sectionPaintMap.put(key, paint);
965: notifyListeners(new PlotChangeEvent(this));
966: }
967:
968:
976: public Paint getBaseSectionPaint() {
977: return this.baseSectionPaint;
978: }
979:
980:
988: public void setBaseSectionPaint(Paint paint) {
989: if (paint == null) {
990: throw new IllegalArgumentException("Null 'paint' argument.");
991: }
992: this.baseSectionPaint = paint;
993: notifyListeners(new PlotChangeEvent(this));
994: }
995:
996:
997:
998:
1007: public boolean getSectionOutlinesVisible() {
1008: return this.sectionOutlinesVisible;
1009: }
1010:
1011:
1020: public void setSectionOutlinesVisible(boolean visible) {
1021: this.sectionOutlinesVisible = visible;
1022: notifyListeners(new PlotChangeEvent(this));
1023: }
1024:
1025:
1037: protected Paint lookupSectionOutlinePaint(Comparable key) {
1038: return lookupSectionOutlinePaint(key, false);
1039: }
1040:
1041:
1064: protected Paint lookupSectionOutlinePaint(Comparable key,
1065: boolean autoPopulate) {
1066:
1067:
1068: Paint result = getSectionOutlinePaint();
1069: if (result != null) {
1070: return result;
1071: }
1072:
1073:
1074: result = this.sectionOutlinePaintMap.getPaint(key);
1075: if (result != null) {
1076: return result;
1077: }
1078:
1079:
1080: if (autoPopulate) {
1081: DrawingSupplier ds = getDrawingSupplier();
1082: if (ds != null) {
1083: result = ds.getNextOutlinePaint();
1084: this.sectionOutlinePaintMap.put(key, result);
1085: }
1086: else {
1087: result = this.baseSectionOutlinePaint;
1088: }
1089: }
1090: else {
1091: result = this.baseSectionOutlinePaint;
1092: }
1093: return result;
1094: }
1095:
1096:
1107: public Paint getSectionOutlinePaint() {
1108: return this.sectionOutlinePaint;
1109: }
1110:
1111:
1124: public void setSectionOutlinePaint(Paint paint) {
1125: this.sectionOutlinePaint = paint;
1126: notifyListeners(new PlotChangeEvent(this));
1127: }
1128:
1129:
1145: public Paint getSectionOutlinePaint(Comparable key) {
1146:
1147: return this.sectionOutlinePaintMap.getPaint(key);
1148: }
1149:
1150:
1164: public void setSectionOutlinePaint(Comparable key, Paint paint) {
1165:
1166: this.sectionOutlinePaintMap.put(key, paint);
1167: notifyListeners(new PlotChangeEvent(this));
1168: }
1169:
1170:
1178: public Paint getBaseSectionOutlinePaint() {
1179: return this.baseSectionOutlinePaint;
1180: }
1181:
1182:
1189: public void setBaseSectionOutlinePaint(Paint paint) {
1190: if (paint == null) {
1191: throw new IllegalArgumentException("Null 'paint' argument.");
1192: }
1193: this.baseSectionOutlinePaint = paint;
1194: notifyListeners(new PlotChangeEvent(this));
1195: }
1196:
1197:
1198:
1199:
1211: protected Stroke lookupSectionOutlineStroke(Comparable key) {
1212: return lookupSectionOutlineStroke(key, false);
1213: }
1214:
1215:
1238: protected Stroke lookupSectionOutlineStroke(Comparable key,
1239: boolean autoPopulate) {
1240:
1241:
1242: Stroke result = getSectionOutlineStroke();
1243: if (result != null) {
1244: return result;
1245: }
1246:
1247:
1248: result = this.sectionOutlineStrokeMap.getStroke(key);
1249: if (result != null) {
1250: return result;
1251: }
1252:
1253:
1254: if (autoPopulate) {
1255: DrawingSupplier ds = getDrawingSupplier();
1256: if (ds != null) {
1257: result = ds.getNextOutlineStroke();
1258: this.sectionOutlineStrokeMap.put(key, result);
1259: }
1260: else {
1261: result = this.baseSectionOutlineStroke;
1262: }
1263: }
1264: else {
1265: result = this.baseSectionOutlineStroke;
1266: }
1267: return result;
1268: }
1269:
1270:
1281: public Stroke getSectionOutlineStroke() {
1282: return this.sectionOutlineStroke;
1283: }
1284:
1285:
1298: public void setSectionOutlineStroke(Stroke stroke) {
1299: this.sectionOutlineStroke = stroke;
1300: notifyListeners(new PlotChangeEvent(this));
1301: }
1302:
1303:
1319: public Stroke getSectionOutlineStroke(Comparable key) {
1320:
1321: return this.sectionOutlineStrokeMap.getStroke(key);
1322: }
1323:
1324:
1338: public void setSectionOutlineStroke(Comparable key, Stroke stroke) {
1339:
1340: this.sectionOutlineStrokeMap.put(key, stroke);
1341: notifyListeners(new PlotChangeEvent(this));
1342: }
1343:
1344:
1352: public Stroke getBaseSectionOutlineStroke() {
1353: return this.baseSectionOutlineStroke;
1354: }
1355:
1356:
1363: public void setBaseSectionOutlineStroke(Stroke stroke) {
1364: if (stroke == null) {
1365: throw new IllegalArgumentException("Null 'stroke' argument.");
1366: }
1367: this.baseSectionOutlineStroke = stroke;
1368: notifyListeners(new PlotChangeEvent(this));
1369: }
1370:
1371:
1378: public Paint getShadowPaint() {
1379: return this.shadowPaint;
1380: }
1381:
1382:
1390: public void setShadowPaint(Paint paint) {
1391: this.shadowPaint = paint;
1392: notifyListeners(new PlotChangeEvent(this));
1393: }
1394:
1395:
1402: public double getShadowXOffset() {
1403: return this.shadowXOffset;
1404: }
1405:
1406:
1414: public void setShadowXOffset(double offset) {
1415: this.shadowXOffset = offset;
1416: notifyListeners(new PlotChangeEvent(this));
1417: }
1418:
1419:
1426: public double getShadowYOffset() {
1427: return this.shadowYOffset;
1428: }
1429:
1430:
1438: public void setShadowYOffset(double offset) {
1439: this.shadowYOffset = offset;
1440: notifyListeners(new PlotChangeEvent(this));
1441: }
1442:
1443:
1459: public double getExplodePercent(Comparable key) {
1460: double result = 0.0;
1461: if (this.explodePercentages != null) {
1462: Number percent = (Number) this.explodePercentages.get(key);
1463: if (percent != null) {
1464: result = percent.doubleValue();
1465: }
1466: }
1467: return result;
1468: }
1469:
1470:
1481: public void setExplodePercent(Comparable key, double percent) {
1482: if (key == null) {
1483: throw new IllegalArgumentException("Null 'key' argument.");
1484: }
1485: if (this.explodePercentages == null) {
1486: this.explodePercentages = new TreeMap();
1487: }
1488: this.explodePercentages.put(key, new Double(percent));
1489: notifyListeners(new PlotChangeEvent(this));
1490: }
1491:
1492:
1497: public double getMaximumExplodePercent() {
1498: double result = 0.0;
1499: Iterator iterator = this.dataset.getKeys().iterator();
1500: while (iterator.hasNext()) {
1501: Comparable key = (Comparable) iterator.next();
1502: Number explode = (Number) this.explodePercentages.get(key);
1503: if (explode != null) {
1504: result = Math.max(result, explode.doubleValue());
1505: }
1506: }
1507: return result;
1508: }
1509:
1510:
1517: public PieSectionLabelGenerator getLabelGenerator() {
1518: return this.labelGenerator;
1519: }
1520:
1521:
1529: public void setLabelGenerator(PieSectionLabelGenerator generator) {
1530: this.labelGenerator = generator;
1531: notifyListeners(new PlotChangeEvent(this));
1532: }
1533:
1534:
1542: public double getLabelGap() {
1543: return this.labelGap;
1544: }
1545:
1546:
1555: public void setLabelGap(double gap) {
1556: this.labelGap = gap;
1557: notifyListeners(new PlotChangeEvent(this));
1558: }
1559:
1560:
1567: public double getMaximumLabelWidth() {
1568: return this.maximumLabelWidth;
1569: }
1570:
1571:
1579: public void setMaximumLabelWidth(double width) {
1580: this.maximumLabelWidth = width;
1581: notifyListeners(new PlotChangeEvent(this));
1582: }
1583:
1584:
1592: public boolean getLabelLinksVisible() {
1593: return this.labelLinksVisible;
1594: }
1595:
1596:
1607: public void setLabelLinksVisible(boolean visible) {
1608: this.labelLinksVisible = visible;
1609: notifyListeners(new PlotChangeEvent(this));
1610: }
1611:
1612:
1620: public double getLabelLinkMargin() {
1621: return this.labelLinkMargin;
1622: }
1623:
1624:
1632: public void setLabelLinkMargin(double margin) {
1633: this.labelLinkMargin = margin;
1634: notifyListeners(new PlotChangeEvent(this));
1635: }
1636:
1637:
1645: public Paint getLabelLinkPaint() {
1646: return this.labelLinkPaint;
1647: }
1648:
1649:
1658: public void setLabelLinkPaint(Paint paint) {
1659: if (paint == null) {
1660: throw new IllegalArgumentException("Null 'paint' argument.");
1661: }
1662: this.labelLinkPaint = paint;
1663: notifyListeners(new PlotChangeEvent(this));
1664: }
1665:
1666:
1673: public Stroke getLabelLinkStroke() {
1674: return this.labelLinkStroke;
1675: }
1676:
1677:
1685: public void setLabelLinkStroke(Stroke stroke) {
1686: if (stroke == null) {
1687: throw new IllegalArgumentException("Null 'stroke' argument.");
1688: }
1689: this.labelLinkStroke = stroke;
1690: notifyListeners(new PlotChangeEvent(this));
1691: }
1692:
1693:
1700: public Font getLabelFont() {
1701: return this.labelFont;
1702: }
1703:
1704:
1712: public void setLabelFont(Font font) {
1713: if (font == null) {
1714: throw new IllegalArgumentException("Null 'font' argument.");
1715: }
1716: this.labelFont = font;
1717: notifyListeners(new PlotChangeEvent(this));
1718: }
1719:
1720:
1727: public Paint getLabelPaint() {
1728: return this.labelPaint;
1729: }
1730:
1731:
1739: public void setLabelPaint(Paint paint) {
1740: if (paint == null) {
1741: throw new IllegalArgumentException("Null 'paint' argument.");
1742: }
1743: this.labelPaint = paint;
1744: notifyListeners(new PlotChangeEvent(this));
1745: }
1746:
1747:
1754: public Paint getLabelBackgroundPaint() {
1755: return this.labelBackgroundPaint;
1756: }
1757:
1758:
1766: public void setLabelBackgroundPaint(Paint paint) {
1767: this.labelBackgroundPaint = paint;
1768: notifyListeners(new PlotChangeEvent(this));
1769: }
1770:
1771:
1778: public Paint getLabelOutlinePaint() {
1779: return this.labelOutlinePaint;
1780: }
1781:
1782:
1790: public void setLabelOutlinePaint(Paint paint) {
1791: this.labelOutlinePaint = paint;
1792: notifyListeners(new PlotChangeEvent(this));
1793: }
1794:
1795:
1802: public Stroke getLabelOutlineStroke() {
1803: return this.labelOutlineStroke;
1804: }
1805:
1806:
1814: public void setLabelOutlineStroke(Stroke stroke) {
1815: this.labelOutlineStroke = stroke;
1816: notifyListeners(new PlotChangeEvent(this));
1817: }
1818:
1819:
1826: public Paint getLabelShadowPaint() {
1827: return this.labelShadowPaint;
1828: }
1829:
1830:
1838: public void setLabelShadowPaint(Paint paint) {
1839: this.labelShadowPaint = paint;
1840: notifyListeners(new PlotChangeEvent(this));
1841: }
1842:
1843:
1852: public RectangleInsets getLabelPadding() {
1853: return this.labelPadding;
1854: }
1855:
1856:
1866: public void setLabelPadding(RectangleInsets padding) {
1867: if (padding == null) {
1868: throw new IllegalArgumentException("Null 'padding' argument.");
1869: }
1870: this.labelPadding = padding;
1871: notifyListeners(new PlotChangeEvent(this));
1872: }
1873:
1874:
1882: public boolean getSimpleLabels() {
1883: return this.simpleLabels;
1884: }
1885:
1886:
1895: public void setSimpleLabels(boolean simple) {
1896: this.simpleLabels = simple;
1897: notifyListeners(new PlotChangeEvent(this));
1898: }
1899:
1900:
1909: public RectangleInsets getSimpleLabelOffset() {
1910: return this.simpleLabelOffset;
1911: }
1912:
1913:
1923: public void setSimpleLabelOffset(RectangleInsets offset) {
1924: if (offset == null) {
1925: throw new IllegalArgumentException("Null 'offset' argument.");
1926: }
1927: this.simpleLabelOffset = offset;
1928: notifyListeners(new PlotChangeEvent(this));
1929: }
1930:
1931:
1939: public AbstractPieLabelDistributor getLabelDistributor() {
1940: return this.labelDistributor;
1941: }
1942:
1943:
1951: public void setLabelDistributor(AbstractPieLabelDistributor distributor) {
1952: if (distributor == null) {
1953: throw new IllegalArgumentException("Null 'distributor' argument.");
1954: }
1955: this.labelDistributor = distributor;
1956: notifyListeners(new PlotChangeEvent(this));
1957: }
1958:
1959:
1968: public PieToolTipGenerator getToolTipGenerator() {
1969: return this.toolTipGenerator;
1970: }
1971:
1972:
1981: public void setToolTipGenerator(PieToolTipGenerator generator) {
1982: this.toolTipGenerator = generator;
1983: notifyListeners(new PlotChangeEvent(this));
1984: }
1985:
1986:
1993: public PieURLGenerator getURLGenerator() {
1994: return this.urlGenerator;
1995: }
1996:
1997:
2005: public void setURLGenerator(PieURLGenerator generator) {
2006: this.urlGenerator = generator;
2007: notifyListeners(new PlotChangeEvent(this));
2008: }
2009:
2010:
2018: public double getMinimumArcAngleToDraw() {
2019: return this.minimumArcAngleToDraw;
2020: }
2021:
2022:
2040: public void setMinimumArcAngleToDraw(double angle) {
2041: this.minimumArcAngleToDraw = angle;
2042: }
2043:
2044:
2051: public Shape getLegendItemShape() {
2052: return this.legendItemShape;
2053: }
2054:
2055:
2063: public void setLegendItemShape(Shape shape) {
2064: if (shape == null) {
2065: throw new IllegalArgumentException("Null 'shape' argument.");
2066: }
2067: this.legendItemShape = shape;
2068: notifyListeners(new PlotChangeEvent(this));
2069: }
2070:
2071:
2078: public PieSectionLabelGenerator getLegendLabelGenerator() {
2079: return this.legendLabelGenerator;
2080: }
2081:
2082:
2090: public void setLegendLabelGenerator(PieSectionLabelGenerator generator) {
2091: if (generator == null) {
2092: throw new IllegalArgumentException("Null 'generator' argument.");
2093: }
2094: this.legendLabelGenerator = generator;
2095: notifyListeners(new PlotChangeEvent(this));
2096: }
2097:
2098:
2105: public PieSectionLabelGenerator getLegendLabelToolTipGenerator() {
2106: return this.legendLabelToolTipGenerator;
2107: }
2108:
2109:
2117: public void setLegendLabelToolTipGenerator(
2118: PieSectionLabelGenerator generator) {
2119: this.legendLabelToolTipGenerator = generator;
2120: notifyListeners(new PlotChangeEvent(this));
2121: }
2122:
2123:
2132: public PieURLGenerator getLegendLabelURLGenerator() {
2133: return this.legendLabelURLGenerator;
2134: }
2135:
2136:
2146: public void setLegendLabelURLGenerator(PieURLGenerator generator) {
2147: this.legendLabelURLGenerator = generator;
2148: notifyListeners(new PlotChangeEvent(this));
2149: }
2150:
2151:
2166: public PiePlotState initialise(Graphics2D g2, Rectangle2D plotArea,
2167: PiePlot plot, Integer index, PlotRenderingInfo info) {
2168:
2169: PiePlotState state = new PiePlotState(info);
2170: state.setPassesRequired(2);
2171: state.setTotal(DatasetUtilities.calculatePieDatasetTotal(
2172: plot.getDataset()));
2173: state.setLatestAngle(plot.getStartAngle());
2174: return state;
2175:
2176: }
2177:
2178:
2189: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
2190: PlotState parentState, PlotRenderingInfo info) {
2191:
2192:
2193: RectangleInsets insets = getInsets();
2194: insets.trim(area);
2195:
2196: if (info != null) {
2197: info.setPlotArea(area);
2198: info.setDataArea(area);
2199: }
2200:
2201: drawBackground(g2, area);
2202: drawOutline(g2, area);
2203:
2204: Shape savedClip = g2.getClip();
2205: g2.clip(area);
2206:
2207: Composite originalComposite = g2.getComposite();
2208: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
2209: getForegroundAlpha()));
2210:
2211: if (!DatasetUtilities.isEmptyOrNull(this.dataset)) {
2212: drawPie(g2, area, info);
2213: }
2214: else {
2215: drawNoDataMessage(g2, area);
2216: }
2217:
2218: g2.setClip(savedClip);
2219: g2.setComposite(originalComposite);
2220:
2221: drawOutline(g2, area);
2222:
2223: }
2224:
2225:
2232: protected void drawPie(Graphics2D g2, Rectangle2D plotArea,
2233: PlotRenderingInfo info) {
2234:
2235: PiePlotState state = initialise(g2, plotArea, this, null, info);
2236:
2237:
2238: double labelWidth = 0.0;
2239: if (this.labelGenerator != null && !this.simpleLabels) {
2240: labelWidth = this.labelGap + this.maximumLabelWidth
2241: + this.labelLinkMargin;
2242: }
2243: double gapHorizontal = plotArea.getWidth() * (this.interiorGap
2244: + labelWidth);
2245: double gapVertical = plotArea.getHeight() * this.interiorGap;
2246:
2247: double linkX = plotArea.getX() + gapHorizontal / 2;
2248: double linkY = plotArea.getY() + gapVertical / 2;
2249: double linkW = plotArea.getWidth() - gapHorizontal;
2250: double linkH = plotArea.getHeight() - gapVertical;
2251:
2252:
2253: if (this.circular) {
2254: double min = Math.min(linkW, linkH) / 2;
2255: linkX = (linkX + linkX + linkW) / 2 - min;
2256: linkY = (linkY + linkY + linkH) / 2 - min;
2257: linkW = 2 * min;
2258: linkH = 2 * min;
2259: }
2260:
2261:
2262:
2263: Rectangle2D linkArea = new Rectangle2D.Double(linkX, linkY, linkW,
2264: linkH);
2265: state.setLinkArea(linkArea);
2266:
2267:
2268:
2269:
2270: double lm = 0.0;
2271: if (!this.simpleLabels) {
2272: lm = this.labelLinkMargin;
2273: }
2274: double hh = linkArea.getWidth() * lm;
2275: double vv = linkArea.getHeight() * lm;
2276: Rectangle2D explodeArea = new Rectangle2D.Double(linkX + hh / 2.0,
2277: linkY + vv / 2.0, linkW - hh, linkH - vv);
2278:
2279: state.setExplodedPieArea(explodeArea);
2280:
2281:
2282:
2283:
2284: double maximumExplodePercent = getMaximumExplodePercent();
2285: double percent = maximumExplodePercent / (1.0 + maximumExplodePercent);
2286:
2287: double h1 = explodeArea.getWidth() * percent;
2288: double v1 = explodeArea.getHeight() * percent;
2289: Rectangle2D pieArea = new Rectangle2D.Double(explodeArea.getX()
2290: + h1 / 2.0, explodeArea.getY() + v1 / 2.0,
2291: explodeArea.getWidth() - h1, explodeArea.getHeight() - v1);
2292:
2293: state.setPieArea(pieArea);
2294: state.setPieCenterX(pieArea.getCenterX());
2295: state.setPieCenterY(pieArea.getCenterY());
2296: state.setPieWRadius(pieArea.getWidth() / 2.0);
2297: state.setPieHRadius(pieArea.getHeight() / 2.0);
2298:
2299:
2300: if ((this.dataset != null) && (this.dataset.getKeys().size() > 0)) {
2301:
2302: List keys = this.dataset.getKeys();
2303: double totalValue = DatasetUtilities.calculatePieDatasetTotal(
2304: this.dataset);
2305:
2306: int passesRequired = state.getPassesRequired();
2307: for (int pass = 0; pass < passesRequired; pass++) {
2308: double runningTotal = 0.0;
2309: for (int section = 0; section < keys.size(); section++) {
2310: Number n = this.dataset.getValue(section);
2311: if (n != null) {
2312: double value = n.doubleValue();
2313: if (value > 0.0) {
2314: runningTotal += value;
2315: drawItem(g2, section, explodeArea, state, pass);
2316: }
2317: }
2318: }
2319: }
2320: if (this.simpleLabels) {
2321: drawSimpleLabels(g2, keys, totalValue, plotArea, linkArea,
2322: state);
2323: }
2324: else {
2325: drawLabels(g2, keys, totalValue, plotArea, linkArea, state);
2326: }
2327:
2328: }
2329: else {
2330: drawNoDataMessage(g2, plotArea);
2331: }
2332: }
2333:
2334:
2343: protected void drawItem(Graphics2D g2, int section, Rectangle2D dataArea,
2344: PiePlotState state, int currentPass) {
2345:
2346: Number n = this.dataset.getValue(section);
2347: if (n == null) {
2348: return;
2349: }
2350: double value = n.doubleValue();
2351: double angle1 = 0.0;
2352: double angle2 = 0.0;
2353:
2354: if (this.direction == Rotation.CLOCKWISE) {
2355: angle1 = state.getLatestAngle();
2356: angle2 = angle1 - value / state.getTotal() * 360.0;
2357: }
2358: else if (this.direction == Rotation.ANTICLOCKWISE) {
2359: angle1 = state.getLatestAngle();
2360: angle2 = angle1 + value / state.getTotal() * 360.0;
2361: }
2362: else {
2363: throw new IllegalStateException("Rotation type not recognised.");
2364: }
2365:
2366: double angle = (angle2 - angle1);
2367: if (Math.abs(angle) > getMinimumArcAngleToDraw()) {
2368: double ep = 0.0;
2369: double mep = getMaximumExplodePercent();
2370: if (mep > 0.0) {
2371: ep = getExplodePercent(section) / mep;
2372: }
2373: Rectangle2D arcBounds = getArcBounds(state.getPieArea(),
2374: state.getExplodedPieArea(), angle1, angle, ep);
2375: Arc2D.Double arc = new Arc2D.Double(arcBounds, angle1, angle,
2376: Arc2D.PIE);
2377:
2378: if (currentPass == 0) {
2379: if (this.shadowPaint != null) {
2380: Shape shadowArc = ShapeUtilities.createTranslatedShape(
2381: arc, (float) this.shadowXOffset,
2382: (float) this.shadowYOffset);
2383: g2.setPaint(this.shadowPaint);
2384: g2.fill(shadowArc);
2385: }
2386: }
2387: else if (currentPass == 1) {
2388: Comparable key = getSectionKey(section);
2389: Paint paint = lookupSectionPaint(key, true);
2390: g2.setPaint(paint);
2391: g2.fill(arc);
2392:
2393: Paint outlinePaint = lookupSectionOutlinePaint(key);
2394: Stroke outlineStroke = lookupSectionOutlineStroke(key);
2395: if (this.sectionOutlinesVisible) {
2396: g2.setPaint(outlinePaint);
2397: g2.setStroke(outlineStroke);
2398: g2.draw(arc);
2399: }
2400:
2401:
2402:
2403: if (state.getInfo() != null) {
2404: EntityCollection entities = state.getEntityCollection();
2405: if (entities != null) {
2406: String tip = null;
2407: if (this.toolTipGenerator != null) {
2408: tip = this.toolTipGenerator.generateToolTip(
2409: this.dataset, key);
2410: }
2411: String url = null;
2412: if (this.urlGenerator != null) {
2413: url = this.urlGenerator.generateURL(this.dataset,
2414: key, this.pieIndex);
2415: }
2416: PieSectionEntity entity = new PieSectionEntity(
2417: arc, this.dataset, this.pieIndex, section, key,
2418: tip, url);
2419: entities.add(entity);
2420: }
2421: }
2422: }
2423: }
2424: state.setLatestAngle(angle2);
2425: }
2426:
2427:
2439: protected void drawSimpleLabels(Graphics2D g2, List keys,
2440: double totalValue, Rectangle2D plotArea, Rectangle2D pieArea,
2441: PiePlotState state) {
2442:
2443: Composite originalComposite = g2.getComposite();
2444: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
2445: 1.0f));
2446:
2447: RectangleInsets labelInsets = new RectangleInsets(UnitType.RELATIVE,
2448: 0.18, 0.18, 0.18, 0.18);
2449: Rectangle2D labelsArea = labelInsets.createInsetRectangle(pieArea);
2450: double runningTotal = 0.0;
2451: Iterator iterator = keys.iterator();
2452: while (iterator.hasNext()) {
2453: Comparable key = (Comparable) iterator.next();
2454: boolean include = true;
2455: double v = 0.0;
2456: Number n = getDataset().getValue(key);
2457: if (n == null) {
2458: include = !getIgnoreNullValues();
2459: }
2460: else {
2461: v = n.doubleValue();
2462: include = getIgnoreZeroValues() ? v > 0.0 : v >= 0.0;
2463: }
2464:
2465: if (include) {
2466: runningTotal = runningTotal + v;
2467:
2468:
2469: double mid = getStartAngle() + (getDirection().getFactor()
2470: * ((runningTotal - v / 2.0) * 360) / totalValue);
2471:
2472: Arc2D arc = new Arc2D.Double(labelsArea, getStartAngle(),
2473: mid - getStartAngle(), Arc2D.OPEN);
2474: int x = (int) arc.getEndPoint().getX();
2475: int y = (int) arc.getEndPoint().getY();
2476:
2477: PieSectionLabelGenerator labelGenerator = getLabelGenerator();
2478: if (labelGenerator == null) {
2479: continue;
2480: }
2481: String label = labelGenerator.generateSectionLabel(
2482: this.dataset, key);
2483: if (label == null) {
2484: continue;
2485: }
2486: g2.setFont(this.labelFont);
2487: FontMetrics fm = g2.getFontMetrics();
2488: Rectangle2D bounds = TextUtilities.getTextBounds(label, g2, fm);
2489: Rectangle2D out = this.labelPadding.createOutsetRectangle(
2490: bounds);
2491: Shape bg = ShapeUtilities.createTranslatedShape(out,
2492: x - bounds.getCenterX(), y - bounds.getCenterY());
2493: if (this.labelShadowPaint != null) {
2494: Shape shadow = ShapeUtilities.createTranslatedShape(bg,
2495: this.shadowXOffset, this.shadowYOffset);
2496: g2.setPaint(this.labelShadowPaint);
2497: g2.fill(shadow);
2498: }
2499: if (this.labelBackgroundPaint != null) {
2500: g2.setPaint(this.labelBackgroundPaint);
2501: g2.fill(bg);
2502: }
2503: if (this.labelOutlinePaint != null
2504: && this.labelOutlineStroke != null) {
2505: g2.setPaint(this.labelOutlinePaint);
2506: g2.setStroke(this.labelOutlineStroke);
2507: g2.draw(bg);
2508: }
2509:
2510: g2.setPaint(this.labelPaint);
2511: g2.setFont(this.labelFont);
2512: TextUtilities.drawAlignedString(getLabelGenerator()
2513: .generateSectionLabel(getDataset(), key), g2, x, y,
2514: TextAnchor.CENTER);
2515:
2516: }
2517: }
2518:
2519: g2.setComposite(originalComposite);
2520:
2521: }
2522:
2523:
2533: protected void drawLabels(Graphics2D g2, List keys, double totalValue,
2534: Rectangle2D plotArea, Rectangle2D linkArea,
2535: PiePlotState state) {
2536:
2537: Composite originalComposite = g2.getComposite();
2538: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
2539: 1.0f));
2540:
2541:
2542: DefaultKeyedValues leftKeys = new DefaultKeyedValues();
2543: DefaultKeyedValues rightKeys = new DefaultKeyedValues();
2544:
2545: double runningTotal = 0.0;
2546: Iterator iterator = keys.iterator();
2547: while (iterator.hasNext()) {
2548: Comparable key = (Comparable) iterator.next();
2549: boolean include = true;
2550: double v = 0.0;
2551: Number n = this.dataset.getValue(key);
2552: if (n == null) {
2553: include = !this.ignoreNullValues;
2554: }
2555: else {
2556: v = n.doubleValue();
2557: include = this.ignoreZeroValues ? v > 0.0 : v >= 0.0;
2558: }
2559:
2560: if (include) {
2561: runningTotal = runningTotal + v;
2562:
2563:
2564: double mid = this.startAngle + (this.direction.getFactor()
2565: * ((runningTotal - v / 2.0) * 360) / totalValue);
2566: if (Math.cos(Math.toRadians(mid)) < 0.0) {
2567: leftKeys.addValue(key, new Double(mid));
2568: }
2569: else {
2570: rightKeys.addValue(key, new Double(mid));
2571: }
2572: }
2573: }
2574:
2575: g2.setFont(getLabelFont());
2576: float maxLabelWidth = (float) (getMaximumLabelWidth()
2577: * plotArea.getWidth());
2578:
2579:
2580: if (this.labelGenerator != null) {
2581: drawLeftLabels(leftKeys, g2, plotArea, linkArea, maxLabelWidth,
2582: state);
2583: drawRightLabels(rightKeys, g2, plotArea, linkArea, maxLabelWidth,
2584: state);
2585: }
2586: g2.setComposite(originalComposite);
2587:
2588: }
2589:
2590:
2602: protected void drawLeftLabels(KeyedValues leftKeys, Graphics2D g2,
2603: Rectangle2D plotArea, Rectangle2D linkArea,
2604: float maxLabelWidth, PiePlotState state) {
2605:
2606: this.labelDistributor.clear();
2607: double lGap = plotArea.getWidth() * this.labelGap;
2608: double verticalLinkRadius = state.getLinkArea().getHeight() / 2.0;
2609: for (int i = 0; i < leftKeys.getItemCount(); i++) {
2610: String label = this.labelGenerator.generateSectionLabel(
2611: this.dataset, leftKeys.getKey(i));
2612: if (label != null) {
2613: TextBlock block = TextUtilities.createTextBlock(label,
2614: this.labelFont, this.labelPaint, maxLabelWidth,
2615: new G2TextMeasurer(g2));
2616: TextBox labelBox = new TextBox(block);
2617: labelBox.setBackgroundPaint(this.labelBackgroundPaint);
2618: labelBox.setOutlinePaint(this.labelOutlinePaint);
2619: labelBox.setOutlineStroke(this.labelOutlineStroke);
2620: labelBox.setShadowPaint(this.labelShadowPaint);
2621: labelBox.setInteriorGap(this.labelPadding);
2622: double theta = Math.toRadians(
2623: leftKeys.getValue(i).doubleValue());
2624: double baseY = state.getPieCenterY() - Math.sin(theta)
2625: * verticalLinkRadius;
2626: double hh = labelBox.getHeight(g2);
2627:
2628: this.labelDistributor.addPieLabelRecord(new PieLabelRecord(
2629: leftKeys.getKey(i), theta, baseY, labelBox, hh,
2630: lGap / 2.0 + lGap / 2.0 * -Math.cos(theta), 0.9
2631: + getExplodePercent(leftKeys.getKey(i))));
2632: }
2633: }
2634: this.labelDistributor.distributeLabels(plotArea.getMinY(),
2635: plotArea.getHeight());
2636: for (int i = 0; i < this.labelDistributor.getItemCount(); i++) {
2637: drawLeftLabel(g2, state,
2638: this.labelDistributor.getPieLabelRecord(i));
2639: }
2640: }
2641:
2642:
2652: protected void drawRightLabels(KeyedValues keys, Graphics2D g2,
2653: Rectangle2D plotArea, Rectangle2D linkArea,
2654: float maxLabelWidth, PiePlotState state) {
2655:
2656:
2657: this.labelDistributor.clear();
2658: double lGap = plotArea.getWidth() * this.labelGap;
2659: double verticalLinkRadius = state.getLinkArea().getHeight() / 2.0;
2660:
2661: for (int i = 0; i < keys.getItemCount(); i++) {
2662: String label = this.labelGenerator.generateSectionLabel(
2663: this.dataset, keys.getKey(i));
2664:
2665: if (label != null) {
2666: TextBlock block = TextUtilities.createTextBlock(label,
2667: this.labelFont, this.labelPaint, maxLabelWidth,
2668: new G2TextMeasurer(g2));
2669: TextBox labelBox = new TextBox(block);
2670: labelBox.setBackgroundPaint(this.labelBackgroundPaint);
2671: labelBox.setOutlinePaint(this.labelOutlinePaint);
2672: labelBox.setOutlineStroke(this.labelOutlineStroke);
2673: labelBox.setShadowPaint(this.labelShadowPaint);
2674: labelBox.setInteriorGap(this.labelPadding);
2675: double theta = Math.toRadians(keys.getValue(i).doubleValue());
2676: double baseY = state.getPieCenterY()
2677: - Math.sin(theta) * verticalLinkRadius;
2678: double hh = labelBox.getHeight(g2);
2679: this.labelDistributor.addPieLabelRecord(new PieLabelRecord(
2680: keys.getKey(i), theta, baseY, labelBox, hh,
2681: lGap / 2.0 + lGap / 2.0 * Math.cos(theta),
2682: 0.9 + getExplodePercent(keys.getKey(i))));
2683: }
2684: }
2685: this.labelDistributor.distributeLabels(plotArea.getMinY(),
2686: plotArea.getHeight());
2687: for (int i = 0; i < this.labelDistributor.getItemCount(); i++) {
2688: drawRightLabel(g2, state,
2689: this.labelDistributor.getPieLabelRecord(i));
2690: }
2691:
2692: }
2693:
2694:
2699: public LegendItemCollection getLegendItems() {
2700:
2701: LegendItemCollection result = new LegendItemCollection();
2702: if (this.dataset == null) {
2703: return result;
2704: }
2705: List keys = this.dataset.getKeys();
2706: int section = 0;
2707: Shape shape = getLegendItemShape();
2708: Iterator iterator = keys.iterator();
2709: while (iterator.hasNext()) {
2710: Comparable key = (Comparable) iterator.next();
2711: Number n = this.dataset.getValue(key);
2712: boolean include = true;
2713: if (n == null) {
2714: include = !this.ignoreNullValues;
2715: }
2716: else {
2717: double v = n.doubleValue();
2718: if (v == 0.0) {
2719: include = !this.ignoreZeroValues;
2720: }
2721: else {
2722: include = v > 0.0;
2723: }
2724: }
2725: if (include) {
2726: String label = this.legendLabelGenerator.generateSectionLabel(
2727: this.dataset, key);
2728: if (label != null) {
2729: String description = label;
2730: String toolTipText = null;
2731: if (this.legendLabelToolTipGenerator != null) {
2732: toolTipText = this.legendLabelToolTipGenerator
2733: .generateSectionLabel(this.dataset, key);
2734: }
2735: String urlText = null;
2736: if (this.legendLabelURLGenerator != null) {
2737: urlText = this.legendLabelURLGenerator.generateURL(
2738: this.dataset, key, this.pieIndex);
2739: }
2740: Paint paint = lookupSectionPaint(key, true);
2741: Paint outlinePaint = lookupSectionOutlinePaint(key);
2742: Stroke outlineStroke = lookupSectionOutlineStroke(key);
2743: LegendItem item = new LegendItem(label, description,
2744: toolTipText, urlText, true, shape, true, paint,
2745: true, outlinePaint, outlineStroke,
2746: false,
2747: new Line2D.Float(), new BasicStroke(), Color.black);
2748: item.setDataset(getDataset());
2749: result.add(item);
2750: }
2751: section++;
2752: }
2753: else {
2754: section++;
2755: }
2756: }
2757: return result;
2758: }
2759:
2760:
2765: public String getPlotType() {
2766: return localizationResources.getString("Pie_Plot");
2767: }
2768:
2769:
2783: protected Rectangle2D getArcBounds(Rectangle2D unexploded,
2784: Rectangle2D exploded,
2785: double angle, double extent,
2786: double explodePercent) {
2787:
2788: if (explodePercent == 0.0) {
2789: return unexploded;
2790: }
2791: else {
2792: Arc2D arc1 = new Arc2D.Double(unexploded, angle, extent / 2,
2793: Arc2D.OPEN);
2794: Point2D point1 = arc1.getEndPoint();
2795: Arc2D.Double arc2 = new Arc2D.Double(exploded, angle, extent / 2,
2796: Arc2D.OPEN);
2797: Point2D point2 = arc2.getEndPoint();
2798: double deltaX = (point1.getX() - point2.getX()) * explodePercent;
2799: double deltaY = (point1.getY() - point2.getY()) * explodePercent;
2800: return new Rectangle2D.Double(unexploded.getX() - deltaX,
2801: unexploded.getY() - deltaY, unexploded.getWidth(),
2802: unexploded.getHeight());
2803: }
2804: }
2805:
2806:
2813: protected void drawLeftLabel(Graphics2D g2, PiePlotState state,
2814: PieLabelRecord record) {
2815:
2816: double anchorX = state.getLinkArea().getMinX();
2817: double targetX = anchorX - record.getGap();
2818: double targetY = record.getAllocatedY();
2819:
2820: if (this.labelLinksVisible) {
2821: double theta = record.getAngle();
2822: double linkX = state.getPieCenterX() + Math.cos(theta)
2823: * state.getPieWRadius() * record.getLinkPercent();
2824: double linkY = state.getPieCenterY() - Math.sin(theta)
2825: * state.getPieHRadius() * record.getLinkPercent();
2826: double elbowX = state.getPieCenterX() + Math.cos(theta)
2827: * state.getLinkArea().getWidth() / 2.0;
2828: double elbowY = state.getPieCenterY() - Math.sin(theta)
2829: * state.getLinkArea().getHeight() / 2.0;
2830: double anchorY = elbowY;
2831: g2.setPaint(this.labelLinkPaint);
2832: g2.setStroke(this.labelLinkStroke);
2833: g2.draw(new Line2D.Double(linkX, linkY, elbowX, elbowY));
2834: g2.draw(new Line2D.Double(anchorX, anchorY, elbowX, elbowY));
2835: g2.draw(new Line2D.Double(anchorX, anchorY, targetX, targetY));
2836: }
2837: TextBox tb = record.getLabel();
2838: tb.draw(g2, (float) targetX, (float) targetY, RectangleAnchor.RIGHT);
2839:
2840: }
2841:
2842:
2849: protected void drawRightLabel(Graphics2D g2, PiePlotState state,
2850: PieLabelRecord record) {
2851:
2852: double anchorX = state.getLinkArea().getMaxX();
2853: double targetX = anchorX + record.getGap();
2854: double targetY = record.getAllocatedY();
2855:
2856: if (this.labelLinksVisible) {
2857: double theta = record.getAngle();
2858: double linkX = state.getPieCenterX() + Math.cos(theta)
2859: * state.getPieWRadius() * record.getLinkPercent();
2860: double linkY = state.getPieCenterY() - Math.sin(theta)
2861: * state.getPieHRadius() * record.getLinkPercent();
2862: double elbowX = state.getPieCenterX() + Math.cos(theta)
2863: * state.getLinkArea().getWidth() / 2.0;
2864: double elbowY = state.getPieCenterY() - Math.sin(theta)
2865: * state.getLinkArea().getHeight() / 2.0;
2866: double anchorY = elbowY;
2867: g2.setPaint(this.labelLinkPaint);
2868: g2.setStroke(this.labelLinkStroke);
2869: g2.draw(new Line2D.Double(linkX, linkY, elbowX, elbowY));
2870: g2.draw(new Line2D.Double(anchorX, anchorY, elbowX, elbowY));
2871: g2.draw(new Line2D.Double(anchorX, anchorY, targetX, targetY));
2872: }
2873:
2874: TextBox tb = record.getLabel();
2875: tb.draw(g2, (float) targetX, (float) targetY, RectangleAnchor.LEFT);
2876:
2877: }
2878:
2879:
2887: public boolean equals(Object obj) {
2888: if (obj == this) {
2889: return true;
2890: }
2891: if (!(obj instanceof PiePlot)) {
2892: return false;
2893: }
2894: if (!super.equals(obj)) {
2895: return false;
2896: }
2897: PiePlot that = (PiePlot) obj;
2898: if (this.pieIndex != that.pieIndex) {
2899: return false;
2900: }
2901: if (this.interiorGap != that.interiorGap) {
2902: return false;
2903: }
2904: if (this.circular != that.circular) {
2905: return false;
2906: }
2907: if (this.startAngle != that.startAngle) {
2908: return false;
2909: }
2910: if (this.direction != that.direction) {
2911: return false;
2912: }
2913: if (this.ignoreZeroValues != that.ignoreZeroValues) {
2914: return false;
2915: }
2916: if (this.ignoreNullValues != that.ignoreNullValues) {
2917: return false;
2918: }
2919: if (!PaintUtilities.equal(this.sectionPaint, that.sectionPaint)) {
2920: return false;
2921: }
2922: if (!ObjectUtilities.equal(this.sectionPaintMap,
2923: that.sectionPaintMap)) {
2924: return false;
2925: }
2926: if (!PaintUtilities.equal(this.baseSectionPaint,
2927: that.baseSectionPaint)) {
2928: return false;
2929: }
2930: if (this.sectionOutlinesVisible != that.sectionOutlinesVisible) {
2931: return false;
2932: }
2933: if (!PaintUtilities.equal(this.sectionOutlinePaint,
2934: that.sectionOutlinePaint)) {
2935: return false;
2936: }
2937: if (!ObjectUtilities.equal(this.sectionOutlinePaintMap,
2938: that.sectionOutlinePaintMap)) {
2939: return false;
2940: }
2941: if (!PaintUtilities.equal(
2942: this.baseSectionOutlinePaint, that.baseSectionOutlinePaint
2943: )) {
2944: return false;
2945: }
2946: if (!ObjectUtilities.equal(this.sectionOutlineStroke,
2947: that.sectionOutlineStroke)) {
2948: return false;
2949: }
2950: if (!ObjectUtilities.equal(this.sectionOutlineStrokeMap,
2951: that.sectionOutlineStrokeMap)) {
2952: return false;
2953: }
2954: if (!ObjectUtilities.equal(
2955: this.baseSectionOutlineStroke, that.baseSectionOutlineStroke
2956: )) {
2957: return false;
2958: }
2959: if (!PaintUtilities.equal(this.shadowPaint, that.shadowPaint)) {
2960: return false;
2961: }
2962: if (!(this.shadowXOffset == that.shadowXOffset)) {
2963: return false;
2964: }
2965: if (!(this.shadowYOffset == that.shadowYOffset)) {
2966: return false;
2967: }
2968: if (!ObjectUtilities.equal(this.explodePercentages,
2969: that.explodePercentages)) {
2970: return false;
2971: }
2972: if (!ObjectUtilities.equal(this.labelGenerator,
2973: that.labelGenerator)) {
2974: return false;
2975: }
2976: if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) {
2977: return false;
2978: }
2979: if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
2980: return false;
2981: }
2982: if (!PaintUtilities.equal(this.labelBackgroundPaint,
2983: that.labelBackgroundPaint)) {
2984: return false;
2985: }
2986: if (!PaintUtilities.equal(this.labelOutlinePaint,
2987: that.labelOutlinePaint)) {
2988: return false;
2989: }
2990: if (!ObjectUtilities.equal(this.labelOutlineStroke,
2991: that.labelOutlineStroke)) {
2992: return false;
2993: }
2994: if (!PaintUtilities.equal(this.labelShadowPaint,
2995: that.labelShadowPaint)) {
2996: return false;
2997: }
2998: if (this.simpleLabels != that.simpleLabels) {
2999: return false;
3000: }
3001: if (!this.simpleLabelOffset.equals(that.simpleLabelOffset)) {
3002: return false;
3003: }
3004: if (!this.labelPadding.equals(that.labelPadding)) {
3005: return false;
3006: }
3007: if (!(this.maximumLabelWidth == that.maximumLabelWidth)) {
3008: return false;
3009: }
3010: if (!(this.labelGap == that.labelGap)) {
3011: return false;
3012: }
3013: if (!(this.labelLinkMargin == that.labelLinkMargin)) {
3014: return false;
3015: }
3016: if (this.labelLinksVisible != that.labelLinksVisible) {
3017: return false;
3018: }
3019: if (!PaintUtilities.equal(this.labelLinkPaint, that.labelLinkPaint)) {
3020: return false;
3021: }
3022: if (!ObjectUtilities.equal(this.labelLinkStroke,
3023: that.labelLinkStroke)) {
3024: return false;
3025: }
3026: if (!ObjectUtilities.equal(this.toolTipGenerator,
3027: that.toolTipGenerator)) {
3028: return false;
3029: }
3030: if (!ObjectUtilities.equal(this.urlGenerator, that.urlGenerator)) {
3031: return false;
3032: }
3033: if (!(this.minimumArcAngleToDraw == that.minimumArcAngleToDraw)) {
3034: return false;
3035: }
3036: if (!ShapeUtilities.equal(this.legendItemShape, that.legendItemShape)) {
3037: return false;
3038: }
3039: if (!ObjectUtilities.equal(this.legendLabelGenerator,
3040: that.legendLabelGenerator)) {
3041: return false;
3042: }
3043: if (!ObjectUtilities.equal(this.legendLabelToolTipGenerator,
3044: that.legendLabelToolTipGenerator)) {
3045: return false;
3046: }
3047: if (!ObjectUtilities.equal(this.legendLabelURLGenerator,
3048: that.legendLabelURLGenerator)) {
3049: return false;
3050: }
3051:
3052: return true;
3053: }
3054:
3055:
3063: public Object clone() throws CloneNotSupportedException {
3064: PiePlot clone = (PiePlot) super.clone();
3065: if (clone.dataset != null) {
3066: clone.dataset.addChangeListener(clone);
3067: }
3068: if (this.urlGenerator instanceof PublicCloneable) {
3069: clone.urlGenerator = (PieURLGenerator) ObjectUtilities.clone(
3070: this.urlGenerator);
3071: }
3072: clone.legendItemShape = ShapeUtilities.clone(this.legendItemShape);
3073: if (this.legendLabelGenerator != null) {
3074: clone.legendLabelGenerator = (PieSectionLabelGenerator)
3075: ObjectUtilities.clone(this.legendLabelGenerator);
3076: }
3077: if (this.legendLabelToolTipGenerator != null) {
3078: clone.legendLabelToolTipGenerator = (PieSectionLabelGenerator)
3079: ObjectUtilities.clone(this.legendLabelToolTipGenerator);
3080: }
3081: if (this.legendLabelURLGenerator instanceof PublicCloneable) {
3082: clone.legendLabelURLGenerator = (PieURLGenerator)
3083: ObjectUtilities.clone(this.legendLabelURLGenerator);
3084: }
3085: return clone;
3086: }
3087:
3088:
3095: private void writeObject(ObjectOutputStream stream) throws IOException {
3096: stream.defaultWriteObject();
3097: SerialUtilities.writePaint(this.sectionPaint, stream);
3098: SerialUtilities.writePaint(this.baseSectionPaint, stream);
3099: SerialUtilities.writePaint(this.sectionOutlinePaint, stream);
3100: SerialUtilities.writePaint(this.baseSectionOutlinePaint, stream);
3101: SerialUtilities.writeStroke(this.sectionOutlineStroke, stream);
3102: SerialUtilities.writeStroke(this.baseSectionOutlineStroke, stream);
3103: SerialUtilities.writePaint(this.shadowPaint, stream);
3104: SerialUtilities.writePaint(this.labelPaint, stream);
3105: SerialUtilities.writePaint(this.labelBackgroundPaint, stream);
3106: SerialUtilities.writePaint(this.labelOutlinePaint, stream);
3107: SerialUtilities.writeStroke(this.labelOutlineStroke, stream);
3108: SerialUtilities.writePaint(this.labelShadowPaint, stream);
3109: SerialUtilities.writePaint(this.labelLinkPaint, stream);
3110: SerialUtilities.writeStroke(this.labelLinkStroke, stream);
3111: SerialUtilities.writeShape(this.legendItemShape, stream);
3112: }
3113:
3114:
3122: private void readObject(ObjectInputStream stream)
3123: throws IOException, ClassNotFoundException {
3124: stream.defaultReadObject();
3125: this.sectionPaint = SerialUtilities.readPaint(stream);
3126: this.baseSectionPaint = SerialUtilities.readPaint(stream);
3127: this.sectionOutlinePaint = SerialUtilities.readPaint(stream);
3128: this.baseSectionOutlinePaint = SerialUtilities.readPaint(stream);
3129: this.sectionOutlineStroke = SerialUtilities.readStroke(stream);
3130: this.baseSectionOutlineStroke = SerialUtilities.readStroke(stream);
3131: this.shadowPaint = SerialUtilities.readPaint(stream);
3132: this.labelPaint = SerialUtilities.readPaint(stream);
3133: this.labelBackgroundPaint = SerialUtilities.readPaint(stream);
3134: this.labelOutlinePaint = SerialUtilities.readPaint(stream);
3135: this.labelOutlineStroke = SerialUtilities.readStroke(stream);
3136: this.labelShadowPaint = SerialUtilities.readPaint(stream);
3137: this.labelLinkPaint = SerialUtilities.readPaint(stream);
3138: this.labelLinkStroke = SerialUtilities.readStroke(stream);
3139: this.legendItemShape = SerialUtilities.readShape(stream);
3140: }
3141:
3142:
3143:
3144:
3153: public Paint getSectionPaint(int section) {
3154: Comparable key = getSectionKey(section);
3155: return getSectionPaint(key);
3156: }
3157:
3158:
3167: public void setSectionPaint(int section, Paint paint) {
3168: Comparable key = getSectionKey(section);
3169: setSectionPaint(key, paint);
3170: }
3171:
3172:
3181: public Paint getSectionOutlinePaint(int section) {
3182: Comparable key = getSectionKey(section);
3183: return getSectionOutlinePaint(key);
3184: }
3185:
3186:
3196: public void setSectionOutlinePaint(int section, Paint paint) {
3197: Comparable key = getSectionKey(section);
3198: setSectionOutlinePaint(key, paint);
3199: }
3200:
3201:
3210: public Stroke getSectionOutlineStroke(int section) {
3211: Comparable key = getSectionKey(section);
3212: return getSectionOutlineStroke(key);
3213: }
3214:
3215:
3225: public void setSectionOutlineStroke(int section, Stroke stroke) {
3226: Comparable key = getSectionKey(section);
3227: setSectionOutlineStroke(key, stroke);
3228: }
3229:
3230:
3239: public double getExplodePercent(int section) {
3240: Comparable key = getSectionKey(section);
3241: return getExplodePercent(key);
3242: }
3243:
3244:
3253: public void setExplodePercent(int section, double percent) {
3254: Comparable key = getSectionKey(section);
3255: setExplodePercent(key, percent);
3256: }
3257:
3258: }