1 58 59 package org.jfree.chart.plot; 60 61 import java.awt.BasicStroke ; 62 import java.awt.Color ; 63 import java.awt.Font ; 64 import java.awt.Graphics2D ; 65 import java.awt.Paint ; 66 import java.awt.Polygon ; 67 import java.awt.Stroke ; 68 import java.awt.geom.Area ; 69 import java.awt.geom.Ellipse2D ; 70 import java.awt.geom.Point2D ; 71 import java.awt.geom.Rectangle2D ; 72 import java.io.Serializable ; 73 import java.util.Arrays ; 74 import java.util.ResourceBundle ; 75 76 import org.jfree.chart.LegendItemCollection; 77 import org.jfree.chart.event.PlotChangeEvent; 78 import org.jfree.chart.needle.ArrowNeedle; 79 import org.jfree.chart.needle.LineNeedle; 80 import org.jfree.chart.needle.LongNeedle; 81 import org.jfree.chart.needle.MeterNeedle; 82 import org.jfree.chart.needle.MiddlePinNeedle; 83 import org.jfree.chart.needle.PinNeedle; 84 import org.jfree.chart.needle.PlumNeedle; 85 import org.jfree.chart.needle.PointerNeedle; 86 import org.jfree.chart.needle.ShipNeedle; 87 import org.jfree.chart.needle.WindNeedle; 88 import org.jfree.data.general.DefaultValueDataset; 89 import org.jfree.data.general.ValueDataset; 90 import org.jfree.ui.RectangleInsets; 91 import org.jfree.util.ObjectUtilities; 92 93 99 public class CompassPlot extends Plot implements Cloneable , Serializable { 100 101 102 private static final long serialVersionUID = 6924382802125527395L; 103 104 105 public static final Font DEFAULT_LABEL_FONT 106 = new Font ("SansSerif", Font.BOLD, 10); 107 108 109 public static final int NO_LABELS = 0; 110 111 112 public static final int VALUE_LABELS = 1; 113 114 115 private int labelType; 116 117 118 private Font labelFont; 119 120 121 private boolean drawBorder = false; 122 123 124 private Paint roseHighlightPaint = Color.black; 125 126 127 private Paint rosePaint = Color.yellow; 128 129 130 private Paint roseCenterPaint = Color.white; 131 132 133 private Font compassFont = new Font ("Arial", Font.PLAIN, 10); 134 135 136 private transient Ellipse2D circle1; 137 138 139 private transient Ellipse2D circle2; 140 141 142 private transient Area a1; 143 144 145 private transient Area a2; 146 147 148 private transient Rectangle2D rect1; 149 150 151 private ValueDataset[] datasets = new ValueDataset[1]; 152 153 154 private MeterNeedle[] seriesNeedle = new MeterNeedle[1]; 155 156 157 protected static ResourceBundle localizationResources = 158 ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle"); 159 160 163 protected double revolutionDistance = 360; 164 165 168 public CompassPlot() { 169 this(new DefaultValueDataset()); 170 } 171 172 177 public CompassPlot(ValueDataset dataset) { 178 179 super(); 180 181 if (dataset != null) { 182 this.datasets[0] = dataset; 183 dataset.addChangeListener(this); 184 } 185 186 187 this.circle1 = new Ellipse2D.Double (); 188 this.circle2 = new Ellipse2D.Double (); 189 this.rect1 = new Rectangle2D.Double (); 190 setSeriesNeedle(0); 191 192 } 193 194 200 public int getLabelType() { 201 return this.labelType; 202 } 203 204 212 public void setLabelType(int type) { 213 214 if ((type != NO_LABELS) && (type != VALUE_LABELS)) { 215 throw new IllegalArgumentException ( 216 "MeterPlot.setLabelType(int): unrecognised type." 217 ); 218 } 219 220 if (this.labelType != type) { 221 this.labelType = type; 222 notifyListeners(new PlotChangeEvent(this)); 223 } 224 225 } 226 227 232 public Font getLabelFont() { 233 return this.labelFont; 234 } 235 236 243 public void setLabelFont(Font font) { 244 245 if (font == null) { 247 throw new IllegalArgumentException ("Null 'font' not allowed."); 248 } 249 250 if (!this.labelFont.equals(font)) { 252 this.labelFont = font; 253 notifyListeners(new PlotChangeEvent(this)); 254 } 255 256 } 257 258 263 public boolean getDrawBorder() { 264 return this.drawBorder; 265 } 266 267 272 public void setDrawBorder(boolean status) { 273 this.drawBorder = status; 274 } 275 276 282 public void setSeriesPaint(int series, Paint paint) { 283 if ((series >= 0) && (series < this.seriesNeedle.length)) { 285 this.seriesNeedle[series].setFillPaint(paint); 286 } 287 } 288 289 295 public void setSeriesOutlinePaint(int series, Paint p) { 296 297 if ((series >= 0) && (series < this.seriesNeedle.length)) { 298 this.seriesNeedle[series].setOutlinePaint(p); 299 } 300 301 } 302 303 309 public void setSeriesOutlineStroke(int series, Stroke stroke) { 310 311 if ((series >= 0) && (series < this.seriesNeedle.length)) { 312 this.seriesNeedle[series].setOutlineStroke(stroke); 313 } 314 315 } 316 317 322 public void setSeriesNeedle(int type) { 323 setSeriesNeedle(0, type); 324 } 325 326 332 public void setSeriesNeedle(int index, int type) { 333 switch (type) { 334 case 0: 335 setSeriesNeedle(index, new ArrowNeedle(true)); 336 setSeriesPaint(index, Color.red); 337 this.seriesNeedle[index].setHighlightPaint(Color.white); 338 break; 339 case 1: 340 setSeriesNeedle(index, new LineNeedle()); 341 break; 342 case 2: 343 MeterNeedle longNeedle = new LongNeedle(); 344 longNeedle.setRotateY(0.5); 345 setSeriesNeedle(index, longNeedle); 346 break; 347 case 3: 348 setSeriesNeedle(index, new PinNeedle()); 349 break; 350 case 4: 351 setSeriesNeedle(index, new PlumNeedle()); 352 break; 353 case 5: 354 setSeriesNeedle(index, new PointerNeedle()); 355 break; 356 case 6: 357 setSeriesPaint(index, null); 358 setSeriesOutlineStroke(index, new BasicStroke (3)); 359 setSeriesNeedle(index, new ShipNeedle()); 360 break; 361 case 7: 362 setSeriesPaint(index, Color.blue); 363 setSeriesNeedle(index, new WindNeedle()); 364 break; 365 case 8: 366 setSeriesNeedle(index, new ArrowNeedle(true)); 367 break; 368 case 9: 369 setSeriesNeedle(index, new MiddlePinNeedle()); 370 break; 371 372 default: 373 throw new IllegalArgumentException ("Unrecognised type."); 374 } 375 376 } 377 378 384 public void setSeriesNeedle(int index, MeterNeedle needle) { 385 386 if ((needle != null) && (index < this.seriesNeedle.length)) { 387 this.seriesNeedle[index] = needle; 388 } 389 notifyListeners(new PlotChangeEvent(this)); 390 391 } 392 393 400 public ValueDataset[] getData() { 401 return this.datasets; 402 } 403 404 409 public void addData(ValueDataset data) { 410 addData(data, null); 411 } 412 413 419 public void addData(ValueDataset data, MeterNeedle needle) { 420 421 if (data != null) { 422 int i = this.datasets.length + 1; 423 ValueDataset[] t = new ValueDataset[i]; 424 MeterNeedle[] p = new MeterNeedle[i]; 425 i = i - 2; 426 for (; i >= 0; --i) { 427 t[i] = this.datasets[i]; 428 p[i] = this.seriesNeedle[i]; 429 } 430 i = this.datasets.length; 431 t[i] = data; 432 p[i] = ((needle != null) ? needle : p[i - 1]); 433 434 ValueDataset[] a = this.datasets; 435 MeterNeedle[] b = this.seriesNeedle; 436 this.datasets = t; 437 this.seriesNeedle = p; 438 439 for (--i; i >= 0; --i) { 440 a[i] = null; 441 b[i] = null; 442 } 443 data.addChangeListener(this); 444 } 445 } 446 447 457 public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, 458 PlotState parentState, 459 PlotRenderingInfo info) { 460 461 int outerRadius = 0; 462 int innerRadius = 0; 463 int x1, y1, x2, y2; 464 double a; 465 466 if (info != null) { 467 info.setPlotArea(area); 468 } 469 470 RectangleInsets insets = getInsets(); 472 insets.trim(area); 473 474 if (this.drawBorder) { 476 drawBackground(g2, area); 477 } 478 479 int midX = (int) (area.getWidth() / 2); 480 int midY = (int) (area.getHeight() / 2); 481 int radius = midX; 482 if (midY < midX) { 483 radius = midY; 484 } 485 --radius; 486 int diameter = 2 * radius; 487 488 midX += (int) area.getMinX(); 489 midY += (int) area.getMinY(); 490 491 this.circle1.setFrame(midX - radius, midY - radius, diameter, diameter); 492 this.circle2.setFrame( 493 midX - radius + 15, midY - radius + 15, 494 diameter - 30, diameter - 30 495 ); 496 g2.setPaint(this.rosePaint); 497 this.a1 = new Area (this.circle1); 498 this.a2 = new Area (this.circle2); 499 this.a1.subtract(this.a2); 500 g2.fill(this.a1); 501 502 g2.setPaint(this.roseCenterPaint); 503 x1 = diameter - 30; 504 g2.fillOval(midX - radius + 15, midY - radius + 15, x1, x1); 505 g2.setPaint(this.roseHighlightPaint); 506 g2.drawOval(midX - radius, midY - radius, diameter, diameter); 507 x1 = diameter - 20; 508 g2.drawOval(midX - radius + 10, midY - radius + 10, x1, x1); 509 x1 = diameter - 30; 510 g2.drawOval(midX - radius + 15, midY - radius + 15, x1, x1); 511 x1 = diameter - 80; 512 g2.drawOval(midX - radius + 40, midY - radius + 40, x1, x1); 513 514 outerRadius = radius - 20; 515 innerRadius = radius - 32; 516 for (int w = 0; w < 360; w += 15) { 517 a = Math.toRadians(w); 518 x1 = midX - ((int) (Math.sin(a) * innerRadius)); 519 x2 = midX - ((int) (Math.sin(a) * outerRadius)); 520 y1 = midY - ((int) (Math.cos(a) * innerRadius)); 521 y2 = midY - ((int) (Math.cos(a) * outerRadius)); 522 g2.drawLine(x1, y1, x2, y2); 523 } 524 525 g2.setPaint(this.roseHighlightPaint); 526 innerRadius = radius - 26; 527 outerRadius = 7; 528 for (int w = 45; w < 360; w += 90) { 529 a = Math.toRadians(w); 530 x1 = midX - ((int) (Math.sin(a) * innerRadius)); 531 y1 = midY - ((int) (Math.cos(a) * innerRadius)); 532 g2.fillOval( 533 x1 - outerRadius, y1 - outerRadius, 534 2 * outerRadius, 2 * outerRadius 535 ); 536 } 537 538 for (int w = 0; w < 360; w += 90) { 540 a = Math.toRadians(w); 541 x1 = midX - ((int) (Math.sin(a) * innerRadius)); 542 y1 = midY - ((int) (Math.cos(a) * innerRadius)); 543 544 Polygon p = new Polygon (); 545 p.addPoint(x1 - outerRadius, y1); 546 p.addPoint(x1, y1 + outerRadius); 547 p.addPoint(x1 + outerRadius, y1); 548 p.addPoint(x1, y1 - outerRadius); 549 g2.fillPolygon(p); 550 } 551 552 innerRadius = radius - 42; 554 Font f = getCompassFont(radius); 555 g2.setFont(f); 556 g2.drawString("N", midX - 5, midY - innerRadius + f.getSize()); 557 g2.drawString("S", midX - 5, midY + innerRadius - 5); 558 g2.drawString("W", midX - innerRadius + 5, midY + 5); 559 g2.drawString("E", midX + innerRadius - f.getSize(), midY + 5); 560 561 y1 = radius / 2; 563 x1 = radius / 6; 564 Rectangle2D needleArea = new Rectangle2D.Double ( 565 (midX - x1), (midY - y1), (2 * x1), (2 * y1) 566 ); 567 int x = this.seriesNeedle.length; 568 int current = 0; 569 double value = 0; 570 int i = (this.datasets.length - 1); 571 for (; i >= 0; --i) { 572 ValueDataset data = this.datasets[i]; 573 574 if (data != null && data.getValue() != null) { 575 value = (data.getValue().doubleValue()) 576 % this.revolutionDistance; 577 value = value / this.revolutionDistance * 360; 578 current = i % x; 579 this.seriesNeedle[current].draw(g2, needleArea, value); 580 } 581 } 582 583 if (this.drawBorder) { 584 drawOutline(g2, area); 585 } 586 587 } 588 589 594 public String getPlotType() { 595 return localizationResources.getString("Compass_Plot"); 596 } 597 598 604 public LegendItemCollection getLegendItems() { 605 return null; 606 } 607 608 613 public void zoom(double percent) { 614 } 616 617 624 protected Font getCompassFont(int radius) { 625 626 float fontSize = radius / 10.0f; 627 if (fontSize < 8) { 628 fontSize = 8; 629 } 630 631 Font newFont = this.compassFont.deriveFont(fontSize); 632 return newFont; 633 634 } 635 636 643 public boolean equals(Object obj) { 644 645 if (obj == this) { 646 return true; 647 } 648 649 if (!(obj instanceof CompassPlot)) { 650 return false; 651 } 652 if (!super.equals(obj)) { 653 return false; 654 } 655 CompassPlot that = (CompassPlot) obj; 656 if (this.labelType != that.labelType) { 657 return false; 658 } 659 if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) { 660 return false; 661 } 662 if (this.drawBorder != that.drawBorder) { 663 return false; 664 } 665 if (!ObjectUtilities.equal(this.roseHighlightPaint, 666 that.roseHighlightPaint)) { 667 return false; 668 } 669 if (!ObjectUtilities.equal(this.rosePaint, that.rosePaint)) { 670 return false; 671 } 672 if (!ObjectUtilities.equal(this.roseCenterPaint, 673 that.roseCenterPaint)) { 674 return false; 675 } 676 if (!ObjectUtilities.equal(this.compassFont, that.compassFont)) { 677 return false; 678 } 679 if (!Arrays.equals(this.seriesNeedle, that.seriesNeedle)) { 680 return false; 681 } 682 if (getRevolutionDistance() != that.getRevolutionDistance()) { 683 return false; 684 } 685 return true; 686 687 } 688 689 697 public Object clone() throws CloneNotSupportedException { 698 699 CompassPlot clone = (CompassPlot) super.clone(); 700 if (this.circle1 != null) { 708 clone.circle1 = (Ellipse2D ) this.circle1.clone(); 709 } 710 if (this.circle2 != null) { 711 clone.circle2 = (Ellipse2D ) this.circle2.clone(); 712 } 713 if (this.a1 != null) { 714 clone.a1 = (Area ) this.a1.clone(); 715 } 716 if (this.a2 != null) { 717 clone.a2 = (Area ) this.a2.clone(); 718 } 719 if (this.rect1 != null) { 720 clone.rect1 = (Rectangle2D ) this.rect1.clone(); 721 } 722 clone.datasets = (ValueDataset[]) this.datasets.clone(); 723 clone.seriesNeedle = (MeterNeedle[]) this.seriesNeedle.clone(); 724 725 for (int i = 0; i < this.datasets.length; ++i) { 727 if (clone.datasets[i] != null) { 728 clone.datasets[i].addChangeListener(clone); 729 } 730 } 731 return clone; 732 733 } 734 735 741 public void setRevolutionDistance(double size) { 742 if (size > 0) { 743 this.revolutionDistance = size; 744 } 745 } 746 747 752 public double getRevolutionDistance() { 753 return this.revolutionDistance; 754 } 755 } 756 | Popular Tags |