1 23 24 package info.monitorenter.gui.chart; 25 26 import info.monitorenter.gui.chart.labelformatters.ALabelFormatter; 27 import info.monitorenter.gui.chart.labelformatters.LabelFormatterAutoUnits; 28 import info.monitorenter.gui.chart.labelformatters.LabelFormatterSimple; 29 import info.monitorenter.gui.chart.rangepolicies.ARangePolicy; 30 import info.monitorenter.gui.chart.rangepolicies.RangePolicyUnbounded; 31 import info.monitorenter.util.Range; 32 33 import java.awt.Dimension ; 34 import java.awt.FontMetrics ; 35 import java.awt.event.MouseEvent ; 36 import java.beans.PropertyChangeEvent ; 37 import java.beans.PropertyChangeListener ; 38 import java.beans.PropertyChangeSupport ; 39 import java.util.LinkedList ; 40 41 56 public abstract class AAxis implements IAxis { 57 58 59 private PropertyChangeSupport m_propertyChangeSupport; 60 61 62 private boolean m_paintGrid = false; 63 64 70 public final boolean isPaintGrid() { 71 return this.m_paintGrid; 72 } 73 74 83 public final void setPaintGrid(final boolean grid) { 84 boolean oldValue = this.m_paintGrid; 85 this.m_paintGrid = grid; 86 if (oldValue != grid) { 87 88 Chart2D chart2D = this.getAccessor().getChart(); 89 if (grid) { 90 this.setPaintScale(true); 92 } 93 this.m_propertyChangeSupport.firePropertyChange(new PropertyChangeEvent (this, 94 IAxis.PROPERTY_PAINTGRID, new Boolean (oldValue), new Boolean (this.m_paintGrid))); 95 chart2D.repaint(200); 96 } 97 } 98 99 100 private boolean m_paintScale = true; 101 102 109 public final void setPaintScale(final boolean show) { 110 this.m_paintScale = show; 111 } 112 113 129 protected abstract double translateMousePosition(final MouseEvent mouseEvent); 130 131 146 protected abstract double getScaledValue(final double absolute); 147 148 161 public abstract class Chart2DDataAccessor { 162 163 178 public abstract double translateMousePosition(final MouseEvent mouseEvent); 179 180 181 protected Chart2D m_chart; 182 183 194 protected abstract int getPixelRange(); 195 196 199 protected IRangePolicy m_rangePolicy = new RangePolicyUnbounded(Range.RANGE_UNBOUNDED); 200 201 208 protected Chart2DDataAccessor(final Chart2D chart) { 209 210 AAxis.this.setAccessor(this); 211 this.m_chart = chart; 212 this.m_rangePolicy.addPropertyChangeListener(ARangePolicy.PROPERTY_RANGE, chart); 213 } 214 215 221 public final Chart2D getChart() { 222 return this.m_chart; 223 } 224 225 233 protected abstract double getMax(); 234 235 240 protected abstract double getMaxFromAxis(); 241 242 248 protected abstract double getMaximumPixelForLable(); 249 250 256 protected abstract double getMin(); 257 258 263 protected abstract double getMinFromAxis(); 264 265 280 protected abstract double getMinimumValueDistanceForLables(); 281 282 285 public final IRangePolicy getRangePolicy() { 286 287 return this.m_rangePolicy; 288 } 289 290 314 protected abstract double getValueDistanceForPixel(int pixel); 315 316 326 public void setRangePolicy(final IRangePolicy rangePolicy) { 327 328 rangePolicy.setRange(new Range(this.getMinFromAxis(), this.getMaxFromAxis())); 331 this.m_rangePolicy.removePropertyChangeListener(this.m_chart); 332 this.m_rangePolicy = rangePolicy; 333 this.m_rangePolicy.addPropertyChangeListener(ARangePolicy.PROPERTY_RANGE, this.m_chart); 334 this.m_rangePolicy.addPropertyChangeListener(ARangePolicy.PROPERTY_RANGE_MAX, this.m_chart); 335 this.m_rangePolicy.addPropertyChangeListener(ARangePolicy.PROPERTY_RANGE_MIN, this.m_chart); 336 } 337 } 338 339 348 public final class XDataAccessor extends AAxis.Chart2DDataAccessor { 349 350 353 public double translateMousePosition(final MouseEvent mouseEvent) { 354 double result = 0; 355 double mouseX = mouseEvent.getX() - this.m_chart.getXChartStart(); 357 358 int rangeX = this.m_chart.getXChartEnd() - this.m_chart.getXChartStart(); 359 if (rangeX == 0) { 360 } else { 362 double scaledX = mouseX / (double) rangeX; 363 Range valueRangeX = AAxis.this.getRange(); 364 result = scaledX * valueRangeX.getExtent() + valueRangeX.getMin(); 365 } 366 return result; 367 } 368 369 372 protected int getPixelRange() { 373 return this.m_chart.getXChartEnd() - this.m_chart.getXChartStart(); 374 } 375 376 383 public XDataAccessor(final Chart2D chart) { 384 385 super(chart); 386 } 387 388 391 protected double getMax() { 392 return this.m_rangePolicy.getMax(this.m_chart.getMinX(), this.m_chart.getMaxX()); 393 } 394 395 398 protected final double getMaxFromAxis() { 399 400 return m_chart.getMaxX(); 401 } 402 403 406 protected double getMaximumPixelForLable() { 407 408 FontMetrics fontdim = m_chart.getGraphics().getFontMetrics(); 409 int fontwidth = fontdim.charWidth('0'); 410 415 int len = AAxis.this.getFormatter().getMaxAmountChars(); 416 return fontwidth * (len + 2); 417 } 418 419 422 protected final double getMin() { 423 return this.m_rangePolicy.getMin(this.m_chart.getMinX(), this.m_chart.getMaxX()); 424 } 425 426 429 protected final double getMinFromAxis() { 430 431 return m_chart.getMinX(); 432 } 433 434 437 protected final double getMinimumValueDistanceForLables() { 438 439 Dimension d = this.m_chart.getSize(); 440 int pxrange = (int) d.getWidth() - 60; 441 if (pxrange <= 0) { 442 return 1; 443 } 444 double valuerange = AAxis.this.getMax() - AAxis.this.getMin(); 445 if (valuerange == 0) { 446 valuerange = 10; 447 } 448 double pxToValue = valuerange / pxrange; 449 double ret = pxToValue * this.getMaximumPixelForLable(); 450 return ret; 451 } 452 453 456 protected double getValueDistanceForPixel(final int pixel) { 457 Dimension d = this.m_chart.getSize(); 458 int pxrangex = (int) d.getWidth() - 60; 459 if (pxrangex <= 0) { 460 return -1d; 461 } 462 double valuerangex = this.getMax() - this.getMin(); 463 double pxToValue = valuerangex / pxrangex; 464 double ret = pxToValue * pixel; 465 return ret; 466 } 467 468 471 public void setRangePolicy(final IRangePolicy rangePolicy) { 472 473 double xmax = this.getMax(); 474 double xmin = this.getMin(); 475 super.setRangePolicy(rangePolicy); 476 if (xmax != this.getMax() || xmin != this.getMin()) { 478 this.m_chart.propertyChange(new PropertyChangeEvent (rangePolicy, 479 ARangePolicy.PROPERTY_RANGE, new Range(xmin, xmax), this.m_rangePolicy.getRange())); 480 } 481 } 482 483 489 public String toString() { 490 return "X"; 491 } 492 } 493 494 502 503 public final class YDataAccessor extends AAxis.Chart2DDataAccessor { 504 505 512 public YDataAccessor(final Chart2D chart) { 513 514 super(chart); 515 } 516 517 520 protected int getPixelRange() { 521 return this.m_chart.getYChartStart() - this.m_chart.getYChartEnd(); 522 } 523 524 527 protected final double getMax() { 528 return this.m_rangePolicy.getMax(this.m_chart.getMinY(), this.m_chart.getMaxY()); 529 } 530 531 534 protected final double getMaxFromAxis() { 535 536 return m_chart.getMaxY(); 537 } 538 539 542 protected double getMaximumPixelForLable() { 543 544 FontMetrics fontdim = m_chart.getGraphics().getFontMetrics(); 545 int fontheight = fontdim.getHeight(); 546 return fontheight + 10; 547 } 548 549 552 protected final double getMin() { 553 return this.m_rangePolicy.getMin(this.m_chart.getMinY(), this.m_chart.getMaxY()); 554 } 555 556 559 protected final double getMinFromAxis() { 560 561 return m_chart.getMinY(); 562 } 563 564 567 protected final double getMinimumValueDistanceForLables() { 568 569 Dimension d = this.m_chart.getSize(); 570 int pxrange = (int) d.getHeight() - 40; 571 if (pxrange <= 0) { 572 return 1; 573 } 574 double valuerange = AAxis.this.getMax() - AAxis.this.getMin(); 575 if (valuerange == 0) { 576 valuerange = 10; 577 } 578 double pxToValue = valuerange / pxrange; 579 double ret = pxToValue * this.getMaximumPixelForLable(); 580 return ret; 581 } 582 583 586 protected double getValueDistanceForPixel(final int pixel) { 587 Dimension d = this.m_chart.getSize(); 588 int pxrangey = (int) d.getHeight() - 40; 589 if (pxrangey <= 0) { 590 return -1d; 591 } 592 double valuerangey = this.getMaxFromAxis() - this.getMinFromAxis(); 593 double pxToValue = valuerangey / pxrangey; 594 double ret = pxToValue * pixel; 595 return ret; 596 } 597 598 601 public void setRangePolicy(final IRangePolicy rangePolicy) { 602 double ymax = this.getMax(); 603 double ymin = this.getMin(); 604 super.setRangePolicy(rangePolicy); 605 if (ymax != this.getMax() || ymin != this.getMin()) { 607 this.m_chart.propertyChange(new PropertyChangeEvent (rangePolicy, 608 ARangePolicy.PROPERTY_RANGE, new Range(ymin, ymax), this.m_rangePolicy.getRange())); 609 } 610 } 611 612 618 public String toString() { 619 return "Y"; 620 } 621 622 625 public double translateMousePosition(final MouseEvent mouseEvent) { 626 double result = 0; 627 double mouseY = this.m_chart.getYChartStart() - mouseEvent.getY(); 629 630 int rangeY = this.m_chart.getYChartStart() - this.m_chart.getYChartEnd(); 631 if (rangeY == 0) { 632 } else { 634 double scaledY = mouseY / (double) rangeY; 635 Range valueRangeY = AAxis.this.getRange(); 636 result = scaledY * valueRangeY.getExtent() + valueRangeY.getMin(); 637 } 638 return result; 639 } 640 } 641 642 643 private static final boolean DEBUG = false; 644 645 652 protected Chart2DDataAccessor m_accessor; 653 654 657 protected ILabelFormatter m_formatter; 658 659 665 666 protected double m_majorTickSpacing = 5; 667 668 674 protected double m_minorTickSpacing = 1; 675 676 677 protected double m_power; 678 679 686 private boolean m_startMajorTick = false; 687 688 694 public AAxis() { 695 this(new LabelFormatterAutoUnits(new LabelFormatterSimple())); 696 } 697 698 703 public AAxis(final ALabelFormatter formatter) { 704 this.setFormatter(formatter); 705 this.m_propertyChangeSupport = new PropertyChangeSupport (this); 706 } 707 708 712 public void addPropertyChangeListener(final String propertyName, 713 final PropertyChangeListener listener) { 714 this.m_propertyChangeSupport.addPropertyChangeListener(propertyName, listener); 715 } 716 717 723 public Chart2DDataAccessor getAccessor() { 724 return this.m_accessor; 725 } 726 727 730 public final ILabelFormatter getFormatter() { 731 732 return this.m_formatter; 733 } 734 735 738 protected LabeledValue[] getLabels(final double resolution) { 739 if (resolution <= 0) { 740 return new LabeledValue[] {}; 741 } 742 LinkedList collect = new LinkedList (); 743 Range domain = this.getRange(); 744 double min = domain.getMin(); 745 double max = domain.getMax(); 746 String oldLabelName = ""; 747 LabeledValue label; 748 double range = max - min; 749 LabeledValue[] ret = null; 750 double value = min; 751 String labelName = "start"; 752 int loopStop = 0; 753 boolean firstMajorFound = false; 754 while (value <= max && loopStop < 100) { 756 if (loopStop == 99) { 757 if (AAxis.DEBUG) { 758 System.out.println(this.m_accessor.toString() + " axis: loop to high"); 759 } 760 } 761 if (oldLabelName.equals(labelName)) { 762 if (AAxis.DEBUG) { 763 System.out.println("constant Label"); 764 } 765 } 766 label = this.roundToTicks(value, false, !firstMajorFound && this.m_startMajorTick); 767 768 oldLabelName = labelName; 769 labelName = label.m_label; 770 value = label.m_value; 771 772 loopStop++; 773 if (firstMajorFound || !this.m_startMajorTick || label.isMajorTick()) { 774 firstMajorFound = true; 775 if (value <= max) { 776 collect.add(label); 777 } else { 778 } 781 } 782 value += resolution; 783 } 784 int stop = collect.size(); 785 786 ret = new LabeledValue[stop]; 787 for (int i = 0; i < stop; i++) { 788 label = (LabeledValue) collect.get(i); 789 label.m_value = (label.m_value - min) / range; 790 ret[i] = label; 791 } 792 return ret; 793 } 794 795 802 803 public double getMajorTickSpacing() { 804 return this.m_majorTickSpacing; 805 } 806 807 819 public double getMax() { 820 return this.m_accessor.getMax(); 821 } 822 823 835 public double getMin() { 836 837 return this.m_accessor.getMin(); 838 839 } 840 841 850 public double getMinorTickSpacing() { 851 return this.m_minorTickSpacing; 852 } 853 854 869 public final Range getRange() { 870 Range result; 871 double min = this.getMin(); 872 double max = this.getMax(); 873 if (min == max) { 874 max += 10; 875 } 876 result = new Range(min, max); 877 return result; 878 } 879 880 887 public IRangePolicy getRangePolicy() { 888 889 return this.m_accessor.getRangePolicy(); 890 } 891 892 900 protected LabeledValue[] getScaleValues() { 901 double labelspacepx = this.m_accessor.getMinimumValueDistanceForLables(); 902 double formattingspace = this.m_formatter.getMinimumValueShiftForChange(); 903 double max = Math.max(labelspacepx, formattingspace); 904 return this.getLabels(max); 905 } 906 907 931 protected final double getValueDistanceForPixel(final int pixel) { 932 return this.m_accessor.getValueDistanceForPixel(pixel); 933 } 934 935 950 protected void initPaintIteration() { 951 952 double range = this.getMax() - this.getMin(); 957 if (range == 0 || range == Double.NEGATIVE_INFINITY || range == Double.POSITIVE_INFINITY) { 958 range = 1; 959 } 960 double tmpPower = 0; 961 if (range > 1) { 962 while (range > 10) { 963 range /= 10; 964 tmpPower++; 965 } 966 tmpPower = Math.pow(10, tmpPower - 1); 967 } else { 968 while (range < 1) { 969 range *= 10; 970 tmpPower++; 971 } 972 973 tmpPower = 1 / Math.pow(10, tmpPower); 974 } 975 this.m_power = tmpPower; 976 977 this.m_formatter.initPaintIteration(); 980 } 981 982 990 public boolean isStartMajorTick() { 991 return this.m_startMajorTick; 992 } 993 994 1018 protected LabeledValue roundToTicks(final double value, final boolean floor, 1019 final boolean findMajorTick) { 1020 LabeledValue ret = new LabeledValue(); 1021 1022 double minorTick = this.m_minorTickSpacing * this.m_power; 1023 double majorTick = this.m_majorTickSpacing * this.m_power; 1024 1025 double majorRound; 1026 1027 if (floor) { 1028 majorRound = Math.floor(value / majorTick); 1029 } else { 1030 majorRound = Math.ceil(value / majorTick); 1031 } 1032 boolean majorZeroHit = majorRound == 0 && value != 0; 1033 majorRound *= majorTick; 1034 double minorRound; 1035 if (floor) { 1036 minorRound = Math.floor(value / minorTick); 1037 } else { 1038 minorRound = Math.ceil(value / minorTick); 1039 } 1040 boolean minorZeroHit = minorRound == 0 && value != 0; 1041 minorRound *= minorTick; 1042 if (majorZeroHit || minorZeroHit) { 1043 if (AAxis.DEBUG) { 1044 System.out.println("zeroHit"); 1045 } 1046 } 1047 1048 double minorDistance = Math.abs(value - minorRound); 1049 double majorDistance = Math.abs(value - majorRound); 1050 1051 double majorMinorRelation = minorDistance / majorDistance; 1052 if (majorMinorRelation == Double.NaN) { 1053 majorMinorRelation = 1.0; 1054 } 1055 1056 if (majorDistance <= minorDistance || findMajorTick) { 1057 ret.m_value = majorRound; 1058 ret.m_isMajorTick = true; 1059 } else { 1060 ret.m_value = minorRound; 1061 ret.m_isMajorTick = false; 1062 } 1063 1064 ret.m_label = this.getFormatter().format(ret.m_value); 1066 ret.m_value = this.getFormatter().parse(ret.m_label).doubleValue(); 1070 return ret; 1071 } 1072 1073 1080 protected final void setAccessor(final Chart2DDataAccessor accessor) { 1081 1082 this.m_accessor = accessor; 1083 } 1084 1085 1092 public void setFormatter(final ALabelFormatter formatter) { 1093 1094 this.m_formatter = formatter; 1095 this.m_formatter.setAxis(this); 1096 } 1097 1098 1127 public void setMajorTickSpacing(final double majorTickSpacing) { 1128 this.m_majorTickSpacing = majorTickSpacing; 1129 } 1130 1131 1160 public void setMinorTickSpacing(final double minorTickSpacing) { 1161 this.m_minorTickSpacing = minorTickSpacing; 1162 } 1163 1164 1181 public final void setRange(final Range range) { 1182 1183 this.m_accessor.getRangePolicy().setRange(range); 1184 } 1185 1186 1204 public void setRangePolicy(final IRangePolicy rangePolicy) { 1205 1206 IRangePolicy old = this.m_accessor.getRangePolicy(); 1207 this.m_accessor.setRangePolicy(rangePolicy); 1208 this.m_propertyChangeSupport.firePropertyChange(PROPERTY_RANGEPOLICY, old, rangePolicy); 1209 } 1210 1211 1220 public void setStartMajorTick(final boolean majorTick) { 1221 this.m_startMajorTick = majorTick; 1222 } 1223 1224 1230 public final boolean isPaintScale() { 1231 return this.m_paintScale; 1232 } 1233} 1234 | Popular Tags |