1 22 package info.monitorenter.gui.chart; 23 24 import info.monitorenter.gui.chart.axis.AxisLinear; 25 import info.monitorenter.gui.chart.labelpainters.LabelPainterDefault; 26 import info.monitorenter.gui.chart.rangepolicies.ARangePolicy; 27 import info.monitorenter.util.collections.TreeSetGreedy; 28 29 import java.awt.Color ; 30 import java.awt.Cursor ; 31 import java.awt.Dimension ; 32 import java.awt.Font ; 33 import java.awt.FontMetrics ; 34 import java.awt.Graphics ; 35 import java.awt.Graphics2D ; 36 import java.awt.Stroke ; 37 import java.awt.event.MouseEvent ; 38 import java.awt.image.BufferedImage ; 39 import java.beans.PropertyChangeEvent ; 40 import java.beans.PropertyChangeListener ; 41 import java.util.Iterator ; 42 import java.util.LinkedList ; 43 import java.util.List ; 44 import java.util.Set ; 45 46 import javax.swing.JPanel ; 47 import javax.swing.JToolTip ; 48 import javax.swing.SwingUtilities ; 49 50 183 184 public class Chart2D extends JPanel implements PropertyChangeListener { 185 186 203 class Painter extends Thread { 204 205 static final long MAX_SLEEP = 10000; 206 207 208 static final long MIN_SLEEP = 100; 209 210 213 private long m_sleepTime = Chart2D.Painter.MIN_SLEEP; 214 215 218 public void run() { 219 try { 220 while (!this.isInterrupted()) { 221 sleep(this.m_sleepTime); 222 if (Chart2D.DEBUG_THREADING) { 227 System.out.println("Painter, 0 locks"); 228 } 229 230 synchronized (Chart2D.this) { 231 if (Chart2D.DEBUG_THREADING) { 232 System.out.println("Painter, 1 lock"); 233 } 234 if (!Chart2D.this.isDirtyScaling() || Chart2D.this.m_unscaledPoints.size() == 0) { 235 if (this.m_sleepTime < Chart2D.Painter.MAX_SLEEP) { 237 this.m_sleepTime += 10; 238 } 239 } else { 240 this.m_sleepTime = Math.max(this.m_sleepTime 242 - (Chart2D.this.m_unscaledPoints.size() * 2), Chart2D.Painter.MIN_SLEEP); 243 repaint(); 244 } 245 } 246 if (Chart2D.DEBUG_THREADING) { 247 System.out.println("Painter, left lock"); 248 } 249 } 250 251 } catch (InterruptedException ie) { 252 256 257 } 258 } 259 } 260 261 265 protected static final boolean DEBUG_SCALING = false; 266 267 271 public static final boolean DEBUG_THREADING = false; 272 273 283 public static final String PROPERTY_ADD_REMOVE_TRACE = "chart.addTrace"; 284 285 295 public static final String PROPERTY_AXIS_X = "chart.axis.x"; 296 297 307 public static final String PROPERTY_AXIS_Y = "chart.axis.y"; 308 309 320 public static final String PROPERTY_BACKGROUND_COLOR = "background"; 321 322 335 public static final String PROPERTY_FONT = "font"; 336 337 348 public static final String PROPERTY_FOREGROUND_COLOR = "foreground"; 349 350 358 public static final String PROPERTY_GRID_COLOR = "chart.gridColor"; 359 360 368 public static final String PROPERTY_PAINTLABELS = "chart.paintLabels"; 369 370 373 private static final long serialVersionUID = 3978425840633852978L; 374 375 376 public static final int X = 1; 377 378 379 public static final int X_Y = 3; 380 381 382 public static final int Y = 2; 383 384 385 private AAxis m_axisX; 386 387 388 private AAxis m_axisY; 389 390 391 private Color m_gridcolor = Color.lightGray; 392 393 396 private ILabelPainter m_labelPainter; 397 398 399 private Painter m_painter = new Painter(); 400 401 404 private boolean m_paintLabels = true; 405 406 407 private boolean m_toolTipCoords = true; 408 409 413 private TreeSetGreedy m_traces = new TreeSetGreedy(); 414 415 426 private List m_unscaledPoints = new LinkedList (); 428 429 432 private int m_xChartEnd; 433 434 437 private int m_xChartStart; 438 439 440 private double m_xmax; 441 442 446 private double m_xmaxold; 447 448 449 private double m_xmin; 450 451 455 private double m_xminold; 456 457 466 private final int m_yChartEnd = 20; 467 468 471 private int m_yChartStart; 472 473 474 private double m_ymax; 475 476 480 private double m_ymaxold; 481 482 483 private double m_ymin; 484 485 489 private double m_yminold; 490 491 495 public Chart2D() { 496 this.setAxisX(new AxisLinear()); 497 this.setAxisY(new AxisLinear()); 498 this.setLabelPainter(new LabelPainterDefault()); 499 500 Font dflt = this.getFont(); 501 if (dflt != null) { 502 this.setFont(new Font (dflt.getFontName(), dflt.getStyle(), 10)); 503 } 504 this.getBackground(); 505 this.setBackground(Color.white); 506 this.repaint(); 509 this.m_painter.setDaemon(true); 511 this.m_painter.start(); 512 513 this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 515 516 this.setToolTipCoords(true); 518 } 519 520 533 public final void addTrace(final ITrace2D points) { 534 if (Chart2D.DEBUG_THREADING) { 535 System.out.println("trace.addTrace, 0 locks"); 536 } 537 synchronized (this) { 538 if (Chart2D.DEBUG_THREADING) { 539 System.out.println("trace.addTrace, 1 lock"); 540 } 541 synchronized (points) { 542 if (Chart2D.DEBUG_THREADING) { 543 System.out.println("trace.addTrace, 2 locks"); 544 } 545 546 points.setRenderer(this); 547 this.m_traces.add(points); 548 points.addPropertyChangeListener(ITrace2D.PROPERTY_MAX_X, this); 550 points.addPropertyChangeListener(ITrace2D.PROPERTY_MIN_X, this); 551 points.addPropertyChangeListener(ITrace2D.PROPERTY_MAX_Y, this); 552 points.addPropertyChangeListener(ITrace2D.PROPERTY_MIN_Y, this); 553 points.addPropertyChangeListener(ITrace2D.PROPERTY_COLOR, this); 555 points.addPropertyChangeListener(ITrace2D.PROPERTY_STROKE, this); 556 points.addPropertyChangeListener(ITrace2D.PROPERTY_VISIBLE, this); 557 points.addPropertyChangeListener(ITrace2D.PROPERTY_ZINDEX, this); 558 points.addPropertyChangeListener(ITrace2D.PROPERTY_PAINTERS, this); 559 points.addPropertyChangeListener(ITrace2D.PROPERTY_TRACEPOINT, this); 563 564 boolean change = false; 567 double maxX = points.getMaxX(); 568 if (maxX > this.m_xmax) { 569 this.m_xmax = maxX; 570 change = true; 571 } 572 double maxY = points.getMaxY(); 573 if (maxY > this.m_ymax) { 574 this.m_ymax = maxY; 575 change = true; 576 } 577 double minX = points.getMinX(); 578 if (minX < this.m_xmin) { 579 this.m_xmin = minX; 580 change = true; 581 } 582 double minY = points.getMinY(); 583 if (minY < this.m_ymin) { 584 this.m_ymin = minY; 585 change = true; 586 } 587 588 if (!change) { 593 this.scaleTrace(points, Chart2D.X_Y); 594 } 595 if (this.m_traces.size() == 1) { 597 this.m_ymin = minY; 598 this.m_ymax = maxY; 599 this.m_xmin = minX; 600 this.m_xmax = maxX; 601 } 602 603 } 604 if (Chart2D.DEBUG_THREADING) { 605 System.out.println("trace.addTrace, left 1 lock: 1 remaining"); 606 } 607 } 608 if (Chart2D.DEBUG_THREADING) { 609 System.out.println("trace.addTrace, left 1 lock: 0 remaining"); 610 } 611 SwingUtilities.invokeLater(new Runnable () { 614 public void run() { 615 Chart2D.this.firePropertyChange(Chart2D.PROPERTY_ADD_REMOVE_TRACE, null, points); 616 } 617 }); 618 } 619 620 623 public JToolTip createToolTip() { 624 629 JToolTip result = super.createToolTip(); 630 return result; 631 } 632 633 641 public void destroy() { 642 if (Chart2D.DEBUG_THREADING) { 643 System.out.println("destroy, 0 locks"); 644 } 645 synchronized (this) { 646 if (Chart2D.DEBUG_THREADING) { 647 System.out.println("destroy, 1 lock"); 648 } 649 this.m_axisX = null; 650 this.m_axisY = null; 651 this.m_traces = null; 652 this.m_unscaledPoints = null; 653 this.m_painter.interrupt(); 654 this.m_painter = null; 655 } 656 } 657 658 668 public void finalize() throws Throwable { 669 super.finalize(); 670 this.destroy(); 671 } 672 673 691 protected final double findMaxX() { 692 double max = -Double.MAX_VALUE, tmp; 693 Iterator it = this.m_traces.iterator(); 694 ITrace2D trace; 695 while (it.hasNext()) { 696 trace = (ITrace2D) it.next(); 697 if (trace.isVisible()) { 698 tmp = trace.getMaxX(); 699 if (tmp > max) { 700 max = tmp; 701 } 702 } 703 } 704 if (max == -Double.MAX_VALUE) { 705 max = 10; 706 } 707 return max; 708 } 709 710 725 protected final double findMaxY() { 726 double max = -Double.MAX_VALUE, tmp; 727 Iterator it = this.m_traces.iterator(); 728 ITrace2D trace; 729 while (it.hasNext()) { 730 trace = (ITrace2D) it.next(); 731 if (trace.isVisible()) { 732 tmp = trace.getMaxY(); 733 if (tmp > max) { 734 max = tmp; 735 } 736 } 737 } 738 if (max == -Double.MAX_VALUE) { 739 max = 10; 740 } 741 return max; 742 } 743 744 759 760 protected final double findMinX() { 761 double min = Double.MAX_VALUE, tmp; 762 Iterator it = this.m_traces.iterator(); 763 ITrace2D trace; 764 while (it.hasNext()) { 765 trace = (ITrace2D) it.next(); 766 if (trace.isVisible()) { 767 tmp = trace.getMinX(); 768 if (tmp < min) { 769 min = tmp; 770 } 771 } 772 } 773 if (min == Double.MAX_VALUE) { 774 min = 0; 775 } 776 return min; 777 } 778 779 794 795 protected final double findMinY() { 796 double min = Double.MAX_VALUE, tmp; 797 Iterator it = this.m_traces.iterator(); 798 ITrace2D trace; 799 while (it.hasNext()) { 800 trace = (ITrace2D) it.next(); 801 if (trace.isVisible()) { 802 tmp = trace.getMinY(); 803 if (tmp < min) { 804 min = tmp; 805 } 806 } 807 } 808 if (min == Double.MAX_VALUE) { 809 min = 0; 810 } 811 return min; 812 } 813 814 820 public final IAxis getAxisX() { 821 return this.m_axisX; 822 } 823 824 830 public final IAxis getAxisY() { 831 return this.m_axisY; 832 } 833 834 840 public final Color getGridColor() { 841 return this.m_gridcolor; 842 } 843 844 850 public ILabelPainter getLabelPainter() { 851 return this.m_labelPainter; 852 } 853 854 862 public final double getMaxX() { 863 return this.m_xmax; 864 } 865 866 874 public final double getMaxY() { 875 return this.m_ymax; 876 } 877 878 887 public final double getMinX() { 888 return this.m_xmin; 889 } 890 891 899 public final double getMinY() { 900 return this.m_ymin; 901 } 902 903 914 public final double getOffsetX() { 915 return this.m_axisX.getRange().getMin(); 916 } 917 918 921 public String getToolTipText(final MouseEvent event) { 922 if (this.m_toolTipCoords) { 923 TracePoint2D tracePoint = this.translateMousePosition(event); 924 StringBuffer result = new StringBuffer ("X: "); 925 result.append(this.getAxisX().getFormatter().format(tracePoint.getX())).append(" "); 926 result.append("Y: "); 927 result.append(this.getAxisY().getFormatter().format(tracePoint.getY())); 928 return result.toString(); 929 } else { 930 return super.getToolTipText(event); 931 } 932 } 933 934 945 public final Set getTraces() { 946 return this.m_traces; 947 } 948 949 955 protected final int getXChartEnd() { 956 return this.m_xChartEnd; 957 } 958 959 965 public int getXChartStart() { 966 return this.m_xChartStart; 967 } 968 969 980 protected final int getYChartEnd() { 981 return this.m_yChartEnd; 982 } 983 984 994 public int getYChartStart() { 995 return this.m_yChartStart; 996 } 997 998 1014 private TracePoint2D interpolateVisible(final TracePoint2D invisible, final TracePoint2D visible) { 1015 1016 1023 double xInterpolate; 1025 double yInterpolate; 1026 if (invisible.m_scaledX > 1.0) { 1028 xInterpolate = 1.0; 1030 yInterpolate = (visible.m_scaledY - invisible.m_scaledY) 1031 / (visible.m_scaledX - invisible.m_scaledX) * (1.0 - invisible.m_scaledX) 1032 + invisible.m_scaledY; 1033 } else if (invisible.m_scaledX < 0.0) { 1034 xInterpolate = 0.0; 1036 yInterpolate = (visible.m_scaledY - invisible.m_scaledY) 1037 / (visible.m_scaledX - invisible.m_scaledX) * -invisible.m_scaledX + invisible.m_scaledY; 1038 } else if (invisible.m_scaledY > 1.0) { 1039 yInterpolate = 1.0; 1041 xInterpolate = (1.0 - invisible.m_scaledY) * (visible.m_scaledX - invisible.m_scaledX) 1042 / (visible.m_scaledY - invisible.m_scaledY) + invisible.m_scaledX; 1043 } else { 1044 yInterpolate = 0.0; 1046 xInterpolate = -invisible.m_scaledY * (visible.m_scaledX - invisible.m_scaledX) 1047 / (visible.m_scaledY - invisible.m_scaledY) + invisible.m_scaledX; 1048 } 1049 TracePoint2D result = new TracePoint2D(0.0, 0.0); 1051 result.m_scaledOnce = true; 1052 result.m_scaledX = xInterpolate; 1053 result.m_scaledY = yInterpolate; 1054 return result; 1055 } 1056 1057 1067 protected final boolean isDirtyScaling() { 1068 return isDirtyScaling(Chart2D.X) || isDirtyScaling(Chart2D.Y); 1069 } 1070 1071 1084 protected final boolean isDirtyScaling(final int axis) { 1085 boolean result = false; 1086 if (axis == Chart2D.Y) { 1087 result = (this.m_ymax != this.m_ymaxold) || (this.m_ymin != this.m_yminold); 1088 1089 } else if (axis == Chart2D.X) { 1090 result = (this.m_xmax != this.m_xmaxold) || (this.m_xmin != this.m_xminold); 1091 1092 } 1093 return result; 1094 } 1095 1096 1103 public final boolean isPaintLabels() { 1104 return this.m_paintLabels; 1105 } 1106 1107 1113 public final boolean isToolTipCoords() { 1114 return this.m_toolTipCoords; 1115 } 1116 1117 1131 private boolean isVisible(final TracePoint2D point) { 1132 if (point == null) { 1133 return false; 1134 } 1135 return !(point.m_scaledX > 1.0 || point.m_scaledX < 0.0 || point.m_scaledY > 1.0 || point.m_scaledY < 0.0); 1136 } 1137 1138 1145 public final Iterator iterator() { 1146 return this.m_traces.iterator(); 1147 } 1148 1149 1164 public synchronized void paint(final Graphics g) { 1165 if (Chart2D.DEBUG_THREADING) { 1166 System.out.println("paint, 1 lock"); 1167 } 1168 super.paint(g); 1169 Graphics2D g2d = (Graphics2D ) g; 1171 ITrace2D tmpdata; 1173 Iterator traceIt; 1174 ITracePainter tracePainter; 1175 1176 this.updateScaling(false); 1178 Dimension d = this.getSize(); 1179 int width = (int) d.getWidth(); 1180 int height = (int) d.getHeight(); 1181 FontMetrics fontdim = g.getFontMetrics(); 1183 int fontwidth = fontdim.charWidth('0'); 1184 int fontheight = fontdim.getHeight(); 1185 int yLabelMax = (this.m_axisY.getFormatter().getMaxAmountChars()) * fontwidth; 1186 this.m_xChartStart = yLabelMax; 1187 int labelheight = this.paintTraceLables(g2d); 1189 1190 this.m_yChartStart = height - fontheight - labelheight - 4; 1193 1194 int xLabelMax = (this.m_axisX.getFormatter().getMaxAmountChars()) * fontwidth; 1195 this.m_xChartEnd = width - xLabelMax; 1196 int rangex = this.m_xChartEnd - this.m_xChartStart; 1197 int rangey = this.m_yChartStart - this.m_yChartEnd; 1198 1199 this.paintCoordinateSystem(g2d); 1200 1201 int tmpx, oldtmpx, tmpy, oldtmpy; 1203 TracePoint2D oldpoint = null, newpoint = null, tmppt = null; 1204 traceIt = this.m_traces.iterator(); 1205 Stroke backupStroke = g2d.getStroke(); 1206 int count = 0; 1207 Iterator itTracePainters; 1208 while (traceIt.hasNext()) { 1209 count++; 1210 tmpdata = (ITrace2D) traceIt.next(); 1211 if (tmpdata.isVisible()) { 1212 1213 g2d.setStroke(tmpdata.getStroke()); 1214 g2d.setColor(tmpdata.getColor()); 1215 itTracePainters = tmpdata.getTracePainters().iterator(); 1216 synchronized (tmpdata) { 1217 if (Chart2D.DEBUG_THREADING) { 1218 System.out.println("paint, 2 locks"); 1219 } 1220 while (itTracePainters.hasNext()) { 1221 tracePainter = (ITracePainter) itTracePainters.next(); 1222 tracePainter.startPaintIteration(); 1223 Iterator pointIt = tmpdata.iterator(); 1224 boolean newpointVisible, oldpointVisible; 1225 while (pointIt.hasNext()) { 1228 oldpoint = newpoint; 1229 newpoint = (TracePoint2D) pointIt.next(); 1230 1231 newpointVisible = isVisible(newpoint); 1232 oldpointVisible = isVisible(oldpoint); 1233 if (newpointVisible || oldpointVisible) { 1234 tmpx = this.m_xChartStart + (int) (newpoint.m_scaledX * rangex); 1235 tmpy = this.m_yChartStart - (int) (newpoint.m_scaledY * rangey); 1236 while (pointIt.hasNext()) { 1237 oldpoint = newpoint; 1238 oldtmpx = tmpx; 1239 oldtmpy = tmpy; 1240 newpoint = (TracePoint2D) pointIt.next(); 1241 newpointVisible = isVisible(newpoint); 1242 oldpointVisible = isVisible(oldpoint); 1243 if (!newpointVisible && !oldpointVisible) { 1244 continue; 1246 } else if (newpointVisible && !oldpointVisible) { 1247 oldpoint = interpolateVisible(oldpoint, newpoint); 1251 tmpx = this.m_xChartStart + (int) (newpoint.m_scaledX * rangex); 1252 tmpy = this.m_yChartStart - (int) (newpoint.m_scaledY * rangey); 1253 oldtmpx = this.m_xChartStart + (int) (oldpoint.m_scaledX * rangex); 1254 oldtmpy = this.m_yChartStart - (int) (oldpoint.m_scaledY * rangey); 1255 tracePainter.paintPoint(oldtmpx, oldtmpy, tmpx, tmpy, g2d); 1256 1257 } else if (!newpointVisible && oldpointVisible) { 1258 tmppt = (TracePoint2D) newpoint.clone(); 1260 newpoint = interpolateVisible(newpoint, oldpoint); 1261 tmpx = this.m_xChartStart + (int) (newpoint.m_scaledX * rangex); 1262 tmpy = this.m_yChartStart - (int) (newpoint.m_scaledY * rangey); 1263 1264 tracePainter.paintPoint(oldtmpx, oldtmpy, tmpx, tmpy, g2d); 1265 tracePainter.discontinue(); 1266 newpoint = tmppt; 1268 1269 } else { 1270 tmpx = this.m_xChartStart + (int) (newpoint.m_scaledX * rangex); 1272 tmpy = this.m_yChartStart - (int) (newpoint.m_scaledY * rangey); 1273 1274 tracePainter.paintPoint(oldtmpx, oldtmpy, tmpx, tmpy, g2d); 1275 } 1276 } 1277 } 1278 } 1279 tracePainter.endPaintIteration(); 1280 } 1281 1282 } 1283 if (Chart2D.DEBUG_THREADING) { 1284 1285 System.out.println("paint, left lock"); 1286 } 1287 } 1288 } 1289 g2d.setStroke(backupStroke); 1290 } 1291 1292 1303 private void paintCoordinateSystem(final Graphics2D g2d) { 1304 ILabelPainter labelPainter = this.getLabelPainter(); 1305 int rangex = this.m_xChartEnd - this.m_xChartStart; 1306 int rangey = this.m_yChartStart - this.m_yChartEnd; 1307 FontMetrics fontdim = g2d.getFontMetrics(); 1309 int fontheight = fontdim.getHeight(); 1310 1311 g2d.setColor(this.getForeground()); 1313 g2d.drawLine(this.m_xChartStart, this.m_yChartStart, this.m_xChartEnd, this.m_yChartStart); 1314 g2d.drawLine(this.m_xChartStart, this.m_yChartStart, this.m_xChartStart, this.m_yChartEnd); 1315 int tmp; 1317 LabeledValue[] labels; 1318 if (this.m_axisX.isPaintScale()) { 1319 tmp = 0; 1321 labels = this.m_axisX.getScaleValues(); 1322 for (int i = 0; i < labels.length; i++) { 1323 tmp = this.m_xChartStart + (int) (labels[i].getValue() * rangex); 1324 labelPainter.paintXTick(tmp, this.m_yChartStart, labels[i].isMajorTick(), g2d); 1325 labelPainter.paintXLabel(tmp, this.m_yChartStart + fontheight, labels[i].getLabel(), g2d); 1326 if (this.m_axisX.isPaintGrid()) { 1327 if ((i != 0) || (tmp != this.m_xChartStart)) { 1328 g2d.setColor(this.m_gridcolor); 1329 g2d.drawLine(tmp, this.m_yChartStart - 1, tmp, this.m_yChartEnd); 1330 g2d.setColor(this.getForeground()); 1331 1332 } 1333 } 1334 } 1335 g2d.drawString(this.m_axisX.getFormatter().getUnit().getUnitName(), this.m_xChartEnd - 20, 1337 this.m_yChartStart - 5); 1338 } 1339 if (this.m_axisY.isPaintScale()) { 1340 labels = this.m_axisY.getScaleValues(); 1342 for (int i = 0; i < labels.length; i++) { 1343 tmp = this.m_yChartStart - (int) (labels[i].getValue() * rangey); 1344 labelPainter.paintYTick(this.m_xChartStart, tmp, labels[i].isMajorTick(), g2d); 1345 labelPainter.paintYLabel(2, tmp, labels[i].getLabel(), g2d); 1346 if (this.m_axisY.isPaintGrid()) { 1347 if ((i != 0) || (tmp != this.m_yChartStart)) { 1348 g2d.setColor(this.m_gridcolor); 1349 g2d.drawLine(this.m_xChartStart + 1, tmp, this.m_xChartEnd, tmp); 1350 g2d.setColor(this.getForeground()); 1351 } 1352 } 1353 } 1354 g2d.drawString(this.m_axisY.getFormatter().getUnit().getUnitName(), this.m_xChartStart, 1356 this.m_yChartEnd - 5); 1357 } 1358 1359 } 1360 1361 1369 1370 private int paintTraceLables(final Graphics2D g2d) { 1371 int labelheight = 0; 1372 Dimension d = this.getSize(); 1373 if (this.m_paintLabels) { 1374 ITrace2D trace; 1375 Iterator traceIt = this.m_traces.iterator(); 1376 int xtmpos = this.m_xChartStart; 1377 int ytmpos = (int) d.getHeight() - 2; 1378 int remwidth = (int) d.getWidth() - this.m_xChartStart; 1379 int allwidth = remwidth; 1380 int lblwidth = 0; 1381 String tmplabel; 1382 boolean crlfdone = false; 1383 FontMetrics fontdim = g2d.getFontMetrics(); 1385 int fontheight = fontdim.getHeight(); 1387 1388 if (traceIt.hasNext()) { 1389 labelheight += fontheight; 1390 } 1391 while (traceIt.hasNext()) { 1392 trace = (ITrace2D) traceIt.next(); 1393 if (trace.isVisible()) { 1394 tmplabel = trace.getLable(); 1395 lblwidth = fontdim.stringWidth(tmplabel) + 10; 1396 if (lblwidth > remwidth) { 1400 if (!(lblwidth > allwidth) || (!crlfdone)) { 1401 ytmpos -= fontheight; 1402 xtmpos = this.m_xChartStart; 1403 labelheight += fontheight; 1404 crlfdone = true; 1405 remwidth = (int) d.getWidth() - this.m_xChartStart; 1406 } else { 1407 crlfdone = false; 1408 } 1409 } 1410 remwidth -= lblwidth; 1411 g2d.setColor(trace.getColor()); 1412 g2d.drawString(tmplabel, xtmpos, ytmpos); 1413 xtmpos += lblwidth; 1414 } 1415 } 1416 } 1417 return labelheight; 1418 } 1419 1420 1442 public void propertyChange(final PropertyChangeEvent evt) { 1443 if (Chart2D.DEBUG_THREADING) { 1444 System.out.println("propertyChange 0 locks"); 1445 } 1446 synchronized (this) { 1447 if (Chart2D.DEBUG_THREADING) { 1448 System.out.println("propertyChange 1 lock"); 1449 } 1450 String property = evt.getPropertyName(); 1451 double value; 1452 if (property.equals(ITrace2D.PROPERTY_MAX_X)) { 1454 if (Chart2D.DEBUG_THREADING) { 1455 System.out.println("pc-Xmax"); 1456 } 1457 value = ((Double ) evt.getNewValue()).doubleValue(); 1458 if (value > this.m_xmax) { 1459 ITrace2D trace = (ITrace2D) evt.getSource(); 1460 if (trace.isVisible()) { 1461 this.m_xmax = value; 1462 } 1463 } else if (value < this.m_xmax) { 1464 this.m_xmax = this.findMaxX(); 1465 } 1466 } else if (property.equals(ITrace2D.PROPERTY_MIN_X)) { 1467 if (Chart2D.DEBUG_THREADING) { 1468 System.out.println("pc-Xmin"); 1469 } 1470 value = ((Double ) evt.getNewValue()).doubleValue(); 1471 if (value < this.m_xmin) { 1472 ITrace2D trace = (ITrace2D) evt.getSource(); 1473 if (trace.isVisible()) { 1474 this.m_xmin = value; 1475 } 1476 } else if (value > this.m_xmin) { 1477 this.m_xmin = this.findMinX(); 1478 } 1479 } else if (property.equals(ITrace2D.PROPERTY_MAX_Y)) { 1480 if (Chart2D.DEBUG_THREADING) { 1481 System.out.println("pc-Ymax"); 1482 } 1483 value = ((Double ) evt.getNewValue()).doubleValue(); 1484 if (value > this.m_ymax) { 1485 ITrace2D trace = (ITrace2D) evt.getSource(); 1486 if (trace.isVisible()) { 1487 this.m_ymax = value; 1488 } 1489 } else if (value < this.m_ymax) { 1490 this.m_ymax = this.findMaxY(); 1491 } 1492 } else if (property.equals(ITrace2D.PROPERTY_MIN_Y)) { 1493 if (Chart2D.DEBUG_THREADING) { 1494 System.out.println("pc-Ymin"); 1495 } 1496 value = ((Double ) evt.getNewValue()).doubleValue(); 1497 if (value < this.m_ymin) { 1498 ITrace2D trace = (ITrace2D) evt.getSource(); 1499 if (trace.isVisible()) { 1500 this.m_ymin = value; 1501 } 1502 } else if (value > this.m_ymin) { 1503 this.m_ymin = this.findMinY(); 1504 } 1505 } else if (property.equals(ARangePolicy.PROPERTY_RANGE)) { 1506 this.updateScaling(true); 1507 this.repaint(200); 1508 } else if (property.equals(ARangePolicy.PROPERTY_RANGE_MAX)) { 1509 this.updateScaling(true); 1513 this.repaint(200); 1514 } else if (property.equals(ARangePolicy.PROPERTY_RANGE_MIN)) { 1515 this.updateScaling(true); 1519 this.repaint(200); 1520 } else if (property.equals(ITrace2D.PROPERTY_TRACEPOINT)) { 1521 if (Chart2D.DEBUG_THREADING) { 1523 System.out.println("pc-tp"); 1524 } 1525 TracePoint2D oldPt = (TracePoint2D) evt.getOldValue(); 1526 TracePoint2D newPt = (TracePoint2D) evt.getNewValue(); 1527 if (oldPt == null) { 1530 this.m_unscaledPoints.add(newPt); 1531 } 1532 } else if (property.equals(ITrace2D.PROPERTY_VISIBLE)) { 1533 boolean visible = ((Boolean ) evt.getNewValue()).booleanValue(); 1534 if (visible) { 1535 this.findMaxX(); 1538 this.findMaxY(); 1539 this.findMinX(); 1540 this.findMinY(); 1541 } 1542 } else if (property.equals(ITrace2D.PROPERTY_STROKE)) { 1543 this.repaint(200); 1549 } else if (property.equals(ITrace2D.PROPERTY_PAINTERS)) { 1550 this.repaint(200); 1551 } else if (property.equals(ITrace2D.PROPERTY_COLOR)) { 1552 this.repaint(200); 1553 } 1554 } 1555 } 1556 1557 1574 public final void removeTrace(final ITrace2D points) { 1575 if (Chart2D.DEBUG_THREADING) { 1576 System.out.println("removeTrace, 0 locks"); 1577 } 1578 synchronized (this) { 1579 if (Chart2D.DEBUG_THREADING) { 1580 System.out.println("removeTrace, 1 lock"); 1581 } 1582 this.m_traces.remove(points); 1583 points.removePropertyChangeListener(ITrace2D.PROPERTY_MAX_X, this); 1585 points.removePropertyChangeListener(ITrace2D.PROPERTY_MIN_X, this); 1586 points.removePropertyChangeListener(ITrace2D.PROPERTY_MAX_Y, this); 1587 points.removePropertyChangeListener(ITrace2D.PROPERTY_MIN_Y, this); 1588 points.removePropertyChangeListener(ITrace2D.PROPERTY_TRACEPOINT, this); 1589 1590 this.m_xmax = this.findMaxX(); 1592 this.m_xmin = this.findMinX(); 1593 this.m_ymax = this.findMaxY(); 1594 this.m_ymin = this.findMinY(); 1595 1596 this.updateScaling(false); 1597 this.repaint(200); 1598 } 1599 this.firePropertyChange(Chart2D.PROPERTY_ADD_REMOVE_TRACE, points, null); 1600 } 1601 1602 1613 protected final void scaleAll(final int axis) { 1614 Iterator it = this.m_traces.iterator(); 1615 while (it.hasNext()) { 1616 this.scaleTrace((ITrace2D) it.next(), axis); 1617 } 1618 } 1619 1620 1634 private final void scalePoint(final TracePoint2D point, final int axis) { 1635 if (axis == Chart2D.X_Y) { 1636 point.m_scaledX = this.m_axisX.getScaledValue(point.getX()); 1637 point.m_scaledY = this.m_axisY.getScaledValue(point.getY()); 1638 } else if (axis == Chart2D.X) { 1639 point.m_scaledX = this.m_axisX.getScaledValue(point.getX()); 1640 1641 } else if (axis == Chart2D.Y) { 1642 point.m_scaledY = this.m_axisY.getScaledValue(point.getY()); 1643 1644 } else { 1645 throw new IllegalArgumentException ("Illegal argument, use constants."); 1646 } 1647 if (Chart2D.DEBUG_SCALING) { 1648 if ((point.m_scaledX > 1.0) || (point.m_scaledX < 0.0) || (point.m_scaledY > 1.0) 1650 || (point.m_scaledY < 0.0)) { 1651 System.out.println("Scaled Point " + point + " to [" + point.m_scaledX + "," 1652 + point.m_scaledY + "]"); 1653 } 1654 } 1655 } 1656 1657 1671 private final void scaleTrace(final ITrace2D trace, final int axis) { 1672 TracePoint2D tmp; 1673 if (trace.isVisible()) { 1674 Iterator it = trace.iterator(); 1675 while (it.hasNext()) { 1676 tmp = (TracePoint2D) it.next(); 1677 this.scalePoint(tmp, axis); 1678 } 1679 } 1680 } 1681 1682 1690 public void setAxisX(final AAxis axisX) { 1691 IAxis old = this.m_axisX; 1692 this.m_axisX = axisX; 1693 axisX.new XDataAccessor(this); 1695 this.updateScaling(true); 1696 this.firePropertyChange(Chart2D.PROPERTY_AXIS_X, old, this.m_axisX); 1697 repaint(200); 1698 1699 } 1700 1701 1709 public void setAxisY(final AAxis axisY) { 1710 IAxis old = this.m_axisY; 1711 this.m_axisY = axisY; 1712 axisY.new YDataAccessor(this); 1714 this.updateScaling(true); 1715 this.firePropertyChange(Chart2D.PROPERTY_AXIS_Y, old, this.m_axisY); 1716 repaint(200); 1717 } 1718 1719 1722 public void setBackground(final Color bg) { 1723 Color old = this.getBackground(); 1724 super.setBackground(bg); 1725 this.firePropertyChange(Chart2D.PROPERTY_BACKGROUND_COLOR, old, bg); 1726 } 1727 1728 1731 public void setForeground(final Color fg) { 1732 Color old = this.getForeground(); 1733 super.setForeground(fg); 1734 this.firePropertyChange(Chart2D.PROPERTY_FOREGROUND_COLOR, old, fg); 1735 } 1736 1737 1745 public final void setGridColor(final Color gridclr) { 1746 if (gridclr != null) { 1747 Color old = this.m_gridcolor; 1748 this.m_gridcolor = gridclr; 1749 if (!old.equals(this.m_gridcolor)) { 1750 this.firePropertyChange(Chart2D.PROPERTY_GRID_COLOR, old, this.m_gridcolor); 1751 } 1752 this.repaint(200); 1753 } 1754 } 1755 1756 1763 public synchronized void setLabelPainter(final ILabelPainter labelPainter) { 1764 this.m_labelPainter = labelPainter; 1765 } 1766 1767 1776 public void setPaintLabels(final boolean paintLabels) { 1777 final boolean change = this.m_paintLabels != paintLabels; 1778 this.m_paintLabels = paintLabels; 1779 if (change) { 1780 this.firePropertyChange(Chart2D.PROPERTY_PAINTLABELS, new Boolean (!paintLabels), new Boolean ( 1781 paintLabels)); 1782 this.repaint(200); 1783 } 1784 } 1785 1786 1799 public final void setToolTipCoords(final boolean toolTipCoords) { 1800 if (toolTipCoords) { 1801 if (this.getToolTipText() == null) { 1803 this.setToolTipText("turnOn"); 1804 } 1805 } else { 1806 this.setToolTipText(null); 1808 } 1809 this.m_toolTipCoords = toolTipCoords; 1810 } 1811 1812 1823 public BufferedImage snapShot() { 1824 BufferedImage img; 1825 img = new BufferedImage (this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB); 1826 Graphics g = img.getGraphics(); 1827 this.paint(g); 1829 return img; 1830 } 1831 1832 1835 public String toString() { 1836 if (Chart2D.DEBUG_THREADING) { 1837 System.out.println("toString(), " + Thread.currentThread().getName() + ", 0 locks"); 1838 } 1839 synchronized (this) { 1840 return super.toString(); 1841 } 1842 } 1843 1844 1859 public TracePoint2D translateMousePosition(final MouseEvent mouseEvent) 1860 throws IllegalArgumentException { 1861 if (mouseEvent.getSource() != this) { 1862 throw new IllegalArgumentException ( 1863 "The given mouse event does not belong to this chart but to: " + mouseEvent.getSource()); 1864 } 1865 TracePoint2D result = null; 1866 double valueX = this.m_axisX.translateMousePosition(mouseEvent); 1867 double valueY = this.m_axisY.translateMousePosition(mouseEvent); 1868 result = new TracePoint2D(valueX, valueY); 1869 1870 return result; 1871 } 1872 1873 1893 private void updateScaling(final boolean force) { 1894 1895 if (this.m_axisX != null && this.m_axisY != null) { 1896 this.m_axisX.initPaintIteration(); 1897 this.m_axisY.initPaintIteration(); 1898 boolean xChanged = isDirtyScaling(Chart2D.X); 1899 boolean yChanged = isDirtyScaling(Chart2D.Y); 1900 if (force || (xChanged && yChanged)) { 1901 this.scaleAll(Chart2D.X_Y); 1902 } else if (xChanged) { 1903 scaleAll(Chart2D.X); 1904 } else if (yChanged) { 1905 scaleAll(Chart2D.Y); 1906 } 1907 1908 Iterator itNewPoints = this.m_unscaledPoints.iterator(); 1910 TracePoint2D newPoint; 1911 while (itNewPoints.hasNext()) { 1912 newPoint = (TracePoint2D) itNewPoints.next(); 1913 this.scalePoint(newPoint, Chart2D.X_Y); 1914 itNewPoints.remove(); 1915 } 1916 this.m_xmaxold = this.m_xmax; 1918 this.m_ymaxold = this.m_ymax; 1919 this.m_xminold = this.m_xmin; 1920 this.m_yminold = this.m_ymin; 1921 } 1922 1923 } 1924} 1925 | Popular Tags |