1:
92:
93: package ;
94:
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106:
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117:
118:
130: public class NumberAxis extends ValueAxis implements Cloneable, Serializable {
131:
132:
133: private static final long serialVersionUID = 2805933088476185789L;
134:
135:
136: public static final boolean DEFAULT_AUTO_RANGE_INCLUDES_ZERO = true;
137:
138:
139: public static final boolean DEFAULT_AUTO_RANGE_STICKY_ZERO = true;
140:
141:
142: public static final NumberTickUnit
143: DEFAULT_TICK_UNIT = new NumberTickUnit(1.0, new DecimalFormat("0"));
144:
145:
146: public static final boolean DEFAULT_VERTICAL_TICK_LABELS = false;
147:
148:
152: private RangeType rangeType;
153:
154:
159: private boolean autoRangeIncludesZero;
160:
161:
166: private boolean autoRangeStickyZero;
167:
168:
169: private NumberTickUnit tickUnit;
170:
171:
172: private NumberFormat numberFormatOverride;
173:
174:
175: private MarkerAxisBand markerBand;
176:
177:
180: public NumberAxis() {
181: this(null);
182: }
183:
184:
189: public NumberAxis(String label) {
190: super(label, NumberAxis.createStandardTickUnits());
191: this.rangeType = RangeType.FULL;
192: this.autoRangeIncludesZero = DEFAULT_AUTO_RANGE_INCLUDES_ZERO;
193: this.autoRangeStickyZero = DEFAULT_AUTO_RANGE_STICKY_ZERO;
194: this.tickUnit = DEFAULT_TICK_UNIT;
195: this.numberFormatOverride = null;
196: this.markerBand = null;
197: }
198:
199:
204: public RangeType getRangeType() {
205: return this.rangeType;
206: }
207:
208:
213: public void setRangeType(RangeType rangeType) {
214: if (rangeType == null) {
215: throw new IllegalArgumentException("Null 'rangeType' argument.");
216: }
217: this.rangeType = rangeType;
218: notifyListeners(new AxisChangeEvent(this));
219: }
220:
221:
227: public boolean getAutoRangeIncludesZero() {
228: return this.autoRangeIncludesZero;
229: }
230:
231:
242: public void setAutoRangeIncludesZero(boolean flag) {
243: if (this.autoRangeIncludesZero != flag) {
244: this.autoRangeIncludesZero = flag;
245: if (isAutoRange()) {
246: autoAdjustRange();
247: }
248: notifyListeners(new AxisChangeEvent(this));
249: }
250: }
251:
252:
258: public boolean getAutoRangeStickyZero() {
259: return this.autoRangeStickyZero;
260: }
261:
262:
268: public void setAutoRangeStickyZero(boolean flag) {
269: if (this.autoRangeStickyZero != flag) {
270: this.autoRangeStickyZero = flag;
271: if (isAutoRange()) {
272: autoAdjustRange();
273: }
274: notifyListeners(new AxisChangeEvent(this));
275: }
276: }
277:
278:
291: public NumberTickUnit getTickUnit() {
292: return this.tickUnit;
293: }
294:
295:
307: public void setTickUnit(NumberTickUnit unit) {
308:
309: setTickUnit(unit, true, true);
310: }
311:
312:
323: public void setTickUnit(NumberTickUnit unit, boolean notify,
324: boolean turnOffAutoSelect) {
325:
326: if (unit == null) {
327: throw new IllegalArgumentException("Null 'unit' argument.");
328: }
329: this.tickUnit = unit;
330: if (turnOffAutoSelect) {
331: setAutoTickUnitSelection(false, false);
332: }
333: if (notify) {
334: notifyListeners(new AxisChangeEvent(this));
335: }
336:
337: }
338:
339:
345: public NumberFormat getNumberFormatOverride() {
346: return this.numberFormatOverride;
347: }
348:
349:
355: public void setNumberFormatOverride(NumberFormat formatter) {
356: this.numberFormatOverride = formatter;
357: notifyListeners(new AxisChangeEvent(this));
358: }
359:
360:
365: public MarkerAxisBand getMarkerBand() {
366: return this.markerBand;
367: }
368:
369:
377: public void setMarkerBand(MarkerAxisBand band) {
378: this.markerBand = band;
379: notifyListeners(new AxisChangeEvent(this));
380: }
381:
382:
386: public void configure() {
387: if (isAutoRange()) {
388: autoAdjustRange();
389: }
390: }
391:
392:
395: protected void autoAdjustRange() {
396:
397: Plot plot = getPlot();
398: if (plot == null) {
399: return;
400: }
401:
402: if (plot instanceof ValueAxisPlot) {
403: ValueAxisPlot vap = (ValueAxisPlot) plot;
404:
405: Range r = vap.getDataRange(this);
406: if (r == null) {
407: r = new Range(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
408: }
409:
410: double upper = r.getUpperBound();
411: double lower = r.getLowerBound();
412: if (this.rangeType == RangeType.POSITIVE) {
413: lower = Math.max(0.0, lower);
414: upper = Math.max(0.0, upper);
415: }
416: else if (this.rangeType == RangeType.NEGATIVE) {
417: lower = Math.min(0.0, lower);
418: upper = Math.min(0.0, upper);
419: }
420:
421: if (getAutoRangeIncludesZero()) {
422: lower = Math.min(lower, 0.0);
423: upper = Math.max(upper, 0.0);
424: }
425: double range = upper - lower;
426:
427:
428: double fixedAutoRange = getFixedAutoRange();
429: if (fixedAutoRange > 0.0) {
430: lower = upper - fixedAutoRange;
431: }
432: else {
433:
434: double minRange = getAutoRangeMinimumSize();
435: if (range < minRange) {
436: double expand = (minRange - range) / 2;
437: upper = upper + expand;
438: lower = lower - expand;
439: if (this.rangeType == RangeType.POSITIVE) {
440: if (lower < 0.0) {
441: upper = upper - lower;
442: lower = 0.0;
443: }
444: }
445: else if (this.rangeType == RangeType.NEGATIVE) {
446: if (upper > 0.0) {
447: lower = lower - upper;
448: upper = 0.0;
449: }
450: }
451: }
452:
453: if (getAutoRangeStickyZero()) {
454: if (upper <= 0.0) {
455: upper = Math.min(0.0, upper + getUpperMargin() * range);
456: }
457: else {
458: upper = upper + getUpperMargin() * range;
459: }
460: if (lower >= 0.0) {
461: lower = Math.max(0.0, lower - getLowerMargin() * range);
462: }
463: else {
464: lower = lower - getLowerMargin() * range;
465: }
466: }
467: else {
468: upper = upper + getUpperMargin() * range;
469: lower = lower - getLowerMargin() * range;
470: }
471: }
472:
473: setRange(new Range(lower, upper), false, false);
474: }
475:
476: }
477:
478:
490: public double valueToJava2D(double value, Rectangle2D area,
491: RectangleEdge edge) {
492:
493: Range range = getRange();
494: double axisMin = range.getLowerBound();
495: double axisMax = range.getUpperBound();
496:
497: double min = 0.0;
498: double max = 0.0;
499: if (RectangleEdge.isTopOrBottom(edge)) {
500: min = area.getX();
501: max = area.getMaxX();
502: }
503: else if (RectangleEdge.isLeftOrRight(edge)) {
504: max = area.getMinY();
505: min = area.getMaxY();
506: }
507: if (isInverted()) {
508: return max
509: - ((value - axisMin) / (axisMax - axisMin)) * (max - min);
510: }
511: else {
512: return min
513: + ((value - axisMin) / (axisMax - axisMin)) * (max - min);
514: }
515:
516: }
517:
518:
528: public double java2DToValue(double java2DValue, Rectangle2D area,
529: RectangleEdge edge) {
530:
531: Range range = getRange();
532: double axisMin = range.getLowerBound();
533: double axisMax = range.getUpperBound();
534:
535: double min = 0.0;
536: double max = 0.0;
537: if (RectangleEdge.isTopOrBottom(edge)) {
538: min = area.getX();
539: max = area.getMaxX();
540: }
541: else if (RectangleEdge.isLeftOrRight(edge)) {
542: min = area.getMaxY();
543: max = area.getY();
544: }
545: if (isInverted()) {
546: return axisMax
547: - (java2DValue - min) / (max - min) * (axisMax - axisMin);
548: }
549: else {
550: return axisMin
551: + (java2DValue - min) / (max - min) * (axisMax - axisMin);
552: }
553:
554: }
555:
556:
561: protected double calculateLowestVisibleTickValue() {
562:
563: double unit = getTickUnit().getSize();
564: double index = Math.ceil(getRange().getLowerBound() / unit);
565: return index * unit;
566:
567: }
568:
569:
574: protected double calculateHighestVisibleTickValue() {
575:
576: double unit = getTickUnit().getSize();
577: double index = Math.floor(getRange().getUpperBound() / unit);
578: return index * unit;
579:
580: }
581:
582:
587: protected int calculateVisibleTickCount() {
588:
589: double unit = getTickUnit().getSize();
590: Range range = getRange();
591: return (int) (Math.floor(range.getUpperBound() / unit)
592: - Math.ceil(range.getLowerBound() / unit) + 1);
593:
594: }
595:
596:
612: public AxisState draw(Graphics2D g2,
613: double cursor,
614: Rectangle2D plotArea,
615: Rectangle2D dataArea,
616: RectangleEdge edge,
617: PlotRenderingInfo plotState) {
618:
619: AxisState state = null;
620:
621: if (!isVisible()) {
622: state = new AxisState(cursor);
623:
624:
625: List ticks = refreshTicks(g2, state, dataArea, edge);
626: state.setTicks(ticks);
627: return state;
628: }
629:
630:
631: state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge);
632:
633:
634:
635:
636:
637:
638:
639:
640:
641:
642: state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
643:
644: return state;
645:
646: }
647:
648:
657: public static TickUnitSource createStandardTickUnits() {
658:
659: TickUnits units = new TickUnits();
660: DecimalFormat df0 = new DecimalFormat("0.00000000");
661: DecimalFormat df1 = new DecimalFormat("0.0000000");
662: DecimalFormat df2 = new DecimalFormat("0.000000");
663: DecimalFormat df3 = new DecimalFormat("0.00000");
664: DecimalFormat df4 = new DecimalFormat("0.0000");
665: DecimalFormat df5 = new DecimalFormat("0.000");
666: DecimalFormat df6 = new DecimalFormat("0.00");
667: DecimalFormat df7 = new DecimalFormat("0.0");
668: DecimalFormat df8 = new DecimalFormat("#,##0");
669: DecimalFormat df9 = new DecimalFormat("#,###,##0");
670: DecimalFormat df10 = new DecimalFormat("#,###,###,##0");
671:
672:
673:
674: units.add(new NumberTickUnit(0.0000001, df1));
675: units.add(new NumberTickUnit(0.000001, df2));
676: units.add(new NumberTickUnit(0.00001, df3));
677: units.add(new NumberTickUnit(0.0001, df4));
678: units.add(new NumberTickUnit(0.001, df5));
679: units.add(new NumberTickUnit(0.01, df6));
680: units.add(new NumberTickUnit(0.1, df7));
681: units.add(new NumberTickUnit(1, df8));
682: units.add(new NumberTickUnit(10, df8));
683: units.add(new NumberTickUnit(100, df8));
684: units.add(new NumberTickUnit(1000, df8));
685: units.add(new NumberTickUnit(10000, df8));
686: units.add(new NumberTickUnit(100000, df8));
687: units.add(new NumberTickUnit(1000000, df9));
688: units.add(new NumberTickUnit(10000000, df9));
689: units.add(new NumberTickUnit(100000000, df9));
690: units.add(new NumberTickUnit(1000000000, df10));
691: units.add(new NumberTickUnit(10000000000.0, df10));
692: units.add(new NumberTickUnit(100000000000.0, df10));
693:
694: units.add(new NumberTickUnit(0.00000025, df0));
695: units.add(new NumberTickUnit(0.0000025, df1));
696: units.add(new NumberTickUnit(0.000025, df2));
697: units.add(new NumberTickUnit(0.00025, df3));
698: units.add(new NumberTickUnit(0.0025, df4));
699: units.add(new NumberTickUnit(0.025, df5));
700: units.add(new NumberTickUnit(0.25, df6));
701: units.add(new NumberTickUnit(2.5, df7));
702: units.add(new NumberTickUnit(25, df8));
703: units.add(new NumberTickUnit(250, df8));
704: units.add(new NumberTickUnit(2500, df8));
705: units.add(new NumberTickUnit(25000, df8));
706: units.add(new NumberTickUnit(250000, df8));
707: units.add(new NumberTickUnit(2500000, df9));
708: units.add(new NumberTickUnit(25000000, df9));
709: units.add(new NumberTickUnit(250000000, df9));
710: units.add(new NumberTickUnit(2500000000.0, df10));
711: units.add(new NumberTickUnit(25000000000.0, df10));
712: units.add(new NumberTickUnit(250000000000.0, df10));
713:
714: units.add(new NumberTickUnit(0.0000005, df1));
715: units.add(new NumberTickUnit(0.000005, df2));
716: units.add(new NumberTickUnit(0.00005, df3));
717: units.add(new NumberTickUnit(0.0005, df4));
718: units.add(new NumberTickUnit(0.005, df5));
719: units.add(new NumberTickUnit(0.05, df6));
720: units.add(new NumberTickUnit(0.5, df7));
721: units.add(new NumberTickUnit(5L, df8));
722: units.add(new NumberTickUnit(50L, df8));
723: units.add(new NumberTickUnit(500L, df8));
724: units.add(new NumberTickUnit(5000L, df8));
725: units.add(new NumberTickUnit(50000L, df8));
726: units.add(new NumberTickUnit(500000L, df8));
727: units.add(new NumberTickUnit(5000000L, df9));
728: units.add(new NumberTickUnit(50000000L, df9));
729: units.add(new NumberTickUnit(500000000L, df9));
730: units.add(new NumberTickUnit(5000000000L, df10));
731: units.add(new NumberTickUnit(50000000000L, df10));
732: units.add(new NumberTickUnit(500000000000L, df10));
733:
734: return units;
735:
736: }
737:
738:
743: public static TickUnitSource createIntegerTickUnits() {
744:
745: TickUnits units = new TickUnits();
746: DecimalFormat df0 = new DecimalFormat("0");
747: DecimalFormat df1 = new DecimalFormat("#,##0");
748: units.add(new NumberTickUnit(1, df0));
749: units.add(new NumberTickUnit(2, df0));
750: units.add(new NumberTickUnit(5, df0));
751: units.add(new NumberTickUnit(10, df0));
752: units.add(new NumberTickUnit(20, df0));
753: units.add(new NumberTickUnit(50, df0));
754: units.add(new NumberTickUnit(100, df0));
755: units.add(new NumberTickUnit(200, df0));
756: units.add(new NumberTickUnit(500, df0));
757: units.add(new NumberTickUnit(1000, df1));
758: units.add(new NumberTickUnit(2000, df1));
759: units.add(new NumberTickUnit(5000, df1));
760: units.add(new NumberTickUnit(10000, df1));
761: units.add(new NumberTickUnit(20000, df1));
762: units.add(new NumberTickUnit(50000, df1));
763: units.add(new NumberTickUnit(100000, df1));
764: units.add(new NumberTickUnit(200000, df1));
765: units.add(new NumberTickUnit(500000, df1));
766: units.add(new NumberTickUnit(1000000, df1));
767: units.add(new NumberTickUnit(2000000, df1));
768: units.add(new NumberTickUnit(5000000, df1));
769: units.add(new NumberTickUnit(10000000, df1));
770: units.add(new NumberTickUnit(20000000, df1));
771: units.add(new NumberTickUnit(50000000, df1));
772: units.add(new NumberTickUnit(100000000, df1));
773: units.add(new NumberTickUnit(200000000, df1));
774: units.add(new NumberTickUnit(500000000, df1));
775: units.add(new NumberTickUnit(1000000000, df1));
776: units.add(new NumberTickUnit(2000000000, df1));
777: units.add(new NumberTickUnit(5000000000.0, df1));
778: units.add(new NumberTickUnit(10000000000.0, df1));
779:
780: return units;
781:
782: }
783:
784:
797: public static TickUnitSource createStandardTickUnits(Locale locale) {
798:
799: TickUnits units = new TickUnits();
800:
801: NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
802:
803:
804:
805: units.add(new NumberTickUnit(0.0000001, numberFormat));
806: units.add(new NumberTickUnit(0.000001, numberFormat));
807: units.add(new NumberTickUnit(0.00001, numberFormat));
808: units.add(new NumberTickUnit(0.0001, numberFormat));
809: units.add(new NumberTickUnit(0.001, numberFormat));
810: units.add(new NumberTickUnit(0.01, numberFormat));
811: units.add(new NumberTickUnit(0.1, numberFormat));
812: units.add(new NumberTickUnit(1, numberFormat));
813: units.add(new NumberTickUnit(10, numberFormat));
814: units.add(new NumberTickUnit(100, numberFormat));
815: units.add(new NumberTickUnit(1000, numberFormat));
816: units.add(new NumberTickUnit(10000, numberFormat));
817: units.add(new NumberTickUnit(100000, numberFormat));
818: units.add(new NumberTickUnit(1000000, numberFormat));
819: units.add(new NumberTickUnit(10000000, numberFormat));
820: units.add(new NumberTickUnit(100000000, numberFormat));
821: units.add(new NumberTickUnit(1000000000, numberFormat));
822: units.add(new NumberTickUnit(10000000000.0, numberFormat));
823:
824: units.add(new NumberTickUnit(0.00000025, numberFormat));
825: units.add(new NumberTickUnit(0.0000025, numberFormat));
826: units.add(new NumberTickUnit(0.000025, numberFormat));
827: units.add(new NumberTickUnit(0.00025, numberFormat));
828: units.add(new NumberTickUnit(0.0025, numberFormat));
829: units.add(new NumberTickUnit(0.025, numberFormat));
830: units.add(new NumberTickUnit(0.25, numberFormat));
831: units.add(new NumberTickUnit(2.5, numberFormat));
832: units.add(new NumberTickUnit(25, numberFormat));
833: units.add(new NumberTickUnit(250, numberFormat));
834: units.add(new NumberTickUnit(2500, numberFormat));
835: units.add(new NumberTickUnit(25000, numberFormat));
836: units.add(new NumberTickUnit(250000, numberFormat));
837: units.add(new NumberTickUnit(2500000, numberFormat));
838: units.add(new NumberTickUnit(25000000, numberFormat));
839: units.add(new NumberTickUnit(250000000, numberFormat));
840: units.add(new NumberTickUnit(2500000000.0, numberFormat));
841: units.add(new NumberTickUnit(25000000000.0, numberFormat));
842:
843: units.add(new NumberTickUnit(0.0000005, numberFormat));
844: units.add(new NumberTickUnit(0.000005, numberFormat));
845: units.add(new NumberTickUnit(0.00005, numberFormat));
846: units.add(new NumberTickUnit(0.0005, numberFormat));
847: units.add(new NumberTickUnit(0.005, numberFormat));
848: units.add(new NumberTickUnit(0.05, numberFormat));
849: units.add(new NumberTickUnit(0.5, numberFormat));
850: units.add(new NumberTickUnit(5L, numberFormat));
851: units.add(new NumberTickUnit(50L, numberFormat));
852: units.add(new NumberTickUnit(500L, numberFormat));
853: units.add(new NumberTickUnit(5000L, numberFormat));
854: units.add(new NumberTickUnit(50000L, numberFormat));
855: units.add(new NumberTickUnit(500000L, numberFormat));
856: units.add(new NumberTickUnit(5000000L, numberFormat));
857: units.add(new NumberTickUnit(50000000L, numberFormat));
858: units.add(new NumberTickUnit(500000000L, numberFormat));
859: units.add(new NumberTickUnit(5000000000L, numberFormat));
860: units.add(new NumberTickUnit(50000000000L, numberFormat));
861:
862: return units;
863:
864: }
865:
866:
874: public static TickUnitSource createIntegerTickUnits(Locale locale) {
875:
876: TickUnits units = new TickUnits();
877:
878: NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
879:
880: units.add(new NumberTickUnit(1, numberFormat));
881: units.add(new NumberTickUnit(2, numberFormat));
882: units.add(new NumberTickUnit(5, numberFormat));
883: units.add(new NumberTickUnit(10, numberFormat));
884: units.add(new NumberTickUnit(20, numberFormat));
885: units.add(new NumberTickUnit(50, numberFormat));
886: units.add(new NumberTickUnit(100, numberFormat));
887: units.add(new NumberTickUnit(200, numberFormat));
888: units.add(new NumberTickUnit(500, numberFormat));
889: units.add(new NumberTickUnit(1000, numberFormat));
890: units.add(new NumberTickUnit(2000, numberFormat));
891: units.add(new NumberTickUnit(5000, numberFormat));
892: units.add(new NumberTickUnit(10000, numberFormat));
893: units.add(new NumberTickUnit(20000, numberFormat));
894: units.add(new NumberTickUnit(50000, numberFormat));
895: units.add(new NumberTickUnit(100000, numberFormat));
896: units.add(new NumberTickUnit(200000, numberFormat));
897: units.add(new NumberTickUnit(500000, numberFormat));
898: units.add(new NumberTickUnit(1000000, numberFormat));
899: units.add(new NumberTickUnit(2000000, numberFormat));
900: units.add(new NumberTickUnit(5000000, numberFormat));
901: units.add(new NumberTickUnit(10000000, numberFormat));
902: units.add(new NumberTickUnit(20000000, numberFormat));
903: units.add(new NumberTickUnit(50000000, numberFormat));
904: units.add(new NumberTickUnit(100000000, numberFormat));
905: units.add(new NumberTickUnit(200000000, numberFormat));
906: units.add(new NumberTickUnit(500000000, numberFormat));
907: units.add(new NumberTickUnit(1000000000, numberFormat));
908: units.add(new NumberTickUnit(2000000000, numberFormat));
909: units.add(new NumberTickUnit(5000000000.0, numberFormat));
910: units.add(new NumberTickUnit(10000000000.0, numberFormat));
911:
912: return units;
913:
914: }
915:
916:
923: protected double estimateMaximumTickLabelHeight(Graphics2D g2) {
924:
925: RectangleInsets tickLabelInsets = getTickLabelInsets();
926: double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom();
927:
928: Font tickLabelFont = getTickLabelFont();
929: FontRenderContext frc = g2.getFontRenderContext();
930: result += tickLabelFont.getLineMetrics("123", frc).getHeight();
931: return result;
932:
933: }
934:
935:
948: protected double estimateMaximumTickLabelWidth(Graphics2D g2,
949: TickUnit unit) {
950:
951: RectangleInsets tickLabelInsets = getTickLabelInsets();
952: double result = tickLabelInsets.getLeft() + tickLabelInsets.getRight();
953:
954: if (isVerticalTickLabels()) {
955:
956:
957: FontRenderContext frc = g2.getFontRenderContext();
958: LineMetrics lm = getTickLabelFont().getLineMetrics("0", frc);
959: result += lm.getHeight();
960: }
961: else {
962:
963: FontMetrics fm = g2.getFontMetrics(getTickLabelFont());
964: Range range = getRange();
965: double lower = range.getLowerBound();
966: double upper = range.getUpperBound();
967: String lowerStr = unit.valueToString(lower);
968: String upperStr = unit.valueToString(upper);
969: double w1 = fm.stringWidth(lowerStr);
970: double w2 = fm.stringWidth(upperStr);
971: result += Math.max(w1, w2);
972: }
973:
974: return result;
975:
976: }
977:
978:
987: protected void selectAutoTickUnit(Graphics2D g2,
988: Rectangle2D dataArea,
989: RectangleEdge edge) {
990:
991: if (RectangleEdge.isTopOrBottom(edge)) {
992: selectHorizontalAutoTickUnit(g2, dataArea, edge);
993: }
994: else if (RectangleEdge.isLeftOrRight(edge)) {
995: selectVerticalAutoTickUnit(g2, dataArea, edge);
996: }
997:
998: }
999:
1000:
1009: protected void selectHorizontalAutoTickUnit(Graphics2D g2,
1010: Rectangle2D dataArea,
1011: RectangleEdge edge) {
1012:
1013: double tickLabelWidth = estimateMaximumTickLabelWidth(
1014: g2, getTickUnit()
1015: );
1016:
1017:
1018: TickUnitSource tickUnits = getStandardTickUnits();
1019: TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1020: double unit1Width = lengthToJava2D(unit1.getSize(), dataArea, edge);
1021:
1022:
1023: double guess = (tickLabelWidth / unit1Width) * unit1.getSize();
1024:
1025: NumberTickUnit unit2
1026: = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1027: double unit2Width = lengthToJava2D(unit2.getSize(), dataArea, edge);
1028:
1029: tickLabelWidth = estimateMaximumTickLabelWidth(g2, unit2);
1030: if (tickLabelWidth > unit2Width) {
1031: unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1032: }
1033:
1034: setTickUnit(unit2, false, false);
1035:
1036: }
1037:
1038:
1047: protected void selectVerticalAutoTickUnit(Graphics2D g2,
1048: Rectangle2D dataArea,
1049: RectangleEdge edge) {
1050:
1051: double tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1052:
1053:
1054: TickUnitSource tickUnits = getStandardTickUnits();
1055: TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1056: double unitHeight = lengthToJava2D(unit1.getSize(), dataArea, edge);
1057:
1058:
1059: double guess = (tickLabelHeight / unitHeight) * unit1.getSize();
1060:
1061: NumberTickUnit unit2
1062: = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1063: double unit2Height = lengthToJava2D(unit2.getSize(), dataArea, edge);
1064:
1065: tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1066: if (tickLabelHeight > unit2Height) {
1067: unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1068: }
1069:
1070: setTickUnit(unit2, false, false);
1071:
1072: }
1073:
1074:
1086: public List refreshTicks(Graphics2D g2,
1087: AxisState state,
1088: Rectangle2D dataArea,
1089: RectangleEdge edge) {
1090:
1091: List result = new java.util.ArrayList();
1092: if (RectangleEdge.isTopOrBottom(edge)) {
1093: result = refreshTicksHorizontal(g2, dataArea, edge);
1094: }
1095: else if (RectangleEdge.isLeftOrRight(edge)) {
1096: result = refreshTicksVertical(g2, dataArea, edge);
1097: }
1098: return result;
1099:
1100: }
1101:
1102:
1112: protected List refreshTicksHorizontal(Graphics2D g2,
1113: Rectangle2D dataArea,
1114: RectangleEdge edge) {
1115:
1116: List result = new java.util.ArrayList();
1117:
1118: Font tickLabelFont = getTickLabelFont();
1119: g2.setFont(tickLabelFont);
1120:
1121: if (isAutoTickUnitSelection()) {
1122: selectAutoTickUnit(g2, dataArea, edge);
1123: }
1124:
1125: double size = getTickUnit().getSize();
1126: int count = calculateVisibleTickCount();
1127: double lowestTickValue = calculateLowestVisibleTickValue();
1128:
1129: if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1130: for (int i = 0; i < count; i++) {
1131: double currentTickValue = lowestTickValue + (i * size);
1132: String tickLabel;
1133: NumberFormat formatter = getNumberFormatOverride();
1134: if (formatter != null) {
1135: tickLabel = formatter.format(currentTickValue);
1136: }
1137: else {
1138: tickLabel = getTickUnit().valueToString(currentTickValue);
1139: }
1140: TextAnchor anchor = null;
1141: TextAnchor rotationAnchor = null;
1142: double angle = 0.0;
1143: if (isVerticalTickLabels()) {
1144: anchor = TextAnchor.CENTER_RIGHT;
1145: rotationAnchor = TextAnchor.CENTER_RIGHT;
1146: if (edge == RectangleEdge.TOP) {
1147: angle = Math.PI / 2.0;
1148: }
1149: else {
1150: angle = -Math.PI / 2.0;
1151: }
1152: }
1153: else {
1154: if (edge == RectangleEdge.TOP) {
1155: anchor = TextAnchor.BOTTOM_CENTER;
1156: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1157: }
1158: else {
1159: anchor = TextAnchor.TOP_CENTER;
1160: rotationAnchor = TextAnchor.TOP_CENTER;
1161: }
1162: }
1163:
1164: Tick tick = new NumberTick(
1165: new Double(currentTickValue), tickLabel, anchor,
1166: rotationAnchor, angle
1167: );
1168: result.add(tick);
1169: }
1170: }
1171: return result;
1172:
1173: }
1174:
1175:
1186: protected List refreshTicksVertical(Graphics2D g2,
1187: Rectangle2D dataArea,
1188: RectangleEdge edge) {
1189:
1190: List result = new java.util.ArrayList();
1191: result.clear();
1192:
1193: Font tickLabelFont = getTickLabelFont();
1194: g2.setFont(tickLabelFont);
1195: if (isAutoTickUnitSelection()) {
1196: selectAutoTickUnit(g2, dataArea, edge);
1197: }
1198:
1199: double size = getTickUnit().getSize();
1200: int count = calculateVisibleTickCount();
1201: double lowestTickValue = calculateLowestVisibleTickValue();
1202:
1203: if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1204: for (int i = 0; i < count; i++) {
1205: double currentTickValue = lowestTickValue + (i * size);
1206: String tickLabel;
1207: NumberFormat formatter = getNumberFormatOverride();
1208: if (formatter != null) {
1209: tickLabel = formatter.format(currentTickValue);
1210: }
1211: else {
1212: tickLabel = getTickUnit().valueToString(currentTickValue);
1213: }
1214:
1215: TextAnchor anchor = null;
1216: TextAnchor rotationAnchor = null;
1217: double angle = 0.0;
1218: if (isVerticalTickLabels()) {
1219: if (edge == RectangleEdge.LEFT) {
1220: anchor = TextAnchor.BOTTOM_CENTER;
1221: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1222: angle = -Math.PI / 2.0;
1223: }
1224: else {
1225: anchor = TextAnchor.BOTTOM_CENTER;
1226: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1227: angle = Math.PI / 2.0;
1228: }
1229: }
1230: else {
1231: if (edge == RectangleEdge.LEFT) {
1232: anchor = TextAnchor.CENTER_RIGHT;
1233: rotationAnchor = TextAnchor.CENTER_RIGHT;
1234: }
1235: else {
1236: anchor = TextAnchor.CENTER_LEFT;
1237: rotationAnchor = TextAnchor.CENTER_LEFT;
1238: }
1239: }
1240:
1241: Tick tick = new NumberTick(
1242: new Double(currentTickValue), tickLabel, anchor,
1243: rotationAnchor, angle
1244: );
1245: result.add(tick);
1246: }
1247: }
1248: return result;
1249:
1250: }
1251:
1252:
1260: public Object clone() throws CloneNotSupportedException {
1261: NumberAxis clone = (NumberAxis) super.clone();
1262: if (this.numberFormatOverride != null) {
1263: clone.numberFormatOverride
1264: = (NumberFormat) this.numberFormatOverride.clone();
1265: }
1266: return clone;
1267: }
1268:
1269:
1276: public boolean equals(Object obj) {
1277: if (obj == this) {
1278: return true;
1279: }
1280: if (!(obj instanceof NumberAxis)) {
1281: return false;
1282: }
1283: if (!super.equals(obj)) {
1284: return false;
1285: }
1286: NumberAxis that = (NumberAxis) obj;
1287: if (this.autoRangeIncludesZero != that.autoRangeIncludesZero) {
1288: return false;
1289: }
1290: if (this.autoRangeStickyZero != that.autoRangeStickyZero) {
1291: return false;
1292: }
1293: if (!ObjectUtilities.equal(this.tickUnit, that.tickUnit)) {
1294: return false;
1295: }
1296: if (!ObjectUtilities.equal(this.numberFormatOverride,
1297: that.numberFormatOverride)) {
1298: return false;
1299: }
1300: if (!this.rangeType.equals(that.rangeType)) {
1301: return false;
1302: }
1303: return true;
1304: }
1305:
1306:
1311: public int hashCode() {
1312: if (getLabel() != null) {
1313: return getLabel().hashCode();
1314: }
1315: else {
1316: return 0;
1317: }
1318: }
1319:
1320: }