Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.chart; 027 028import java.text.DecimalFormat; 029import java.text.ParseException; 030import java.util.ArrayList; 031import java.util.Collections; 032import java.util.List; 033 034import javafx.animation.KeyFrame; 035import javafx.animation.KeyValue; 036import javafx.beans.property.BooleanProperty; 037import javafx.beans.property.BooleanPropertyBase; 038import javafx.beans.property.DoubleProperty; 039import javafx.beans.property.IntegerProperty; 040import javafx.beans.property.SimpleIntegerProperty; 041import javafx.beans.value.ChangeListener; 042import javafx.beans.value.ObservableValue; 043import javafx.geometry.Dimension2D; 044import javafx.geometry.Side; 045import javafx.util.Duration; 046import javafx.util.StringConverter; 047 048import com.sun.javafx.charts.ChartLayoutAnimator; 049import javafx.css.StyleableDoubleProperty; 050import javafx.css.CssMetaData; 051import com.sun.javafx.css.converters.SizeConverter; 052import javafx.css.Styleable; 053import javafx.css.StyleableProperty; 054 055/** 056 * A axis class that plots a range of numbers with major tick marks every "tickUnit". You can use any Number type with 057 * this axis, Long, Double, BigDecimal etc. 058 */ 059public final class NumberAxis extends ValueAxis<Number> { 060 061 /** We use these for auto ranging to pick a user friendly tick unit. We handle tick units in the range of 1e-10 to 1e+12 */ 062 private static final double[] TICK_UNIT_DEFAULTS = { 063 1.0E-10d, 2.5E-10d, 5.0E-10d, 1.0E-9d, 2.5E-9d, 5.0E-9d, 1.0E-8d, 2.5E-8d, 5.0E-8d, 1.0E-7d, 2.5E-7d, 5.0E-7d, 064 1.0E-6d, 2.5E-6d, 5.0E-6d, 1.0E-5d, 2.5E-5d, 5.0E-5d, 1.0E-4d, 2.5E-4d, 5.0E-4d, 0.0010d, 0.0025d, 0.0050d, 065 0.01d, 0.025d, 0.05d, 0.1d, 0.25d, 0.5d, 1.0d, 2.5d, 5.0d, 10.0d, 25.0d, 50.0d, 100.0d, 250.0d, 500.0d, 066 1000.0d, 2500.0d, 5000.0d, 10000.0d, 25000.0d, 50000.0d, 100000.0d, 250000.0d, 500000.0d, 1000000.0d, 067 2500000.0d, 5000000.0d, 1.0E7d, 2.5E7d, 5.0E7d, 1.0E8d, 2.5E8d, 5.0E8d, 1.0E9d, 2.5E9d, 5.0E9d, 1.0E10d, 068 2.5E10d, 5.0E10d, 1.0E11d, 2.5E11d, 5.0E11d, 1.0E12d, 2.5E12d, 5.0E12d 069 }; 070 /** These are matching decimal formatter strings */ 071 private static final String[] TICK_UNIT_FORMATTER_DEFAULTS = {"0.0000000000", "0.00000000000", "0.0000000000", 072 "0.000000000", "0.0000000000", "0.000000000", 073 "0.00000000", "0.000000000", "0.00000000", 074 "0.0000000", "0.00000000", "0.0000000", "0.000000", 075 "0.0000000", "0.000000", "0.00000", "0.000000", 076 "0.00000", "0.0000", "0.00000", "0.0000", "0.000", 077 "0.0000", "0.000", "0.00", "0.000", "0.00", "0.0", 078 "0.00", "0.0", "0", "0.0", "0", "#,##0"}; 079 080 private Object currentAnimationID; 081 private final ChartLayoutAnimator animator = new ChartLayoutAnimator(this); 082 private IntegerProperty currentRangeIndexProperty = new SimpleIntegerProperty(this, "currentRangeIndex", -1); 083 private DefaultFormatter defaultFormatter = new DefaultFormatter(this); 084 085 // -------------- PUBLIC PROPERTIES -------------------------------------------------------------------------------- 086 087 /** When true zero is always included in the visible range. This only has effect if auto-ranging is on. */ 088 private BooleanProperty forceZeroInRange = new BooleanPropertyBase(true) { 089 @Override protected void invalidated() { 090 // This will effect layout if we are auto ranging 091 if(isAutoRanging()) requestAxisLayout(); 092 } 093 094 @Override 095 public Object getBean() { 096 return NumberAxis.this; 097 } 098 099 @Override 100 public String getName() { 101 return "forceZeroInRange"; 102 } 103 }; 104 public final boolean isForceZeroInRange() { return forceZeroInRange.getValue(); } 105 public final void setForceZeroInRange(boolean value) { forceZeroInRange.setValue(value); } 106 public final BooleanProperty forceZeroInRangeProperty() { return forceZeroInRange; } 107 108 /** The value between each major tick mark in data units. This is automatically set if we are auto-ranging. */ 109 private DoubleProperty tickUnit = new StyleableDoubleProperty(5) { 110 @Override protected void invalidated() { 111 if(!isAutoRanging()) { 112 invalidateRange(); 113 requestAxisLayout(); 114 } 115 } 116 117 @Override 118 public CssMetaData<NumberAxis,Number> getCssMetaData() { 119 return StyleableProperties.TICK_UNIT; 120 } 121 122 @Override 123 public Object getBean() { 124 return NumberAxis.this; 125 } 126 127 @Override 128 public String getName() { 129 return "tickUnit"; 130 } 131 }; 132 public final double getTickUnit() { return tickUnit.get(); } 133 public final void setTickUnit(double value) { tickUnit.set(value); } 134 public final DoubleProperty tickUnitProperty() { return tickUnit; } 135 136 // -------------- CONSTRUCTORS ------------------------------------------------------------------------------------- 137 138 /** 139 * Create a auto-ranging NumberAxis 140 */ 141 public NumberAxis() {} 142 143 /** 144 * Create a non-auto-ranging NumberAxis with the given upper bound, lower bound and tick unit 145 * 146 * @param lowerBound The lower bound for this axis, ie min plottable value 147 * @param upperBound The upper bound for this axis, ie max plottable value 148 * @param tickUnit The tick unit, ie space between tickmarks 149 */ 150 public NumberAxis(double lowerBound, double upperBound, double tickUnit) { 151 super(lowerBound, upperBound); 152 setTickUnit(tickUnit); 153 } 154 155 /** 156 * Create a non-auto-ranging NumberAxis with the given upper bound, lower bound and tick unit 157 * 158 * @param axisLabel The name to display for this axis 159 * @param lowerBound The lower bound for this axis, ie min plottable value 160 * @param upperBound The upper bound for this axis, ie max plottable value 161 * @param tickUnit The tick unit, ie space between tickmarks 162 */ 163 public NumberAxis(String axisLabel, double lowerBound, double upperBound, double tickUnit) { 164 super(lowerBound, upperBound); 165 setTickUnit(tickUnit); 166 setLabel(axisLabel); 167 } 168 169 // -------------- PROTECTED METHODS -------------------------------------------------------------------------------- 170 171 /** 172 * Get the string label name for a tick mark with the given value 173 * 174 * @param value The value to format into a tick label string 175 * @return A formatted string for the given value 176 */ 177 @Override protected String getTickMarkLabel(Number value) { 178 StringConverter<Number> formatter = getTickLabelFormatter(); 179 if (formatter == null) formatter = defaultFormatter; 180 return formatter.toString(value); 181 } 182 183 /** 184 * Called to get the current axis range. 185 * 186 * @return A range object that can be passed to setRange() and calculateTickValues() 187 */ 188 @Override protected Object getRange() { 189 return new double[]{ 190 getLowerBound(), 191 getUpperBound(), 192 getTickUnit(), 193 getScale(), 194 currentRangeIndexProperty.get() 195 }; 196 } 197 198 /** 199 * Called to set the current axis range to the given range. If isAnimating() is true then this method should 200 * animate the range to the new range. 201 * 202 * @param range A range object returned from autoRange() 203 * @param animate If true animate the change in range 204 */ 205 @Override protected void setRange(Object range, boolean animate) { 206 final double[] rangeProps = (double[]) range; 207 final double lowerBound = rangeProps[0]; 208 final double upperBound = rangeProps[1]; 209 final double tickUnit = rangeProps[2]; 210 final double scale = rangeProps[3]; 211 final double rangeIndex = rangeProps[4]; 212 currentRangeIndexProperty.set((int)rangeIndex); 213 final double oldLowerBound = getLowerBound(); 214 setLowerBound(lowerBound); 215 setUpperBound(upperBound); 216 setTickUnit(tickUnit); 217 if(animate) { 218 animator.stop(currentAnimationID); 219 currentAnimationID = animator.animate( 220 new KeyFrame(Duration.ZERO, 221 new KeyValue(currentLowerBound, oldLowerBound), 222 new KeyValue(scalePropertyImpl(), getScale()) 223 ), 224 new KeyFrame(Duration.millis(700), 225 new KeyValue(currentLowerBound, lowerBound), 226 new KeyValue(scalePropertyImpl(), scale) 227 ) 228 ); 229 } else { 230 currentLowerBound.set(lowerBound); 231 setScale(scale); 232 } 233 } 234 235 /** 236 * Calculate a list of all the data values for each tick mark in range 237 * 238 * @param length The length of the axis in display units 239 * @param range A range object returned from autoRange() 240 * @return A list of tick marks that fit along the axis if it was the given length 241 */ 242 @Override protected List<Number> calculateTickValues(double length, Object range) { 243 final double[] rangeProps = (double[]) range; 244 final double lowerBound = rangeProps[0]; 245 final double upperBound = rangeProps[1]; 246 final double tickUnit = rangeProps[2]; 247 List<Number> tickValues = new ArrayList<Number>(); 248 if (tickUnit <= 0 || lowerBound == upperBound) { 249 tickValues.add(lowerBound); 250 } else if (getTickUnit() > 0) { 251 for (double major = lowerBound; major <= upperBound; major += tickUnit) { 252 tickValues.add(major); 253 if(tickValues.size()>2000) { 254 // This is a ridiculous amount of major tick marks, something has probably gone wrong 255 System.err.println("Warning we tried to create more than 2000 major tick marks on a NumberAxis. " + 256 "Lower Bound=" + lowerBound + ", Upper Bound=" + upperBound + ", Tick Unit=" + tickUnit); 257 break; 258 } 259 } 260 } 261 return tickValues; 262 } 263 264 /** 265 * Calculate a list of the data values for every minor tick mark 266 * 267 * @return List of data values where to draw minor tick marks 268 */ 269 protected List<Number> calculateMinorTickMarks() { 270 final List<Number> minorTickMarks = new ArrayList<Number>(); 271 final double lowerBound = getLowerBound(); 272 final double upperBound = getUpperBound(); 273 final double tickUnit = getTickUnit(); 274 final double minorUnit = tickUnit/getMinorTickCount(); 275 if (getTickUnit() > 0) { 276 for (double major = lowerBound; major < upperBound; major += tickUnit) { 277 for (double minor=major+minorUnit; minor < (major+tickUnit); minor += minorUnit) { 278 minorTickMarks.add(minor); 279 if(minorTickMarks.size()>10000) { 280 // This is a ridiculous amount of major tick marks, something has probably gone wrong 281 System.err.println("Warning we tried to create more than 10000 minor tick marks on a NumberAxis. " + 282 "Lower Bound=" + getLowerBound() + ", Upper Bound=" + getUpperBound() + ", Tick Unit=" + tickUnit); 283 break; 284 } 285 } 286 } 287 } 288 return minorTickMarks; 289 } 290 291 /** 292 * Measure the size of the label for given tick mark value. This uses the font that is set for the tick marks 293 * 294 * @param value tick mark value 295 * @param range range to use during calculations 296 * @return size of tick mark label for given value 297 */ 298 @Override protected Dimension2D measureTickMarkSize(Number value, Object range) { 299 final double[] rangeProps = (double[]) range; 300 final double rangeIndex = rangeProps[4]; 301 return measureTickMarkSize(value, getTickLabelRotation(), (int)rangeIndex); 302 } 303 304 /** 305 * Measure the size of the label for given tick mark value. This uses the font that is set for the tick marks 306 * 307 * @param value tick mark value 308 * @param rotation The text rotation 309 * @param rangeIndex The index of the tick unit range 310 * @return size of tick mark label for given value 311 */ 312 private Dimension2D measureTickMarkSize(Number value, double rotation, int rangeIndex) { 313 String labelText; 314 StringConverter<Number> formatter = getTickLabelFormatter(); 315 if (formatter == null) formatter = defaultFormatter; 316 if(formatter instanceof DefaultFormatter) { 317 labelText = ((DefaultFormatter)formatter).toString(value, rangeIndex); 318 } else { 319 labelText = formatter.toString(value); 320 } 321 return measureTickMarkLabelSize(labelText, rotation); 322 } 323 324 /** 325 * Called to set the upper and lower bound and anything else that needs to be auto-ranged 326 * 327 * @param minValue The min data value that needs to be plotted on this axis 328 * @param maxValue The max data value that needs to be plotted on this axis 329 * @param length The length of the axis in display coordinates 330 * @param labelSize The approximate average size a label takes along the axis 331 * @return The calculated range 332 */ 333 @Override protected Object autoRange(double minValue, double maxValue, double length, double labelSize) { 334 final Side side = getSide(); 335 final boolean vertical = Side.LEFT.equals(side) || Side.RIGHT.equals(side); 336 // check if we need to force zero into range 337 if (isForceZeroInRange()) { 338 if (maxValue < 0) { 339 maxValue = 0; 340 } else if (minValue > 0) { 341 minValue = 0; 342 } 343 } 344 final double range = maxValue-minValue; 345 // pad min and max by 2%, checking if the range is zero 346 final double paddedRange = (range==0) ? 2 : Math.abs(range)*1.02; 347 final double padding = (paddedRange - range) / 2; 348 // if min and max are not zero then add padding to them 349 double paddedMin = minValue - padding; 350 double paddedMax = maxValue + padding; 351 // check padding has not pushed min or max over zero line 352 if ((paddedMin < 0 && minValue >= 0) || (paddedMin > 0 && minValue <= 0)) { 353 // padding pushed min above or below zero so clamp to 0 354 paddedMin = 0; 355 } 356 if ((paddedMax < 0 && maxValue >= 0) || (paddedMax > 0 && maxValue <= 0)) { 357 // padding pushed min above or below zero so clamp to 0 358 paddedMax = 0; 359 } 360 // calculate the number of tick-marks we can fit in the given length 361 int numOfTickMarks = (int)Math.floor(Math.abs(length)/labelSize); 362 // can never have less than 2 tick marks one for each end 363 numOfTickMarks = Math.max(numOfTickMarks, 2); 364 // calculate tick unit for the number of ticks can have in the given data range 365 double tickUnit = paddedRange/(double)numOfTickMarks; 366 // search for the best tick unit that fits 367 double tickUnitRounded = 0; 368 double minRounded = 0; 369 double maxRounded = 0; 370 int count = 0; 371 double reqLength = Double.MAX_VALUE; 372 int rangeIndex = 10; 373 // loop till we find a set of ticks that fit length and result in a total of less than 20 tick marks 374 while (reqLength > length || count > 20) { 375 // find a user friendly match from our default tick units to match calculated tick unit 376 for (int i=0; i<TICK_UNIT_DEFAULTS.length; i++) { 377 double tickUnitDefault = TICK_UNIT_DEFAULTS[i]; 378 if (tickUnitDefault > tickUnit) { 379 tickUnitRounded = tickUnitDefault; 380 rangeIndex = i; 381 break; 382 } 383 } 384 // move min and max to nearest tick mark 385 minRounded = Math.floor(paddedMin / tickUnitRounded) * tickUnitRounded; 386 maxRounded = Math.ceil(paddedMax / tickUnitRounded) * tickUnitRounded; 387 // calculate the required length to display the chosen tick marks for real, this will handle if there are 388 // huge numbers involved etc or special formatting of the tick mark label text 389 double maxReqTickGap = 0; 390 double last = 0; 391 count = 0; 392 for (double major = minRounded; major <= maxRounded; major += tickUnitRounded, count ++) { 393 double size = (vertical) ? measureTickMarkSize((Double)major, getTickLabelRotation(), rangeIndex).getHeight() : 394 measureTickMarkSize((Double)major, getTickLabelRotation(), rangeIndex).getWidth(); 395 if (major == minRounded) { // first 396 last = size/2; 397 } else { 398 maxReqTickGap = Math.max(maxReqTickGap, last + 6 + (size/2) ); 399 } 400 } 401 reqLength = (count-1) * maxReqTickGap; 402 tickUnit = tickUnitRounded; 403 // check if we already found max tick unit 404 if (tickUnitRounded == TICK_UNIT_DEFAULTS[TICK_UNIT_DEFAULTS.length-1]) { 405 // nothing we can do so just have to use this 406 break; 407 } 408 } 409 // calculate new scale 410 final double newScale = calculateNewScale(length, minRounded, maxRounded); 411 // return new range 412 return new double[]{minRounded, maxRounded, tickUnitRounded, newScale, rangeIndex}; 413 } 414 415 // -------------- STYLESHEET HANDLING ------------------------------------------------------------------------------ 416 417 /** @treatAsPrivate implementation detail */ 418 private static class StyleableProperties { 419 private static final CssMetaData<NumberAxis,Number> TICK_UNIT = 420 new CssMetaData<NumberAxis,Number>("-fx-tick-unit", 421 SizeConverter.getInstance(), 5.0) { 422 423 @Override 424 public boolean isSettable(NumberAxis n) { 425 return n.tickUnit == null || !n.tickUnit.isBound(); 426 } 427 428 @Override 429 public StyleableProperty<Number> getStyleableProperty(NumberAxis n) { 430 return (StyleableProperty<Number>)n.tickUnitProperty(); 431 } 432 }; 433 434 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 435 static { 436 final List<CssMetaData<? extends Styleable, ?>> styleables = 437 new ArrayList<CssMetaData<? extends Styleable, ?>>(ValueAxis.getClassCssMetaData()); 438 styleables.add(TICK_UNIT); 439 STYLEABLES = Collections.unmodifiableList(styleables); 440 } 441 } 442 443 /** 444 * @return The CssMetaData associated with this class, which may include the 445 * CssMetaData of its super classes. 446 */ 447 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 448 return StyleableProperties.STYLEABLES; 449 } 450 451 /** 452 * {@inheritDoc} 453 */ 454 @Override 455 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 456 return getClassCssMetaData(); 457 } 458 459 // -------------- INNER CLASSES ------------------------------------------------------------------------------------ 460 461 /** 462 * Default number formatter for NumberAxis, this stays in sync with auto-ranging and formats values appropriately. 463 * You can wrap this formatter to add prefixes or suffixes; 464 */ 465 public static class DefaultFormatter extends StringConverter<Number> { 466 private DecimalFormat formatter; 467 private String prefix = null; 468 private String suffix = null; 469 470 /** used internally */ 471 private DefaultFormatter() {} 472 473 /** 474 * Construct a DefaultFormatter for the given NumberAxis 475 * 476 * @param axis The axis to format tick marks for 477 */ 478 public DefaultFormatter(final NumberAxis axis) { 479 formatter = getFormatter(axis.isAutoRanging()? axis.currentRangeIndexProperty.get() : -1); 480 final ChangeListener axisListener = new ChangeListener() { 481 @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { 482 formatter = getFormatter(axis.isAutoRanging()? axis.currentRangeIndexProperty.get() : -1); 483 } 484 }; 485 axis.currentRangeIndexProperty.addListener(axisListener); 486 axis.autoRangingProperty().addListener(axisListener); 487 } 488 489 /** 490 * Construct a DefaultFormatter for the given NumberAxis with a prefix and/or suffix. 491 * 492 * @param axis The axis to format tick marks for 493 * @param prefix The prefix to append to the start of formatted number, can be null if not needed 494 * @param suffix The suffix to append to the end of formatted number, can be null if not needed 495 */ 496 public DefaultFormatter(NumberAxis axis, String prefix, String suffix) { 497 this(axis); 498 this.prefix = prefix; 499 this.suffix = suffix; 500 } 501 502 private static DecimalFormat getFormatter(int rangeIndex) { 503 if (rangeIndex < 0) { 504 return new DecimalFormat(); 505 } else if(rangeIndex >= TICK_UNIT_FORMATTER_DEFAULTS.length) { 506 return new DecimalFormat(TICK_UNIT_FORMATTER_DEFAULTS[TICK_UNIT_FORMATTER_DEFAULTS.length-1]); 507 } else { 508 return new DecimalFormat(TICK_UNIT_FORMATTER_DEFAULTS[rangeIndex]); 509 } 510 } 511 512 /** 513 * Converts the object provided into its string form. 514 * Format of the returned string is defined by this converter. 515 * @return a string representation of the object passed in. 516 * @see StringConverter#toString 517 */ 518 @Override public String toString(Number object) { 519 return toString(object, formatter); 520 } 521 522 private String toString(Number object, int rangeIndex) { 523 return toString(object, getFormatter(rangeIndex)); 524 } 525 526 private String toString(Number object, DecimalFormat formatter) { 527 if (prefix != null && suffix != null) { 528 return prefix + formatter.format(object) + suffix; 529 } else if (prefix != null) { 530 return prefix + formatter.format(object); 531 } else if (suffix != null) { 532 return formatter.format(object) + suffix; 533 } else { 534 return formatter.format(object); 535 } 536 } 537 538 /** 539 * Converts the string provided into a Number defined by the this converter. 540 * Format of the string and type of the resulting object is defined by this converter. 541 * @return a Number representation of the string passed in. 542 * @see StringConverter#toString 543 */ 544 @Override public Number fromString(String string) { 545 try { 546 int prefixLength = (prefix == null)? 0: prefix.length(); 547 int suffixLength = (suffix == null)? 0: suffix.length(); 548 return formatter.parse(string.substring(prefixLength, string.length() - suffixLength)); 549 } catch (ParseException e) { 550 return null; 551 } 552 } 553 } 554 555} 556 557/* 558 // Code to generate tick unit defaults 559 560 public static void main(String[] args) { 561 List<BigDecimal> values = new ArrayList<BigDecimal>(); 562 List<String> formats = new ArrayList<String>(); 563 for(int power=-10; power <= 12; power ++) { 564 BigDecimal val = new BigDecimal(10); 565 val = val.pow(power, MathContext.DECIMAL32); 566 BigDecimal val2 = val.multiply(new BigDecimal(2.5d)); 567 BigDecimal val5 = val.multiply(new BigDecimal(5d)); 568 values.add(val); 569 values.add(val2); 570 values.add(val5); 571 System.out.print("["+power+"] "); 572 System.out.print( 573 val.doubleValue() + "d, " + 574 val2.doubleValue() + "d, " + 575 val5.doubleValue() + "d, " 576 ); 577 DecimalFormat df = null; 578 DecimalFormat dfTwoHalf = null; 579 if (power < 0) { 580 String nf = "0."; 581 for (int i=0; i<Math.abs(power); i++) nf = nf+"0"; 582 System.out.print(" --- nf = " + nf); 583 String nf2 = "0."; 584 for (int i=0; i<=Math.abs(power); i++) nf2 = nf2+"0"; 585 System.out.print(" --- nf2 = " + nf2); 586 df = new DecimalFormat(nf); 587 dfTwoHalf = new DecimalFormat(nf2); 588 formats.add(nf); 589 formats.add(nf2); 590 formats.add(nf); 591 } else if (power == 0) { 592 df = new DecimalFormat("0"); 593 dfTwoHalf = new DecimalFormat("0.0"); 594 formats.add("0"); 595 formats.add("0.0"); 596 formats.add("0"); 597 } else { 598 String nf = "0"; 599 for (int i=0; i<Math.abs(power); i++) { 600 if((i % 3) == 2) { 601 nf = "#," + nf; 602 } else { 603 nf = "#" + nf; 604 } 605 } 606 System.out.print(" --- nf = " + nf); 607 formats.add(nf); 608 formats.add(nf); 609 formats.add(nf); 610 dfTwoHalf = df = new DecimalFormat(nf); 611 } 612 System.out.println(" --- "+ 613 df.format(val.doubleValue())+", "+ 614 dfTwoHalf.format(val2.doubleValue())+", "+ 615 df.format(val5.doubleValue())+", " 616 ); 617 } 618 System.out.print(" private static final double[] TICK_UNIT_DEFAULTS = { "); 619 for(BigDecimal val: values) System.out.print(val.doubleValue()+", "); 620 System.out.println(" };"); 621 System.out.print(" private static final String[] TICK_UNIT_FORMATTER_DEFAULTS = { "); 622 for(String format: formats) System.out.print("\""+format+"\", "); 623 System.out.println(" };"); 624 } 625*/