1:
97:
98: package ;
99:
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111:
112: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122:
123:
135: public class NumberAxis extends ValueAxis implements Cloneable, Serializable {
136:
137:
138: private static final long serialVersionUID = 2805933088476185789L;
139:
140:
141: public static final boolean DEFAULT_AUTO_RANGE_INCLUDES_ZERO = true;
142:
143:
144: public static final boolean DEFAULT_AUTO_RANGE_STICKY_ZERO = true;
145:
146:
147: public static final NumberTickUnit DEFAULT_TICK_UNIT = new NumberTickUnit(
148: 1.0, new DecimalFormat("0"));
149:
150:
151: public static final boolean DEFAULT_VERTICAL_TICK_LABELS = false;
152:
153:
157: private RangeType rangeType;
158:
159:
164: private boolean autoRangeIncludesZero;
165:
166:
171: private boolean autoRangeStickyZero;
172:
173:
174: private NumberTickUnit tickUnit;
175:
176:
177: private NumberFormat numberFormatOverride;
178:
179:
180: private MarkerAxisBand markerBand;
181:
182:
185: public NumberAxis() {
186: this(null);
187: }
188:
189:
194: public NumberAxis(String label) {
195: super(label, NumberAxis.createStandardTickUnits());
196: this.rangeType = RangeType.FULL;
197: this.autoRangeIncludesZero = DEFAULT_AUTO_RANGE_INCLUDES_ZERO;
198: this.autoRangeStickyZero = DEFAULT_AUTO_RANGE_STICKY_ZERO;
199: this.tickUnit = DEFAULT_TICK_UNIT;
200: this.numberFormatOverride = null;
201: this.markerBand = null;
202: }
203:
204:
211: public RangeType getRangeType() {
212: return this.rangeType;
213: }
214:
215:
222: public void setRangeType(RangeType rangeType) {
223: if (rangeType == null) {
224: throw new IllegalArgumentException("Null 'rangeType' argument.");
225: }
226: this.rangeType = rangeType;
227: notifyListeners(new AxisChangeEvent(this));
228: }
229:
230:
236: public boolean getAutoRangeIncludesZero() {
237: return this.autoRangeIncludesZero;
238: }
239:
240:
253: public void setAutoRangeIncludesZero(boolean flag) {
254: if (this.autoRangeIncludesZero != flag) {
255: this.autoRangeIncludesZero = flag;
256: if (isAutoRange()) {
257: autoAdjustRange();
258: }
259: notifyListeners(new AxisChangeEvent(this));
260: }
261: }
262:
263:
271: public boolean getAutoRangeStickyZero() {
272: return this.autoRangeStickyZero;
273: }
274:
275:
283: public void setAutoRangeStickyZero(boolean flag) {
284: if (this.autoRangeStickyZero != flag) {
285: this.autoRangeStickyZero = flag;
286: if (isAutoRange()) {
287: autoAdjustRange();
288: }
289: notifyListeners(new AxisChangeEvent(this));
290: }
291: }
292:
293:
306: public NumberTickUnit getTickUnit() {
307: return this.tickUnit;
308: }
309:
310:
322: public void setTickUnit(NumberTickUnit unit) {
323:
324: setTickUnit(unit, true, true);
325: }
326:
327:
338: public void setTickUnit(NumberTickUnit unit, boolean notify,
339: boolean turnOffAutoSelect) {
340:
341: if (unit == null) {
342: throw new IllegalArgumentException("Null 'unit' argument.");
343: }
344: this.tickUnit = unit;
345: if (turnOffAutoSelect) {
346: setAutoTickUnitSelection(false, false);
347: }
348: if (notify) {
349: notifyListeners(new AxisChangeEvent(this));
350: }
351:
352: }
353:
354:
362: public NumberFormat getNumberFormatOverride() {
363: return this.numberFormatOverride;
364: }
365:
366:
374: public void setNumberFormatOverride(NumberFormat formatter) {
375: this.numberFormatOverride = formatter;
376: notifyListeners(new AxisChangeEvent(this));
377: }
378:
379:
386: public MarkerAxisBand getMarkerBand() {
387: return this.markerBand;
388: }
389:
390:
400: public void setMarkerBand(MarkerAxisBand band) {
401: this.markerBand = band;
402: notifyListeners(new AxisChangeEvent(this));
403: }
404:
405:
409: public void configure() {
410: if (isAutoRange()) {
411: autoAdjustRange();
412: }
413: }
414:
415:
418: protected void autoAdjustRange() {
419:
420: Plot plot = getPlot();
421: if (plot == null) {
422: return;
423: }
424:
425: if (plot instanceof ValueAxisPlot) {
426: ValueAxisPlot vap = (ValueAxisPlot) plot;
427:
428: Range r = vap.getDataRange(this);
429: if (r == null) {
430: r = getDefaultAutoRange();
431: }
432:
433: double upper = r.getUpperBound();
434: double lower = r.getLowerBound();
435: if (this.rangeType == RangeType.POSITIVE) {
436: lower = Math.max(0.0, lower);
437: upper = Math.max(0.0, upper);
438: }
439: else if (this.rangeType == RangeType.NEGATIVE) {
440: lower = Math.min(0.0, lower);
441: upper = Math.min(0.0, upper);
442: }
443:
444: if (getAutoRangeIncludesZero()) {
445: lower = Math.min(lower, 0.0);
446: upper = Math.max(upper, 0.0);
447: }
448: double range = upper - lower;
449:
450:
451: double fixedAutoRange = getFixedAutoRange();
452: if (fixedAutoRange > 0.0) {
453: lower = upper - fixedAutoRange;
454: }
455: else {
456:
457: double minRange = getAutoRangeMinimumSize();
458: if (range < minRange) {
459: double expand = (minRange - range) / 2;
460: upper = upper + expand;
461: lower = lower - expand;
462: if (lower == upper) {
463: double adjust = Math.abs(lower) / 10.0;
464: lower = lower - adjust;
465: upper = upper + adjust;
466: }
467: if (this.rangeType == RangeType.POSITIVE) {
468: if (lower < 0.0) {
469: upper = upper - lower;
470: lower = 0.0;
471: }
472: }
473: else if (this.rangeType == RangeType.NEGATIVE) {
474: if (upper > 0.0) {
475: lower = lower - upper;
476: upper = 0.0;
477: }
478: }
479: }
480:
481: if (getAutoRangeStickyZero()) {
482: if (upper <= 0.0) {
483: upper = Math.min(0.0, upper + getUpperMargin() * range);
484: }
485: else {
486: upper = upper + getUpperMargin() * range;
487: }
488: if (lower >= 0.0) {
489: lower = Math.max(0.0, lower - getLowerMargin() * range);
490: }
491: else {
492: lower = lower - getLowerMargin() * range;
493: }
494: }
495: else {
496: upper = upper + getUpperMargin() * range;
497: lower = lower - getLowerMargin() * range;
498: }
499: }
500:
501: setRange(new Range(lower, upper), false, false);
502: }
503:
504: }
505:
506:
520: public double valueToJava2D(double value, Rectangle2D area,
521: RectangleEdge edge) {
522:
523: Range range = getRange();
524: double axisMin = range.getLowerBound();
525: double axisMax = range.getUpperBound();
526:
527: double min = 0.0;
528: double max = 0.0;
529: if (RectangleEdge.isTopOrBottom(edge)) {
530: min = area.getX();
531: max = area.getMaxX();
532: }
533: else if (RectangleEdge.isLeftOrRight(edge)) {
534: max = area.getMinY();
535: min = area.getMaxY();
536: }
537: if (isInverted()) {
538: return max
539: - ((value - axisMin) / (axisMax - axisMin)) * (max - min);
540: }
541: else {
542: return min
543: + ((value - axisMin) / (axisMax - axisMin)) * (max - min);
544: }
545:
546: }
547:
548:
560: public double java2DToValue(double java2DValue, Rectangle2D area,
561: RectangleEdge edge) {
562:
563: Range range = getRange();
564: double axisMin = range.getLowerBound();
565: double axisMax = range.getUpperBound();
566:
567: double min = 0.0;
568: double max = 0.0;
569: if (RectangleEdge.isTopOrBottom(edge)) {
570: min = area.getX();
571: max = area.getMaxX();
572: }
573: else if (RectangleEdge.isLeftOrRight(edge)) {
574: min = area.getMaxY();
575: max = area.getY();
576: }
577: if (isInverted()) {
578: return axisMax
579: - (java2DValue - min) / (max - min) * (axisMax - axisMin);
580: }
581: else {
582: return axisMin
583: + (java2DValue - min) / (max - min) * (axisMax - axisMin);
584: }
585:
586: }
587:
588:
595: protected double calculateLowestVisibleTickValue() {
596:
597: double unit = getTickUnit().getSize();
598: double index = Math.ceil(getRange().getLowerBound() / unit);
599: return index * unit;
600:
601: }
602:
603:
610: protected double calculateHighestVisibleTickValue() {
611:
612: double unit = getTickUnit().getSize();
613: double index = Math.floor(getRange().getUpperBound() / unit);
614: return index * unit;
615:
616: }
617:
618:
623: protected int calculateVisibleTickCount() {
624:
625: double unit = getTickUnit().getSize();
626: Range range = getRange();
627: return (int) (Math.floor(range.getUpperBound() / unit)
628: - Math.ceil(range.getLowerBound() / unit) + 1);
629:
630: }
631:
632:
648: public AxisState draw(Graphics2D g2,
649: double cursor,
650: Rectangle2D plotArea,
651: Rectangle2D dataArea,
652: RectangleEdge edge,
653: PlotRenderingInfo plotState) {
654:
655: AxisState state = null;
656:
657: if (!isVisible()) {
658: state = new AxisState(cursor);
659:
660:
661: List ticks = refreshTicks(g2, state, dataArea, edge);
662: state.setTicks(ticks);
663: return state;
664: }
665:
666:
667: state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge);
668:
669:
670:
671:
672:
673:
674:
675:
676:
677:
678: state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
679:
680: return state;
681:
682: }
683:
684:
696: public static TickUnitSource createStandardTickUnits() {
697:
698: TickUnits units = new TickUnits();
699: DecimalFormat df0 = new DecimalFormat("0.00000000");
700: DecimalFormat df1 = new DecimalFormat("0.0000000");
701: DecimalFormat df2 = new DecimalFormat("0.000000");
702: DecimalFormat df3 = new DecimalFormat("0.00000");
703: DecimalFormat df4 = new DecimalFormat("0.0000");
704: DecimalFormat df5 = new DecimalFormat("0.000");
705: DecimalFormat df6 = new DecimalFormat("0.00");
706: DecimalFormat df7 = new DecimalFormat("0.0");
707: DecimalFormat df8 = new DecimalFormat("#,##0");
708: DecimalFormat df9 = new DecimalFormat("#,###,##0");
709: DecimalFormat df10 = new DecimalFormat("#,###,###,##0");
710:
711:
712:
713: units.add(new NumberTickUnit(0.0000001, df1));
714: units.add(new NumberTickUnit(0.000001, df2));
715: units.add(new NumberTickUnit(0.00001, df3));
716: units.add(new NumberTickUnit(0.0001, df4));
717: units.add(new NumberTickUnit(0.001, df5));
718: units.add(new NumberTickUnit(0.01, df6));
719: units.add(new NumberTickUnit(0.1, df7));
720: units.add(new NumberTickUnit(1, df8));
721: units.add(new NumberTickUnit(10, df8));
722: units.add(new NumberTickUnit(100, df8));
723: units.add(new NumberTickUnit(1000, df8));
724: units.add(new NumberTickUnit(10000, df8));
725: units.add(new NumberTickUnit(100000, df8));
726: units.add(new NumberTickUnit(1000000, df9));
727: units.add(new NumberTickUnit(10000000, df9));
728: units.add(new NumberTickUnit(100000000, df9));
729: units.add(new NumberTickUnit(1000000000, df10));
730: units.add(new NumberTickUnit(10000000000.0, df10));
731: units.add(new NumberTickUnit(100000000000.0, df10));
732:
733: units.add(new NumberTickUnit(0.00000025, df0));
734: units.add(new NumberTickUnit(0.0000025, df1));
735: units.add(new NumberTickUnit(0.000025, df2));
736: units.add(new NumberTickUnit(0.00025, df3));
737: units.add(new NumberTickUnit(0.0025, df4));
738: units.add(new NumberTickUnit(0.025, df5));
739: units.add(new NumberTickUnit(0.25, df6));
740: units.add(new NumberTickUnit(2.5, df7));
741: units.add(new NumberTickUnit(25, df8));
742: units.add(new NumberTickUnit(250, df8));
743: units.add(new NumberTickUnit(2500, df8));
744: units.add(new NumberTickUnit(25000, df8));
745: units.add(new NumberTickUnit(250000, df8));
746: units.add(new NumberTickUnit(2500000, df9));
747: units.add(new NumberTickUnit(25000000, df9));
748: units.add(new NumberTickUnit(250000000, df9));
749: units.add(new NumberTickUnit(2500000000.0, df10));
750: units.add(new NumberTickUnit(25000000000.0, df10));
751: units.add(new NumberTickUnit(250000000000.0, df10));
752:
753: units.add(new NumberTickUnit(0.0000005, df1));
754: units.add(new NumberTickUnit(0.000005, df2));
755: units.add(new NumberTickUnit(0.00005, df3));
756: units.add(new NumberTickUnit(0.0005, df4));
757: units.add(new NumberTickUnit(0.005, df5));
758: units.add(new NumberTickUnit(0.05, df6));
759: units.add(new NumberTickUnit(0.5, df7));
760: units.add(new NumberTickUnit(5L, df8));
761: units.add(new NumberTickUnit(50L, df8));
762: units.add(new NumberTickUnit(500L, df8));
763: units.add(new NumberTickUnit(5000L, df8));
764: units.add(new NumberTickUnit(50000L, df8));
765: units.add(new NumberTickUnit(500000L, df8));
766: units.add(new NumberTickUnit(5000000L, df9));
767: units.add(new NumberTickUnit(50000000L, df9));
768: units.add(new NumberTickUnit(500000000L, df9));
769: units.add(new NumberTickUnit(5000000000L, df10));
770: units.add(new NumberTickUnit(50000000000L, df10));
771: units.add(new NumberTickUnit(500000000000L, df10));
772:
773: return units;
774:
775: }
776:
777:
785: public static TickUnitSource createIntegerTickUnits() {
786:
787: TickUnits units = new TickUnits();
788: DecimalFormat df0 = new DecimalFormat("0");
789: DecimalFormat df1 = new DecimalFormat("#,##0");
790: units.add(new NumberTickUnit(1, df0));
791: units.add(new NumberTickUnit(2, df0));
792: units.add(new NumberTickUnit(5, df0));
793: units.add(new NumberTickUnit(10, df0));
794: units.add(new NumberTickUnit(20, df0));
795: units.add(new NumberTickUnit(50, df0));
796: units.add(new NumberTickUnit(100, df0));
797: units.add(new NumberTickUnit(200, df0));
798: units.add(new NumberTickUnit(500, df0));
799: units.add(new NumberTickUnit(1000, df1));
800: units.add(new NumberTickUnit(2000, df1));
801: units.add(new NumberTickUnit(5000, df1));
802: units.add(new NumberTickUnit(10000, df1));
803: units.add(new NumberTickUnit(20000, df1));
804: units.add(new NumberTickUnit(50000, df1));
805: units.add(new NumberTickUnit(100000, df1));
806: units.add(new NumberTickUnit(200000, df1));
807: units.add(new NumberTickUnit(500000, df1));
808: units.add(new NumberTickUnit(1000000, df1));
809: units.add(new NumberTickUnit(2000000, df1));
810: units.add(new NumberTickUnit(5000000, df1));
811: units.add(new NumberTickUnit(10000000, df1));
812: units.add(new NumberTickUnit(20000000, df1));
813: units.add(new NumberTickUnit(50000000, df1));
814: units.add(new NumberTickUnit(100000000, df1));
815: units.add(new NumberTickUnit(200000000, df1));
816: units.add(new NumberTickUnit(500000000, df1));
817: units.add(new NumberTickUnit(1000000000, df1));
818: units.add(new NumberTickUnit(2000000000, df1));
819: units.add(new NumberTickUnit(5000000000.0, df1));
820: units.add(new NumberTickUnit(10000000000.0, df1));
821:
822: return units;
823:
824: }
825:
826:
841: public static TickUnitSource createStandardTickUnits(Locale locale) {
842:
843: TickUnits units = new TickUnits();
844:
845: NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
846:
847:
848:
849: units.add(new NumberTickUnit(0.0000001, numberFormat));
850: units.add(new NumberTickUnit(0.000001, numberFormat));
851: units.add(new NumberTickUnit(0.00001, numberFormat));
852: units.add(new NumberTickUnit(0.0001, numberFormat));
853: units.add(new NumberTickUnit(0.001, numberFormat));
854: units.add(new NumberTickUnit(0.01, numberFormat));
855: units.add(new NumberTickUnit(0.1, numberFormat));
856: units.add(new NumberTickUnit(1, numberFormat));
857: units.add(new NumberTickUnit(10, numberFormat));
858: units.add(new NumberTickUnit(100, numberFormat));
859: units.add(new NumberTickUnit(1000, numberFormat));
860: units.add(new NumberTickUnit(10000, numberFormat));
861: units.add(new NumberTickUnit(100000, numberFormat));
862: units.add(new NumberTickUnit(1000000, numberFormat));
863: units.add(new NumberTickUnit(10000000, numberFormat));
864: units.add(new NumberTickUnit(100000000, numberFormat));
865: units.add(new NumberTickUnit(1000000000, numberFormat));
866: units.add(new NumberTickUnit(10000000000.0, numberFormat));
867:
868: units.add(new NumberTickUnit(0.00000025, numberFormat));
869: units.add(new NumberTickUnit(0.0000025, numberFormat));
870: units.add(new NumberTickUnit(0.000025, numberFormat));
871: units.add(new NumberTickUnit(0.00025, numberFormat));
872: units.add(new NumberTickUnit(0.0025, numberFormat));
873: units.add(new NumberTickUnit(0.025, numberFormat));
874: units.add(new NumberTickUnit(0.25, numberFormat));
875: units.add(new NumberTickUnit(2.5, numberFormat));
876: units.add(new NumberTickUnit(25, numberFormat));
877: units.add(new NumberTickUnit(250, numberFormat));
878: units.add(new NumberTickUnit(2500, numberFormat));
879: units.add(new NumberTickUnit(25000, numberFormat));
880: units.add(new NumberTickUnit(250000, numberFormat));
881: units.add(new NumberTickUnit(2500000, numberFormat));
882: units.add(new NumberTickUnit(25000000, numberFormat));
883: units.add(new NumberTickUnit(250000000, numberFormat));
884: units.add(new NumberTickUnit(2500000000.0, numberFormat));
885: units.add(new NumberTickUnit(25000000000.0, numberFormat));
886:
887: units.add(new NumberTickUnit(0.0000005, numberFormat));
888: units.add(new NumberTickUnit(0.000005, numberFormat));
889: units.add(new NumberTickUnit(0.00005, numberFormat));
890: units.add(new NumberTickUnit(0.0005, numberFormat));
891: units.add(new NumberTickUnit(0.005, numberFormat));
892: units.add(new NumberTickUnit(0.05, numberFormat));
893: units.add(new NumberTickUnit(0.5, numberFormat));
894: units.add(new NumberTickUnit(5L, numberFormat));
895: units.add(new NumberTickUnit(50L, numberFormat));
896: units.add(new NumberTickUnit(500L, numberFormat));
897: units.add(new NumberTickUnit(5000L, numberFormat));
898: units.add(new NumberTickUnit(50000L, numberFormat));
899: units.add(new NumberTickUnit(500000L, numberFormat));
900: units.add(new NumberTickUnit(5000000L, numberFormat));
901: units.add(new NumberTickUnit(50000000L, numberFormat));
902: units.add(new NumberTickUnit(500000000L, numberFormat));
903: units.add(new NumberTickUnit(5000000000L, numberFormat));
904: units.add(new NumberTickUnit(50000000000L, numberFormat));
905:
906: return units;
907:
908: }
909:
910:
920: public static TickUnitSource createIntegerTickUnits(Locale locale) {
921:
922: TickUnits units = new TickUnits();
923:
924: NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
925:
926: units.add(new NumberTickUnit(1, numberFormat));
927: units.add(new NumberTickUnit(2, numberFormat));
928: units.add(new NumberTickUnit(5, numberFormat));
929: units.add(new NumberTickUnit(10, numberFormat));
930: units.add(new NumberTickUnit(20, numberFormat));
931: units.add(new NumberTickUnit(50, numberFormat));
932: units.add(new NumberTickUnit(100, numberFormat));
933: units.add(new NumberTickUnit(200, numberFormat));
934: units.add(new NumberTickUnit(500, numberFormat));
935: units.add(new NumberTickUnit(1000, numberFormat));
936: units.add(new NumberTickUnit(2000, numberFormat));
937: units.add(new NumberTickUnit(5000, numberFormat));
938: units.add(new NumberTickUnit(10000, numberFormat));
939: units.add(new NumberTickUnit(20000, numberFormat));
940: units.add(new NumberTickUnit(50000, numberFormat));
941: units.add(new NumberTickUnit(100000, numberFormat));
942: units.add(new NumberTickUnit(200000, numberFormat));
943: units.add(new NumberTickUnit(500000, numberFormat));
944: units.add(new NumberTickUnit(1000000, numberFormat));
945: units.add(new NumberTickUnit(2000000, numberFormat));
946: units.add(new NumberTickUnit(5000000, numberFormat));
947: units.add(new NumberTickUnit(10000000, numberFormat));
948: units.add(new NumberTickUnit(20000000, numberFormat));
949: units.add(new NumberTickUnit(50000000, numberFormat));
950: units.add(new NumberTickUnit(100000000, numberFormat));
951: units.add(new NumberTickUnit(200000000, numberFormat));
952: units.add(new NumberTickUnit(500000000, numberFormat));
953: units.add(new NumberTickUnit(1000000000, numberFormat));
954: units.add(new NumberTickUnit(2000000000, numberFormat));
955: units.add(new NumberTickUnit(5000000000.0, numberFormat));
956: units.add(new NumberTickUnit(10000000000.0, numberFormat));
957:
958: return units;
959:
960: }
961:
962:
969: protected double estimateMaximumTickLabelHeight(Graphics2D g2) {
970:
971: RectangleInsets tickLabelInsets = getTickLabelInsets();
972: double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom();
973:
974: Font tickLabelFont = getTickLabelFont();
975: FontRenderContext frc = g2.getFontRenderContext();
976: result += tickLabelFont.getLineMetrics("123", frc).getHeight();
977: return result;
978:
979: }
980:
981:
994: protected double estimateMaximumTickLabelWidth(Graphics2D g2,
995: TickUnit unit) {
996:
997: RectangleInsets tickLabelInsets = getTickLabelInsets();
998: double result = tickLabelInsets.getLeft() + tickLabelInsets.getRight();
999:
1000: if (isVerticalTickLabels()) {
1001:
1002:
1003: FontRenderContext frc = g2.getFontRenderContext();
1004: LineMetrics lm = getTickLabelFont().getLineMetrics("0", frc);
1005: result += lm.getHeight();
1006: }
1007: else {
1008:
1009: FontMetrics fm = g2.getFontMetrics(getTickLabelFont());
1010: Range range = getRange();
1011: double lower = range.getLowerBound();
1012: double upper = range.getUpperBound();
1013: String lowerStr = "";
1014: String upperStr = "";
1015: NumberFormat formatter = getNumberFormatOverride();
1016: if (formatter != null) {
1017: lowerStr = formatter.format(lower);
1018: upperStr = formatter.format(upper);
1019: }
1020: else {
1021: lowerStr = unit.valueToString(lower);
1022: upperStr = unit.valueToString(upper);
1023: }
1024: double w1 = fm.stringWidth(lowerStr);
1025: double w2 = fm.stringWidth(upperStr);
1026: result += Math.max(w1, w2);
1027: }
1028:
1029: return result;
1030:
1031: }
1032:
1033:
1042: protected void selectAutoTickUnit(Graphics2D g2,
1043: Rectangle2D dataArea,
1044: RectangleEdge edge) {
1045:
1046: if (RectangleEdge.isTopOrBottom(edge)) {
1047: selectHorizontalAutoTickUnit(g2, dataArea, edge);
1048: }
1049: else if (RectangleEdge.isLeftOrRight(edge)) {
1050: selectVerticalAutoTickUnit(g2, dataArea, edge);
1051: }
1052:
1053: }
1054:
1055:
1064: protected void selectHorizontalAutoTickUnit(Graphics2D g2,
1065: Rectangle2D dataArea,
1066: RectangleEdge edge) {
1067:
1068: double tickLabelWidth = estimateMaximumTickLabelWidth(
1069: g2, getTickUnit()
1070: );
1071:
1072:
1073: TickUnitSource tickUnits = getStandardTickUnits();
1074: TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1075: double unit1Width = lengthToJava2D(unit1.getSize(), dataArea, edge);
1076:
1077:
1078: double guess = (tickLabelWidth / unit1Width) * unit1.getSize();
1079:
1080: NumberTickUnit unit2
1081: = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1082: double unit2Width = lengthToJava2D(unit2.getSize(), dataArea, edge);
1083:
1084: tickLabelWidth = estimateMaximumTickLabelWidth(g2, unit2);
1085: if (tickLabelWidth > unit2Width) {
1086: unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1087: }
1088:
1089: setTickUnit(unit2, false, false);
1090:
1091: }
1092:
1093:
1102: protected void selectVerticalAutoTickUnit(Graphics2D g2,
1103: Rectangle2D dataArea,
1104: RectangleEdge edge) {
1105:
1106: double tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1107:
1108:
1109: TickUnitSource tickUnits = getStandardTickUnits();
1110: TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1111: double unitHeight = lengthToJava2D(unit1.getSize(), dataArea, edge);
1112:
1113:
1114: double guess = (tickLabelHeight / unitHeight) * unit1.getSize();
1115:
1116: NumberTickUnit unit2
1117: = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1118: double unit2Height = lengthToJava2D(unit2.getSize(), dataArea, edge);
1119:
1120: tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1121: if (tickLabelHeight > unit2Height) {
1122: unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1123: }
1124:
1125: setTickUnit(unit2, false, false);
1126:
1127: }
1128:
1129:
1141: public List refreshTicks(Graphics2D g2,
1142: AxisState state,
1143: Rectangle2D dataArea,
1144: RectangleEdge edge) {
1145:
1146: List result = new java.util.ArrayList();
1147: if (RectangleEdge.isTopOrBottom(edge)) {
1148: result = refreshTicksHorizontal(g2, dataArea, edge);
1149: }
1150: else if (RectangleEdge.isLeftOrRight(edge)) {
1151: result = refreshTicksVertical(g2, dataArea, edge);
1152: }
1153: return result;
1154:
1155: }
1156:
1157:
1167: protected List refreshTicksHorizontal(Graphics2D g2,
1168: Rectangle2D dataArea,
1169: RectangleEdge edge) {
1170:
1171: List result = new java.util.ArrayList();
1172:
1173: Font tickLabelFont = getTickLabelFont();
1174: g2.setFont(tickLabelFont);
1175:
1176: if (isAutoTickUnitSelection()) {
1177: selectAutoTickUnit(g2, dataArea, edge);
1178: }
1179:
1180: double size = getTickUnit().getSize();
1181: int count = calculateVisibleTickCount();
1182: double lowestTickValue = calculateLowestVisibleTickValue();
1183:
1184: if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1185: for (int i = 0; i < count; i++) {
1186: double currentTickValue = lowestTickValue + (i * size);
1187: String tickLabel;
1188: NumberFormat formatter = getNumberFormatOverride();
1189: if (formatter != null) {
1190: tickLabel = formatter.format(currentTickValue);
1191: }
1192: else {
1193: tickLabel = getTickUnit().valueToString(currentTickValue);
1194: }
1195: TextAnchor anchor = null;
1196: TextAnchor rotationAnchor = null;
1197: double angle = 0.0;
1198: if (isVerticalTickLabels()) {
1199: anchor = TextAnchor.CENTER_RIGHT;
1200: rotationAnchor = TextAnchor.CENTER_RIGHT;
1201: if (edge == RectangleEdge.TOP) {
1202: angle = Math.PI / 2.0;
1203: }
1204: else {
1205: angle = -Math.PI / 2.0;
1206: }
1207: }
1208: else {
1209: if (edge == RectangleEdge.TOP) {
1210: anchor = TextAnchor.BOTTOM_CENTER;
1211: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1212: }
1213: else {
1214: anchor = TextAnchor.TOP_CENTER;
1215: rotationAnchor = TextAnchor.TOP_CENTER;
1216: }
1217: }
1218:
1219: Tick tick = new NumberTick(
1220: new Double(currentTickValue), tickLabel, anchor,
1221: rotationAnchor, angle
1222: );
1223: result.add(tick);
1224: }
1225: }
1226: return result;
1227:
1228: }
1229:
1230:
1241: protected List refreshTicksVertical(Graphics2D g2,
1242: Rectangle2D dataArea,
1243: RectangleEdge edge) {
1244:
1245: List result = new java.util.ArrayList();
1246: result.clear();
1247:
1248: Font tickLabelFont = getTickLabelFont();
1249: g2.setFont(tickLabelFont);
1250: if (isAutoTickUnitSelection()) {
1251: selectAutoTickUnit(g2, dataArea, edge);
1252: }
1253:
1254: double size = getTickUnit().getSize();
1255: int count = calculateVisibleTickCount();
1256: double lowestTickValue = calculateLowestVisibleTickValue();
1257:
1258: if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1259: for (int i = 0; i < count; i++) {
1260: double currentTickValue = lowestTickValue + (i * size);
1261: String tickLabel;
1262: NumberFormat formatter = getNumberFormatOverride();
1263: if (formatter != null) {
1264: tickLabel = formatter.format(currentTickValue);
1265: }
1266: else {
1267: tickLabel = getTickUnit().valueToString(currentTickValue);
1268: }
1269:
1270: TextAnchor anchor = null;
1271: TextAnchor rotationAnchor = null;
1272: double angle = 0.0;
1273: if (isVerticalTickLabels()) {
1274: if (edge == RectangleEdge.LEFT) {
1275: anchor = TextAnchor.BOTTOM_CENTER;
1276: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1277: angle = -Math.PI / 2.0;
1278: }
1279: else {
1280: anchor = TextAnchor.BOTTOM_CENTER;
1281: rotationAnchor = TextAnchor.BOTTOM_CENTER;
1282: angle = Math.PI / 2.0;
1283: }
1284: }
1285: else {
1286: if (edge == RectangleEdge.LEFT) {
1287: anchor = TextAnchor.CENTER_RIGHT;
1288: rotationAnchor = TextAnchor.CENTER_RIGHT;
1289: }
1290: else {
1291: anchor = TextAnchor.CENTER_LEFT;
1292: rotationAnchor = TextAnchor.CENTER_LEFT;
1293: }
1294: }
1295:
1296: Tick tick = new NumberTick(
1297: new Double(currentTickValue), tickLabel, anchor,
1298: rotationAnchor, angle
1299: );
1300: result.add(tick);
1301: }
1302: }
1303: return result;
1304:
1305: }
1306:
1307:
1315: public Object clone() throws CloneNotSupportedException {
1316: NumberAxis clone = (NumberAxis) super.clone();
1317: if (this.numberFormatOverride != null) {
1318: clone.numberFormatOverride
1319: = (NumberFormat) this.numberFormatOverride.clone();
1320: }
1321: return clone;
1322: }
1323:
1324:
1331: public boolean equals(Object obj) {
1332: if (obj == this) {
1333: return true;
1334: }
1335: if (!(obj instanceof NumberAxis)) {
1336: return false;
1337: }
1338: if (!super.equals(obj)) {
1339: return false;
1340: }
1341: NumberAxis that = (NumberAxis) obj;
1342: if (this.autoRangeIncludesZero != that.autoRangeIncludesZero) {
1343: return false;
1344: }
1345: if (this.autoRangeStickyZero != that.autoRangeStickyZero) {
1346: return false;
1347: }
1348: if (!ObjectUtilities.equal(this.tickUnit, that.tickUnit)) {
1349: return false;
1350: }
1351: if (!ObjectUtilities.equal(this.numberFormatOverride,
1352: that.numberFormatOverride)) {
1353: return false;
1354: }
1355: if (!this.rangeType.equals(that.rangeType)) {
1356: return false;
1357: }
1358: return true;
1359: }
1360:
1361:
1366: public int hashCode() {
1367: if (getLabel() != null) {
1368: return getLabel().hashCode();
1369: }
1370: else {
1371: return 0;
1372: }
1373: }
1374:
1375: }