1:
79:
80: package ;
81:
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: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121:
122:
126: public class XYBarRenderer extends AbstractXYItemRenderer
127: implements XYItemRenderer, Cloneable, PublicCloneable, Serializable {
128:
129:
130: private static final long serialVersionUID = 770559577251370036L;
131:
132:
135: protected class XYBarRendererState extends XYItemRendererState {
136:
137:
138: private double g2Base;
139:
140:
145: public XYBarRendererState(PlotRenderingInfo info) {
146: super(info);
147: }
148:
149:
154: public double getG2Base() {
155: return this.g2Base;
156: }
157:
158:
163: public void setG2Base(double value) {
164: this.g2Base = value;
165: }
166: }
167:
168:
169: private double base;
170:
171:
175: private boolean useYInterval;
176:
177:
178: private double margin;
179:
180:
181: private boolean drawBarOutline;
182:
183:
187: private GradientPaintTransformer gradientPaintTransformer;
188:
189:
193: private transient Shape legendBar;
194:
195:
199: private ItemLabelPosition positiveItemLabelPositionFallback;
200:
201:
205: private ItemLabelPosition negativeItemLabelPositionFallback;
206:
207:
210: public XYBarRenderer() {
211: this(0.0);
212: }
213:
214:
219: public XYBarRenderer(double margin) {
220: super();
221: this.margin = margin;
222: this.base = 0.0;
223: this.useYInterval = false;
224: this.gradientPaintTransformer = new StandardGradientPaintTransformer();
225: this.drawBarOutline = true;
226: this.legendBar = new Rectangle2D.Double(-3.0, -5.0, 6.0, 10.0);
227: }
228:
229:
234: public double getBase() {
235: return this.base;
236: }
237:
238:
245: public void setBase(double base) {
246: this.base = base;
247: notifyListeners(new RendererChangeEvent(this));
248: }
249:
250:
256: public boolean getUseYInterval() {
257: return this.useYInterval;
258: }
259:
260:
267: public void setUseYInterval(boolean use) {
268: this.useYInterval = use;
269: notifyListeners(new RendererChangeEvent(this));
270: }
271:
272:
278: public double getMargin() {
279: return this.margin;
280: }
281:
282:
288: public void setMargin(double margin) {
289: this.margin = margin;
290: notifyListeners(new RendererChangeEvent(this));
291: }
292:
293:
298: public boolean isDrawBarOutline() {
299: return this.drawBarOutline;
300: }
301:
302:
308: public void setDrawBarOutline(boolean draw) {
309: this.drawBarOutline = draw;
310: notifyListeners(new RendererChangeEvent(this));
311: }
312:
313:
319: public GradientPaintTransformer getGradientPaintTransformer() {
320: return this.gradientPaintTransformer;
321: }
322:
323:
329: public void setGradientPaintTransformer(
330: GradientPaintTransformer transformer) {
331: this.gradientPaintTransformer = transformer;
332: notifyListeners(new RendererChangeEvent(this));
333: }
334:
335:
341: public Shape getLegendBar() {
342: return this.legendBar;
343: }
344:
345:
350: public void setLegendBar(Shape bar) {
351: if (bar == null) {
352: throw new IllegalArgumentException("Null 'bar' argument.");
353: }
354: this.legendBar = bar;
355: notifyListeners(new RendererChangeEvent(this));
356: }
357:
358:
366: public ItemLabelPosition getPositiveItemLabelPositionFallback() {
367: return this.positiveItemLabelPositionFallback;
368: }
369:
370:
379: public void setPositiveItemLabelPositionFallback(
380: ItemLabelPosition position) {
381: this.positiveItemLabelPositionFallback = position;
382: notifyListeners(new RendererChangeEvent(this));
383: }
384:
385:
393: public ItemLabelPosition getNegativeItemLabelPositionFallback() {
394: return this.negativeItemLabelPositionFallback;
395: }
396:
397:
406: public void setNegativeItemLabelPositionFallback(
407: ItemLabelPosition position) {
408: this.negativeItemLabelPositionFallback = position;
409: notifyListeners(new RendererChangeEvent(this));
410: }
411:
412:
427: public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea,
428: XYPlot plot, XYDataset dataset, PlotRenderingInfo info) {
429:
430: XYBarRendererState state = new XYBarRendererState(info);
431: ValueAxis rangeAxis
432: = plot.getRangeAxisForDataset(plot.indexOf(dataset));
433: state.setG2Base(rangeAxis.valueToJava2D(this.base, dataArea,
434: plot.getRangeAxisEdge()));
435: return state;
436:
437: }
438:
439:
448: public LegendItem getLegendItem(int datasetIndex, int series) {
449: LegendItem result = null;
450: XYPlot xyplot = getPlot();
451: if (xyplot != null) {
452: XYDataset dataset = xyplot.getDataset(datasetIndex);
453: if (dataset != null) {
454: XYSeriesLabelGenerator lg = getLegendItemLabelGenerator();
455: String label = lg.generateLabel(dataset, series);
456: String description = label;
457: String toolTipText = null;
458: if (getLegendItemToolTipGenerator() != null) {
459: toolTipText = getLegendItemToolTipGenerator().generateLabel(
460: dataset, series);
461: }
462: String urlText = null;
463: if (getLegendItemURLGenerator() != null) {
464: urlText = getLegendItemURLGenerator().generateLabel(
465: dataset, series);
466: }
467: Shape shape = this.legendBar;
468: Paint paint = getSeriesPaint(series);
469: Paint outlinePaint = getSeriesOutlinePaint(series);
470: Stroke outlineStroke = getSeriesOutlineStroke(series);
471: result = new LegendItem(label, description, toolTipText,
472: urlText, shape, paint, outlineStroke, outlinePaint);
473: }
474: }
475: return result;
476: }
477:
478:
496: public void drawItem(Graphics2D g2,
497: XYItemRendererState state,
498: Rectangle2D dataArea,
499: PlotRenderingInfo info,
500: XYPlot plot,
501: ValueAxis domainAxis,
502: ValueAxis rangeAxis,
503: XYDataset dataset,
504: int series,
505: int item,
506: CrosshairState crosshairState,
507: int pass) {
508:
509: if (!getItemVisible(series, item)) {
510: return;
511: }
512: IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
513:
514: double value0;
515: double value1;
516: if (this.useYInterval) {
517: value0 = intervalDataset.getStartYValue(series, item);
518: value1 = intervalDataset.getEndYValue(series, item);
519: }
520: else {
521: value0 = this.base;
522: value1 = intervalDataset.getYValue(series, item);
523: }
524: if (Double.isNaN(value0) || Double.isNaN(value1)) {
525: return;
526: }
527:
528: double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea,
529: plot.getRangeAxisEdge());
530: double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea,
531: plot.getRangeAxisEdge());
532:
533: RectangleEdge location = plot.getDomainAxisEdge();
534: double startX = intervalDataset.getStartXValue(series, item);
535: if (Double.isNaN(startX)) {
536: return;
537: }
538: double translatedStartX = domainAxis.valueToJava2D(startX, dataArea,
539: location);
540:
541: double endX = intervalDataset.getEndXValue(series, item);
542: if (Double.isNaN(endX)) {
543: return;
544: }
545: double translatedEndX = domainAxis.valueToJava2D(endX, dataArea,
546: location);
547:
548: double translatedWidth = Math.max(1, Math.abs(translatedEndX
549: - translatedStartX));
550: double translatedHeight = Math.abs(translatedValue1 - translatedValue0);
551:
552: if (getMargin() > 0.0) {
553: double cut = translatedWidth * getMargin();
554: translatedWidth = translatedWidth - cut;
555: translatedStartX = translatedStartX + cut / 2;
556: }
557:
558: Rectangle2D bar = null;
559: PlotOrientation orientation = plot.getOrientation();
560: if (orientation == PlotOrientation.HORIZONTAL) {
561: bar = new Rectangle2D.Double(
562: Math.min(translatedValue0, translatedValue1),
563: Math.min(translatedStartX, translatedEndX),
564: translatedHeight, translatedWidth);
565: }
566: else if (orientation == PlotOrientation.VERTICAL) {
567: bar = new Rectangle2D.Double(
568: Math.min(translatedStartX, translatedEndX),
569: Math.min(translatedValue0, translatedValue1),
570: translatedWidth, translatedHeight);
571: }
572:
573: Paint itemPaint = getItemPaint(series, item);
574: if (getGradientPaintTransformer()
575: != null && itemPaint instanceof GradientPaint) {
576: GradientPaint gp = (GradientPaint) itemPaint;
577: itemPaint = getGradientPaintTransformer().transform(gp, bar);
578: }
579: g2.setPaint(itemPaint);
580: g2.fill(bar);
581: if (isDrawBarOutline()
582: && Math.abs(translatedEndX - translatedStartX) > 3) {
583: Stroke stroke = getItemOutlineStroke(series, item);
584: Paint paint = getItemOutlinePaint(series, item);
585: if (stroke != null && paint != null) {
586: g2.setStroke(stroke);
587: g2.setPaint(paint);
588: g2.draw(bar);
589: }
590: }
591:
592: if (isItemLabelVisible(series, item)) {
593: XYItemLabelGenerator generator = getItemLabelGenerator(series,
594: item);
595: drawItemLabel(g2, dataset, series, item, plot, generator, bar,
596: value1 < 0.0);
597: }
598:
599:
600: double x1 = (startX + endX) / 2.0;
601: double y1 = dataset.getYValue(series, item);
602: double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
603: double transY1 = rangeAxis.valueToJava2D(y1, dataArea,
604: plot.getRangeAxisEdge());
605: updateCrosshairValues(crosshairState, x1, y1, transX1, transY1,
606: plot.getOrientation());
607:
608:
609: if (info != null) {
610: EntityCollection entities = info.getOwner().getEntityCollection();
611: if (entities != null) {
612: String tip = null;
613: XYToolTipGenerator generator
614: = getToolTipGenerator(series, item);
615: if (generator != null) {
616: tip = generator.generateToolTip(dataset, series, item);
617: }
618: String url = null;
619: if (getURLGenerator() != null) {
620: url = getURLGenerator().generateURL(dataset, series, item);
621: }
622: XYItemEntity entity = new XYItemEntity(bar, dataset, series,
623: item, tip, url);
624: entities.add(entity);
625: }
626: }
627:
628: }
629:
630:
643: protected void drawItemLabel(Graphics2D g2, XYDataset dataset,
644: int series, int item, XYPlot plot, XYItemLabelGenerator generator,
645: Rectangle2D bar, boolean negative) {
646:
647: String label = generator.generateLabel(dataset, series, item);
648: if (label == null) {
649: return;
650: }
651:
652: Font labelFont = getItemLabelFont(series, item);
653: g2.setFont(labelFont);
654: Paint paint = getItemLabelPaint(series, item);
655: g2.setPaint(paint);
656:
657:
658: ItemLabelPosition position = null;
659: if (!negative) {
660: position = getPositiveItemLabelPosition(series, item);
661: }
662: else {
663: position = getNegativeItemLabelPosition(series, item);
664: }
665:
666:
667: Point2D anchorPoint = calculateLabelAnchorPoint(
668: position.getItemLabelAnchor(), bar, plot.getOrientation());
669:
670: if (isInternalAnchor(position.getItemLabelAnchor())) {
671: Shape bounds = TextUtilities.calculateRotatedStringBounds(label,
672: g2, (float) anchorPoint.getX(), (float) anchorPoint.getY(),
673: position.getTextAnchor(), position.getAngle(),
674: position.getRotationAnchor());
675:
676: if (bounds != null) {
677: if (!bar.contains(bounds.getBounds2D())) {
678: if (!negative) {
679: position = getPositiveItemLabelPositionFallback();
680: }
681: else {
682: position = getNegativeItemLabelPositionFallback();
683: }
684: if (position != null) {
685: anchorPoint = calculateLabelAnchorPoint(
686: position.getItemLabelAnchor(), bar,
687: plot.getOrientation());
688: }
689: }
690: }
691:
692: }
693:
694: if (position != null) {
695: TextUtilities.drawRotatedString(label, g2,
696: (float) anchorPoint.getX(), (float) anchorPoint.getY(),
697: position.getTextAnchor(), position.getAngle(),
698: position.getRotationAnchor());
699: }
700: }
701:
702:
711: private Point2D calculateLabelAnchorPoint(ItemLabelAnchor anchor,
712: Rectangle2D bar, PlotOrientation orientation) {
713:
714: Point2D result = null;
715: double offset = getItemLabelAnchorOffset();
716: double x0 = bar.getX() - offset;
717: double x1 = bar.getX();
718: double x2 = bar.getX() + offset;
719: double x3 = bar.getCenterX();
720: double x4 = bar.getMaxX() - offset;
721: double x5 = bar.getMaxX();
722: double x6 = bar.getMaxX() + offset;
723:
724: double y0 = bar.getMaxY() + offset;
725: double y1 = bar.getMaxY();
726: double y2 = bar.getMaxY() - offset;
727: double y3 = bar.getCenterY();
728: double y4 = bar.getMinY() + offset;
729: double y5 = bar.getMinY();
730: double y6 = bar.getMinY() - offset;
731:
732: if (anchor == ItemLabelAnchor.CENTER) {
733: result = new Point2D.Double(x3, y3);
734: }
735: else if (anchor == ItemLabelAnchor.INSIDE1) {
736: result = new Point2D.Double(x4, y4);
737: }
738: else if (anchor == ItemLabelAnchor.INSIDE2) {
739: result = new Point2D.Double(x4, y4);
740: }
741: else if (anchor == ItemLabelAnchor.INSIDE3) {
742: result = new Point2D.Double(x4, y3);
743: }
744: else if (anchor == ItemLabelAnchor.INSIDE4) {
745: result = new Point2D.Double(x4, y2);
746: }
747: else if (anchor == ItemLabelAnchor.INSIDE5) {
748: result = new Point2D.Double(x4, y2);
749: }
750: else if (anchor == ItemLabelAnchor.INSIDE6) {
751: result = new Point2D.Double(x3, y2);
752: }
753: else if (anchor == ItemLabelAnchor.INSIDE7) {
754: result = new Point2D.Double(x2, y2);
755: }
756: else if (anchor == ItemLabelAnchor.INSIDE8) {
757: result = new Point2D.Double(x2, y2);
758: }
759: else if (anchor == ItemLabelAnchor.INSIDE9) {
760: result = new Point2D.Double(x2, y3);
761: }
762: else if (anchor == ItemLabelAnchor.INSIDE10) {
763: result = new Point2D.Double(x2, y4);
764: }
765: else if (anchor == ItemLabelAnchor.INSIDE11) {
766: result = new Point2D.Double(x2, y4);
767: }
768: else if (anchor == ItemLabelAnchor.INSIDE12) {
769: result = new Point2D.Double(x3, y4);
770: }
771: else if (anchor == ItemLabelAnchor.OUTSIDE1) {
772: result = new Point2D.Double(x5, y6);
773: }
774: else if (anchor == ItemLabelAnchor.OUTSIDE2) {
775: result = new Point2D.Double(x6, y5);
776: }
777: else if (anchor == ItemLabelAnchor.OUTSIDE3) {
778: result = new Point2D.Double(x6, y3);
779: }
780: else if (anchor == ItemLabelAnchor.OUTSIDE4) {
781: result = new Point2D.Double(x6, y1);
782: }
783: else if (anchor == ItemLabelAnchor.OUTSIDE5) {
784: result = new Point2D.Double(x5, y0);
785: }
786: else if (anchor == ItemLabelAnchor.OUTSIDE6) {
787: result = new Point2D.Double(x3, y0);
788: }
789: else if (anchor == ItemLabelAnchor.OUTSIDE7) {
790: result = new Point2D.Double(x1, y0);
791: }
792: else if (anchor == ItemLabelAnchor.OUTSIDE8) {
793: result = new Point2D.Double(x0, y1);
794: }
795: else if (anchor == ItemLabelAnchor.OUTSIDE9) {
796: result = new Point2D.Double(x0, y3);
797: }
798: else if (anchor == ItemLabelAnchor.OUTSIDE10) {
799: result = new Point2D.Double(x0, y5);
800: }
801: else if (anchor == ItemLabelAnchor.OUTSIDE11) {
802: result = new Point2D.Double(x1, y6);
803: }
804: else if (anchor == ItemLabelAnchor.OUTSIDE12) {
805: result = new Point2D.Double(x3, y6);
806: }
807:
808: return result;
809:
810: }
811:
812:
819: private boolean isInternalAnchor(ItemLabelAnchor anchor) {
820: return anchor == ItemLabelAnchor.CENTER
821: || anchor == ItemLabelAnchor.INSIDE1
822: || anchor == ItemLabelAnchor.INSIDE2
823: || anchor == ItemLabelAnchor.INSIDE3
824: || anchor == ItemLabelAnchor.INSIDE4
825: || anchor == ItemLabelAnchor.INSIDE5
826: || anchor == ItemLabelAnchor.INSIDE6
827: || anchor == ItemLabelAnchor.INSIDE7
828: || anchor == ItemLabelAnchor.INSIDE8
829: || anchor == ItemLabelAnchor.INSIDE9
830: || anchor == ItemLabelAnchor.INSIDE10
831: || anchor == ItemLabelAnchor.INSIDE11
832: || anchor == ItemLabelAnchor.INSIDE12;
833: }
834:
835:
845: public Range findDomainBounds(XYDataset dataset) {
846: if (dataset != null) {
847: return DatasetUtilities.findDomainBounds(dataset, true);
848: }
849: else {
850: return null;
851: }
852: }
853:
854:
861: public Object clone() throws CloneNotSupportedException {
862: XYBarRenderer result = (XYBarRenderer) super.clone();
863: if (this.gradientPaintTransformer != null) {
864: result.gradientPaintTransformer = (GradientPaintTransformer)
865: ObjectUtilities.clone(this.gradientPaintTransformer);
866: }
867: return result;
868: }
869:
870:
877: public boolean equals(Object obj) {
878: if (obj == this) {
879: return true;
880: }
881: if (!(obj instanceof XYBarRenderer)) {
882: return false;
883: }
884: if (!super.equals(obj)) {
885: return false;
886: }
887: XYBarRenderer that = (XYBarRenderer) obj;
888: if (this.base != that.base) {
889: return false;
890: }
891: if (this.drawBarOutline != that.drawBarOutline) {
892: return false;
893: }
894: if (this.margin != that.margin) {
895: return false;
896: }
897: if (this.useYInterval != that.useYInterval) {
898: return false;
899: }
900: if (!ObjectUtilities.equal(
901: this.gradientPaintTransformer, that.gradientPaintTransformer)
902: ) {
903: return false;
904: }
905: if (!ShapeUtilities.equal(this.legendBar, that.legendBar)) {
906: return false;
907: }
908: if (!ObjectUtilities.equal(this.positiveItemLabelPositionFallback,
909: that.positiveItemLabelPositionFallback)) {
910: return false;
911: }
912: if (!ObjectUtilities.equal(this.negativeItemLabelPositionFallback,
913: that.negativeItemLabelPositionFallback)) {
914: return false;
915: }
916: return true;
917: }
918:
919:
927: private void readObject(ObjectInputStream stream)
928: throws IOException, ClassNotFoundException {
929: stream.defaultReadObject();
930: this.legendBar = SerialUtilities.readShape(stream);
931: }
932:
933:
940: private void writeObject(ObjectOutputStream stream) throws IOException {
941: stream.defaultWriteObject();
942: SerialUtilities.writeShape(this.legendBar, stream);
943: }
944:
945: }