1:
87:
88: package ;
89:
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102:
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: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122: import ;
123: import ;
124: import ;
125: import ;
126: import ;
127: import ;
128: import ;
129:
130:
134: public class XYBarRenderer extends AbstractXYItemRenderer
135: implements XYItemRenderer, Cloneable, PublicCloneable, Serializable {
136:
137:
138: private static final long serialVersionUID = 770559577251370036L;
139:
140:
143: protected class XYBarRendererState extends XYItemRendererState {
144:
145:
146: private double g2Base;
147:
148:
153: public XYBarRendererState(PlotRenderingInfo info) {
154: super(info);
155: }
156:
157:
162: public double getG2Base() {
163: return this.g2Base;
164: }
165:
166:
171: public void setG2Base(double value) {
172: this.g2Base = value;
173: }
174: }
175:
176:
177: private double base;
178:
179:
183: private boolean useYInterval;
184:
185:
186: private double margin;
187:
188:
189: private boolean drawBarOutline;
190:
191:
195: private GradientPaintTransformer gradientPaintTransformer;
196:
197:
201: private transient Shape legendBar;
202:
203:
207: private ItemLabelPosition positiveItemLabelPositionFallback;
208:
209:
213: private ItemLabelPosition negativeItemLabelPositionFallback;
214:
215:
218: public XYBarRenderer() {
219: this(0.0);
220: }
221:
222:
227: public XYBarRenderer(double margin) {
228: super();
229: this.margin = margin;
230: this.base = 0.0;
231: this.useYInterval = false;
232: this.gradientPaintTransformer = new StandardGradientPaintTransformer();
233: this.drawBarOutline = true;
234: this.legendBar = new Rectangle2D.Double(-3.0, -5.0, 6.0, 10.0);
235: }
236:
237:
244: public double getBase() {
245: return this.base;
246: }
247:
248:
258: public void setBase(double base) {
259: this.base = base;
260: notifyListeners(new RendererChangeEvent(this));
261: }
262:
263:
271: public boolean getUseYInterval() {
272: return this.useYInterval;
273: }
274:
275:
284: public void setUseYInterval(boolean use) {
285: if (this.useYInterval != use) {
286: this.useYInterval = use;
287: notifyListeners(new RendererChangeEvent(this));
288: }
289: }
290:
291:
299: public double getMargin() {
300: return this.margin;
301: }
302:
303:
311: public void setMargin(double margin) {
312: this.margin = margin;
313: notifyListeners(new RendererChangeEvent(this));
314: }
315:
316:
323: public boolean isDrawBarOutline() {
324: return this.drawBarOutline;
325: }
326:
327:
335: public void setDrawBarOutline(boolean draw) {
336: this.drawBarOutline = draw;
337: notifyListeners(new RendererChangeEvent(this));
338: }
339:
340:
348: public GradientPaintTransformer getGradientPaintTransformer() {
349: return this.gradientPaintTransformer;
350: }
351:
352:
360: public void setGradientPaintTransformer(
361: GradientPaintTransformer transformer) {
362: this.gradientPaintTransformer = transformer;
363: notifyListeners(new RendererChangeEvent(this));
364: }
365:
366:
374: public Shape getLegendBar() {
375: return this.legendBar;
376: }
377:
378:
386: public void setLegendBar(Shape bar) {
387: if (bar == null) {
388: throw new IllegalArgumentException("Null 'bar' argument.");
389: }
390: this.legendBar = bar;
391: notifyListeners(new RendererChangeEvent(this));
392: }
393:
394:
403: public ItemLabelPosition getPositiveItemLabelPositionFallback() {
404: return this.positiveItemLabelPositionFallback;
405: }
406:
407:
417: public void setPositiveItemLabelPositionFallback(
418: ItemLabelPosition position) {
419: this.positiveItemLabelPositionFallback = position;
420: notifyListeners(new RendererChangeEvent(this));
421: }
422:
423:
432: public ItemLabelPosition getNegativeItemLabelPositionFallback() {
433: return this.negativeItemLabelPositionFallback;
434: }
435:
436:
446: public void setNegativeItemLabelPositionFallback(
447: ItemLabelPosition position) {
448: this.negativeItemLabelPositionFallback = position;
449: notifyListeners(new RendererChangeEvent(this));
450: }
451:
452:
467: public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea,
468: XYPlot plot, XYDataset dataset, PlotRenderingInfo info) {
469:
470: XYBarRendererState state = new XYBarRendererState(info);
471: ValueAxis rangeAxis = plot.getRangeAxisForDataset(plot.indexOf(
472: dataset));
473: state.setG2Base(rangeAxis.valueToJava2D(this.base, dataArea,
474: plot.getRangeAxisEdge()));
475: return state;
476:
477: }
478:
479:
488: public LegendItem getLegendItem(int datasetIndex, int series) {
489: LegendItem result = null;
490: XYPlot xyplot = getPlot();
491: if (xyplot != null) {
492: XYDataset dataset = xyplot.getDataset(datasetIndex);
493: if (dataset != null) {
494: XYSeriesLabelGenerator lg = getLegendItemLabelGenerator();
495: String label = lg.generateLabel(dataset, series);
496: String description = label;
497: String toolTipText = null;
498: if (getLegendItemToolTipGenerator() != null) {
499: toolTipText = getLegendItemToolTipGenerator().generateLabel(
500: dataset, series);
501: }
502: String urlText = null;
503: if (getLegendItemURLGenerator() != null) {
504: urlText = getLegendItemURLGenerator().generateLabel(
505: dataset, series);
506: }
507: Shape shape = this.legendBar;
508: Paint paint = getSeriesPaint(series);
509: Paint outlinePaint = getSeriesOutlinePaint(series);
510: Stroke outlineStroke = getSeriesOutlineStroke(series);
511: if (this.drawBarOutline) {
512: result = new LegendItem(label, description, toolTipText,
513: urlText, shape, paint, outlineStroke, outlinePaint);
514: }
515: else {
516: result = new LegendItem(label, description, toolTipText,
517: urlText, shape, paint);
518: }
519: if (getGradientPaintTransformer() != null) {
520: result.setFillPaintTransformer(
521: getGradientPaintTransformer());
522: }
523: }
524: }
525: return result;
526: }
527:
528:
546: public void drawItem(Graphics2D g2,
547: XYItemRendererState state,
548: Rectangle2D dataArea,
549: PlotRenderingInfo info,
550: XYPlot plot,
551: ValueAxis domainAxis,
552: ValueAxis rangeAxis,
553: XYDataset dataset,
554: int series,
555: int item,
556: CrosshairState crosshairState,
557: int pass) {
558:
559: if (!getItemVisible(series, item)) {
560: return;
561: }
562: IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
563:
564: double value0;
565: double value1;
566: if (this.useYInterval) {
567: value0 = intervalDataset.getStartYValue(series, item);
568: value1 = intervalDataset.getEndYValue(series, item);
569: }
570: else {
571: value0 = this.base;
572: value1 = intervalDataset.getYValue(series, item);
573: }
574: if (Double.isNaN(value0) || Double.isNaN(value1)) {
575: return;
576: }
577: if (value0 <= value1) {
578: if (!rangeAxis.getRange().intersects(value0, value1)) {
579: return;
580: }
581: }
582: else {
583: if (!rangeAxis.getRange().intersects(value1, value0)) {
584: return;
585: }
586: }
587:
588: double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea,
589: plot.getRangeAxisEdge());
590: double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea,
591: plot.getRangeAxisEdge());
592: double bottom = Math.min(translatedValue0, translatedValue1);
593: double top = Math.max(translatedValue0, translatedValue1);
594:
595: double startX = intervalDataset.getStartXValue(series, item);
596: if (Double.isNaN(startX)) {
597: return;
598: }
599: double endX = intervalDataset.getEndXValue(series, item);
600: if (Double.isNaN(endX)) {
601: return;
602: }
603: if (startX <= endX) {
604: if (!domainAxis.getRange().intersects(startX, endX)) {
605: return;
606: }
607: }
608: else {
609: if (!domainAxis.getRange().intersects(endX, startX)) {
610: return;
611: }
612: }
613:
614: RectangleEdge location = plot.getDomainAxisEdge();
615: double translatedStartX = domainAxis.valueToJava2D(startX, dataArea,
616: location);
617: double translatedEndX = domainAxis.valueToJava2D(endX, dataArea,
618: location);
619:
620: double translatedWidth = Math.max(1, Math.abs(translatedEndX
621: - translatedStartX));
622:
623: if (getMargin() > 0.0) {
624: double cut = translatedWidth * getMargin();
625: translatedWidth = translatedWidth - cut;
626: translatedStartX = translatedStartX + cut / 2;
627: }
628:
629: Rectangle2D bar = null;
630: PlotOrientation orientation = plot.getOrientation();
631: if (orientation == PlotOrientation.HORIZONTAL) {
632:
633: bottom = Math.max(bottom, dataArea.getMinX());
634: top = Math.min(top, dataArea.getMaxX());
635: bar = new Rectangle2D.Double(
636: bottom,
637: Math.min(translatedStartX, translatedEndX),
638: top - bottom, translatedWidth);
639: }
640: else if (orientation == PlotOrientation.VERTICAL) {
641:
642: bottom = Math.max(bottom, dataArea.getMinY());
643: top = Math.min(top, dataArea.getMaxY());
644: bar = new Rectangle2D.Double(
645: Math.min(translatedStartX, translatedEndX),
646: bottom,
647: translatedWidth, top - bottom);
648: }
649:
650: Paint itemPaint = getItemPaint(series, item);
651: if (getGradientPaintTransformer()
652: != null && itemPaint instanceof GradientPaint) {
653: GradientPaint gp = (GradientPaint) itemPaint;
654: itemPaint = getGradientPaintTransformer().transform(gp, bar);
655: }
656: g2.setPaint(itemPaint);
657: g2.fill(bar);
658: if (isDrawBarOutline()
659: && Math.abs(translatedEndX - translatedStartX) > 3) {
660: Stroke stroke = getItemOutlineStroke(series, item);
661: Paint paint = getItemOutlinePaint(series, item);
662: if (stroke != null && paint != null) {
663: g2.setStroke(stroke);
664: g2.setPaint(paint);
665: g2.draw(bar);
666: }
667: }
668:
669: if (isItemLabelVisible(series, item)) {
670: XYItemLabelGenerator generator = getItemLabelGenerator(series,
671: item);
672: drawItemLabel(g2, dataset, series, item, plot, generator, bar,
673: value1 < 0.0);
674: }
675:
676:
677: double x1 = (startX + endX) / 2.0;
678: double y1 = dataset.getYValue(series, item);
679: double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
680: double transY1 = rangeAxis.valueToJava2D(y1, dataArea,
681: plot.getRangeAxisEdge());
682: int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
683: int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
684: updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex,
685: rangeAxisIndex, transX1, transY1, plot.getOrientation());
686:
687:
688: if (info != null) {
689: EntityCollection entities = info.getOwner().getEntityCollection();
690: if (entities != null) {
691: String tip = null;
692: XYToolTipGenerator generator = getToolTipGenerator(series,
693: item);
694: if (generator != null) {
695: tip = generator.generateToolTip(dataset, series, item);
696: }
697: String url = null;
698: if (getURLGenerator() != null) {
699: url = getURLGenerator().generateURL(dataset, series, item);
700: }
701: XYItemEntity entity = new XYItemEntity(bar, dataset, series,
702: item, tip, url);
703: entities.add(entity);
704: }
705: }
706:
707: }
708:
709:
722: protected void drawItemLabel(Graphics2D g2, XYDataset dataset,
723: int series, int item, XYPlot plot, XYItemLabelGenerator generator,
724: Rectangle2D bar, boolean negative) {
725:
726: String label = generator.generateLabel(dataset, series, item);
727: if (label == null) {
728: return;
729: }
730:
731: Font labelFont = getItemLabelFont(series, item);
732: g2.setFont(labelFont);
733: Paint paint = getItemLabelPaint(series, item);
734: g2.setPaint(paint);
735:
736:
737: ItemLabelPosition position = null;
738: if (!negative) {
739: position = getPositiveItemLabelPosition(series, item);
740: }
741: else {
742: position = getNegativeItemLabelPosition(series, item);
743: }
744:
745:
746: Point2D anchorPoint = calculateLabelAnchorPoint(
747: position.getItemLabelAnchor(), bar, plot.getOrientation());
748:
749: if (isInternalAnchor(position.getItemLabelAnchor())) {
750: Shape bounds = TextUtilities.calculateRotatedStringBounds(label,
751: g2, (float) anchorPoint.getX(), (float) anchorPoint.getY(),
752: position.getTextAnchor(), position.getAngle(),
753: position.getRotationAnchor());
754:
755: if (bounds != null) {
756: if (!bar.contains(bounds.getBounds2D())) {
757: if (!negative) {
758: position = getPositiveItemLabelPositionFallback();
759: }
760: else {
761: position = getNegativeItemLabelPositionFallback();
762: }
763: if (position != null) {
764: anchorPoint = calculateLabelAnchorPoint(
765: position.getItemLabelAnchor(), bar,
766: plot.getOrientation());
767: }
768: }
769: }
770:
771: }
772:
773: if (position != null) {
774: TextUtilities.drawRotatedString(label, g2,
775: (float) anchorPoint.getX(), (float) anchorPoint.getY(),
776: position.getTextAnchor(), position.getAngle(),
777: position.getRotationAnchor());
778: }
779: }
780:
781:
790: private Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor,
791: Rectangle2D bar, PlotOrientation orientation) {
792:
793: Point2D result = null;
794: double offset = getItemLabelAnchorOffset();
795: double x0 = bar.getX() - offset;
796: double x1 = bar.getX();
797: double x2 = bar.getX() + offset;
798: double x3 = bar.getCenterX();
799: double x4 = bar.getMaxX() - offset;
800: double x5 = bar.getMaxX();
801: double x6 = bar.getMaxX() + offset;
802:
803: double y0 = bar.getMaxY() + offset;
804: double y1 = bar.getMaxY();
805: double y2 = bar.getMaxY() - offset;
806: double y3 = bar.getCenterY();
807: double y4 = bar.getMinY() + offset;
808: double y5 = bar.getMinY();
809: double y6 = bar.getMinY() - offset;
810:
811: if (anchor == ItemLabelAnchor.CENTER) {
812: result = new Point2D.Double(x3, y3);
813: }
814: else if (anchor == ItemLabelAnchor.INSIDE1) {
815: result = new Point2D.Double(x4, y4);
816: }
817: else if (anchor == ItemLabelAnchor.INSIDE2) {
818: result = new Point2D.Double(x4, y4);
819: }
820: else if (anchor == ItemLabelAnchor.INSIDE3) {
821: result = new Point2D.Double(x4, y3);
822: }
823: else if (anchor == ItemLabelAnchor.INSIDE4) {
824: result = new Point2D.Double(x4, y2);
825: }
826: else if (anchor == ItemLabelAnchor.INSIDE5) {
827: result = new Point2D.Double(x4, y2);
828: }
829: else if (anchor == ItemLabelAnchor.INSIDE6) {
830: result = new Point2D.Double(x3, y2);
831: }
832: else if (anchor == ItemLabelAnchor.INSIDE7) {
833: result = new Point2D.Double(x2, y2);
834: }
835: else if (anchor == ItemLabelAnchor.INSIDE8) {
836: result = new Point2D.Double(x2, y2);
837: }
838: else if (anchor == ItemLabelAnchor.INSIDE9) {
839: result = new Point2D.Double(x2, y3);
840: }
841: else if (anchor == ItemLabelAnchor.INSIDE10) {
842: result = new Point2D.Double(x2, y4);
843: }
844: else if (anchor == ItemLabelAnchor.INSIDE11) {
845: result = new Point2D.Double(x2, y4);
846: }
847: else if (anchor == ItemLabelAnchor.INSIDE12) {
848: result = new Point2D.Double(x3, y4);
849: }
850: else if (anchor == ItemLabelAnchor.OUTSIDE1) {
851: result = new Point2D.Double(x5, y6);
852: }
853: else if (anchor == ItemLabelAnchor.OUTSIDE2) {
854: result = new Point2D.Double(x6, y5);
855: }
856: else if (anchor == ItemLabelAnchor.OUTSIDE3) {
857: result = new Point2D.Double(x6, y3);
858: }
859: else if (anchor == ItemLabelAnchor.OUTSIDE4) {
860: result = new Point2D.Double(x6, y1);
861: }
862: else if (anchor == ItemLabelAnchor.OUTSIDE5) {
863: result = new Point2D.Double(x5, y0);
864: }
865: else if (anchor == ItemLabelAnchor.OUTSIDE6) {
866: result = new Point2D.Double(x3, y0);
867: }
868: else if (anchor == ItemLabelAnchor.OUTSIDE7) {
869: result = new Point2D.Double(x1, y0);
870: }
871: else if (anchor == ItemLabelAnchor.OUTSIDE8) {
872: result = new Point2D.Double(x0, y1);
873: }
874: else if (anchor == ItemLabelAnchor.OUTSIDE9) {
875: result = new Point2D.Double(x0, y3);
876: }
877: else if (anchor == ItemLabelAnchor.OUTSIDE10) {
878: result = new Point2D.Double(x0, y5);
879: }
880: else if (anchor == ItemLabelAnchor.OUTSIDE11) {
881: result = new Point2D.Double(x1, y6);
882: }
883: else if (anchor == ItemLabelAnchor.OUTSIDE12) {
884: result = new Point2D.Double(x3, y6);
885: }
886:
887: return result;
888:
889: }
890:
891:
898: private boolean isInternalAnchor(ItemLabelAnchor anchor) {
899: return anchor == ItemLabelAnchor.CENTER
900: || anchor == ItemLabelAnchor.INSIDE1
901: || anchor == ItemLabelAnchor.INSIDE2
902: || anchor == ItemLabelAnchor.INSIDE3
903: || anchor == ItemLabelAnchor.INSIDE4
904: || anchor == ItemLabelAnchor.INSIDE5
905: || anchor == ItemLabelAnchor.INSIDE6
906: || anchor == ItemLabelAnchor.INSIDE7
907: || anchor == ItemLabelAnchor.INSIDE8
908: || anchor == ItemLabelAnchor.INSIDE9
909: || anchor == ItemLabelAnchor.INSIDE10
910: || anchor == ItemLabelAnchor.INSIDE11
911: || anchor == ItemLabelAnchor.INSIDE12;
912: }
913:
914:
924: public Range findDomainBounds(XYDataset dataset) {
925: if (dataset != null) {
926: return DatasetUtilities.findDomainBounds(dataset, true);
927: }
928: else {
929: return null;
930: }
931: }
932:
933:
940: public Object clone() throws CloneNotSupportedException {
941: XYBarRenderer result = (XYBarRenderer) super.clone();
942: if (this.gradientPaintTransformer != null) {
943: result.gradientPaintTransformer = (GradientPaintTransformer)
944: ObjectUtilities.clone(this.gradientPaintTransformer);
945: }
946: result.legendBar = ShapeUtilities.clone(this.legendBar);
947: return result;
948: }
949:
950:
957: public boolean equals(Object obj) {
958: if (obj == this) {
959: return true;
960: }
961: if (!(obj instanceof XYBarRenderer)) {
962: return false;
963: }
964: if (!super.equals(obj)) {
965: return false;
966: }
967: XYBarRenderer that = (XYBarRenderer) obj;
968: if (this.base != that.base) {
969: return false;
970: }
971: if (this.drawBarOutline != that.drawBarOutline) {
972: return false;
973: }
974: if (this.margin != that.margin) {
975: return false;
976: }
977: if (this.useYInterval != that.useYInterval) {
978: return false;
979: }
980: if (!ObjectUtilities.equal(
981: this.gradientPaintTransformer, that.gradientPaintTransformer)
982: ) {
983: return false;
984: }
985: if (!ShapeUtilities.equal(this.legendBar, that.legendBar)) {
986: return false;
987: }
988: if (!ObjectUtilities.equal(this.positiveItemLabelPositionFallback,
989: that.positiveItemLabelPositionFallback)) {
990: return false;
991: }
992: if (!ObjectUtilities.equal(this.negativeItemLabelPositionFallback,
993: that.negativeItemLabelPositionFallback)) {
994: return false;
995: }
996: return true;
997: }
998:
999:
1007: private void readObject(ObjectInputStream stream)
1008: throws IOException, ClassNotFoundException {
1009: stream.defaultReadObject();
1010: this.legendBar = SerialUtilities.readShape(stream);
1011: }
1012:
1013:
1020: private void writeObject(ObjectOutputStream stream) throws IOException {
1021: stream.defaultWriteObject();
1022: SerialUtilities.writeShape(this.legendBar, stream);
1023: }
1024:
1025: }