1 22 23 24 package net.sourceforge.chart2d; 25 26 27 import java.awt.*; 28 import java.util.Date ; 29 30 31 44 final class PieInfoArea extends FontArea { 45 46 47 52 final static int RAW = 1; 53 54 55 60 final static int PERCENT = 2; 61 62 63 private int labelsType; 64 private int rawLabelsPrecision; 65 private boolean betweenLabelsGapExistence; 66 private int betweenLabelsGapThicknessModel; 67 private TextArea[] labels; 68 private Point[] pointsNearLabels; 69 private boolean labelsPointsGapExistence; 70 private int labelsPointsGapThicknessModel; 71 private PieArea pieArea; 72 private Dimension interiorSize; 73 private Rectangle interiorBounds; 74 private boolean customSizing; 75 private Dimension customSize; 76 private float[] dataset; 77 private Color[] datasetColors; 78 private boolean pieLabelsExistence; 79 80 private boolean needsUpdate; 81 82 83 86 PieInfoArea () { 87 88 pieArea = new PieArea(); 89 setAutoSizes (false, false); 90 setBackgroundExistence (false); 91 setBorderExistence (false); 92 setGapExistence (false); 93 setAutoJustifys (false, false); 94 setFontPointModel (10); 95 setLabelsType (RAW + PERCENT); 96 setRawLabelsPrecision (0); 97 setBetweenLabelsGapExistence (true); 98 setBetweenLabelsGapThicknessModel (3); 99 setLabelsPointsGapExistence (true); 100 setLabelsPointsGapThicknessModel (2); 101 setCustomSize (false, new Dimension()); 102 setPieLabelsExistence (true); 103 resetPieInfoAreaModel (true); 104 needsUpdate = true; 105 } 106 107 108 113 final void setPieLabelsExistence (boolean existence) { 114 115 needsUpdate = true; 116 pieLabelsExistence = existence; 117 } 118 119 120 125 final boolean getPieLabelsExistence() { 126 127 return pieLabelsExistence; 128 } 129 130 131 136 final void setDataset (float[] values) { 137 138 needsUpdate = true; 139 dataset = values; 140 } 141 142 143 148 final void setDatasetColors (Color[] colors) { 149 150 needsUpdate = true; 151 datasetColors = colors; 152 } 153 154 155 159 final float[] getDataset() { 160 161 return dataset; 162 } 163 164 165 169 final Color[] getDatasetColors() { 170 171 return datasetColors; 172 } 173 174 175 184 final void setCustomSize (boolean customize, Dimension size) { 185 186 needsUpdate = true; 187 customSizing = customize; 188 customSize = size; 189 } 190 191 192 196 final PieArea getPieArea() { 197 return pieArea; 198 } 199 200 201 206 final void setLabelsPointsGapExistence (boolean existence) { 207 208 needsUpdate = true; 209 labelsPointsGapExistence = existence; 210 } 211 212 213 219 final void setLabelsPointsGapThicknessModel (int thickness) { 220 221 needsUpdate = true; 222 labelsPointsGapThicknessModel = thickness; 223 } 224 225 226 233 final void setRawLabelsPrecision (int precision) { 234 235 needsUpdate = true; 236 rawLabelsPrecision = precision; 237 } 238 239 240 245 final void setBetweenLabelsGapExistence (boolean existence) { 246 247 needsUpdate = true; 248 betweenLabelsGapExistence = existence; 249 } 250 251 252 259 final void setBetweenLabelsGapThicknessModel (int thickness) { 260 261 needsUpdate = true; 262 betweenLabelsGapThicknessModel = thickness; 263 } 264 265 266 274 final void setLabelsType (int type) { 275 276 needsUpdate = true; 277 labelsType = type; 278 } 279 280 281 286 final int getLabelsPointsGapThicknessModel() { 287 288 return labelsPointsGapThicknessModel; 289 } 290 291 292 299 final int getRawLabelsPrecision() { 300 301 return rawLabelsPrecision; 302 } 303 304 305 314 final int getLabelsType() { 315 316 return labelsType; 317 } 318 319 320 324 final Rectangle getInteriorBounds (Graphics2D g2D) { 325 326 updatePieInfoArea (g2D); 327 return interiorBounds; 328 } 329 330 331 336 final boolean getLabelsPointsGapExistence() { 337 return labelsPointsGapExistence; 338 } 339 340 341 346 final Point[] getPointsNearLabels (Graphics2D g2D) { 347 348 updatePieInfoArea (g2D); 349 return pointsNearLabels; 350 } 351 352 353 357 final boolean getPieInfoAreaNeedsUpdate() { 358 return (needsUpdate || getFontAreaNeedsUpdate() || pieArea.getPieAreaNeedsUpdate()); 359 } 360 361 362 374 final void resetPieInfoAreaModel (boolean reset) { 375 376 needsUpdate = true; 377 resetFontAreaModel (reset); 378 pieArea.resetPieAreaModel (reset); 379 } 380 381 382 386 final void updatePieInfoArea (Graphics2D g2D) { 387 388 if (getPieInfoAreaNeedsUpdate()) { 389 390 updateFontArea(); 391 update (g2D); 392 pieArea.updatePieArea(); 393 for (int i = 0; i < labels.length; ++i) { 394 labels[i].updateTextArea (g2D); 395 } 396 } 397 needsUpdate = false; 398 } 399 400 401 406 final void paintComponent (Graphics2D g2D) { 407 408 updatePieInfoArea (g2D); 409 super.paintComponent (g2D); 410 411 pieArea.paintComponent (g2D); 412 for (int i = 0; i < pieArea.getDataset().length; ++i) { 413 labels[i].paintComponent (g2D); 414 } 415 } 416 417 418 private void update (Graphics2D g2D) { 419 420 float widthRatio = getRatio (WIDTH); 421 float heightRatio = getRatio (HEIGHT); 422 pieArea.setCustomRatio (WIDTH, true, widthRatio); 423 pieArea.setCustomRatio (HEIGHT, true, heightRatio); 424 425 pieArea.setDataset (dataset); 426 pieArea.setColors (datasetColors); 427 pieArea.setSize (MAX, new Dimension (100, 100)); pieArea.setCustomSpaceSize (true, new Dimension (100, 100)); pieArea.updatePieArea(); 430 int[] numLabelsInSectors = pieArea.getNumSectorsInQuarters(); 431 int[] numLabelsInQuarters = new int[4]; 432 numLabelsInQuarters[TOP] = numLabelsInSectors[TOP]; 433 numLabelsInQuarters[RIGHT] = numLabelsInSectors[RIGHT]; 434 numLabelsInQuarters[BOTTOM] = numLabelsInSectors[BOTTOM]; 435 numLabelsInQuarters[LEFT] = numLabelsInSectors[LEFT]; 436 pieArea.setCustomSpaceSize (false, null); 437 pieArea.updatePieArea(); 438 439 int maxLabelsHorizontally = 440 numLabelsInQuarters[TOP] > numLabelsInQuarters[BOTTOM] ? 441 numLabelsInQuarters[TOP] : numLabelsInQuarters[BOTTOM]; 442 int maxLabelsVertically = 443 numLabelsInQuarters[RIGHT] > numLabelsInQuarters[LEFT] ? 444 numLabelsInQuarters[RIGHT] : numLabelsInQuarters[LEFT]; 445 446 int betweenLabelsGapThickness = 0; 447 if (betweenLabelsGapExistence && pieLabelsExistence) { 448 betweenLabelsGapThickness = applyRatio (betweenLabelsGapThicknessModel, getRatio (LESSER)); 449 } 450 451 Dimension labelsSizeMax; 452 if (pieLabelsExistence) { 453 int labelsMaxWidth1 = getSpaceSize (MAX).width / 2 - betweenLabelsGapThickness; 454 int labelsMaxWidth2 = Integer.MAX_VALUE; 455 if (maxLabelsHorizontally > 0) { 456 labelsMaxWidth2 = 457 (getSpaceSize (MAX).width - (maxLabelsHorizontally - 1) * betweenLabelsGapThickness) / 458 maxLabelsHorizontally; 459 } 460 int labelsMaxWidth = labelsMaxWidth1 < labelsMaxWidth2 ? labelsMaxWidth1 : labelsMaxWidth2; 461 labelsMaxWidth = labelsMaxWidth > 0 ? labelsMaxWidth : 0; 462 463 int labelsMaxHeight1 = getSpaceSize (MAX).height / 2 - betweenLabelsGapThickness; 464 int labelsMaxHeight2 = 465 (getSpaceSize (MAX).height - (maxLabelsVertically + 1) * betweenLabelsGapThickness) / 466 (maxLabelsVertically + 2); 467 int labelsMaxHeight = 468 labelsMaxHeight1 < labelsMaxHeight2 ? labelsMaxHeight1 : labelsMaxHeight2; 469 labelsMaxHeight = labelsMaxHeight > 0 ? labelsMaxHeight : 0; 470 labelsSizeMax = new Dimension (labelsMaxWidth, labelsMaxHeight); 471 } 472 else labelsSizeMax = new Dimension(); 473 474 labels = new TextArea[dataset.length]; 475 float datasetTotal = ChartArea.getDatasetTotal (dataset); 476 int labelsWidthMin = 0; 477 int labelsHeightMin = 0; 478 for (int i = 0; i < dataset.length; ++i) { 479 480 TextArea label = new TextArea(); 481 label.setCustomRatio (WIDTH, true, getRatio (WIDTH)); 482 label.setCustomRatio (HEIGHT, true, getRatio (HEIGHT)); 483 label.setAutoJustifys (false, false); 484 label.setAutoSizes (true, false); 485 label.setSize (MAX, labelsSizeMax); 486 label.setBackgroundExistence (false); 487 label.setBorderExistence (false); 488 label.setGapExistence (false); 489 label.setFontColor (getFontColor()); 490 label.setFontName (getFontName()); 491 label.setFontPointModel (getFontPointModel()); 492 label.setFontStyle (getFontStyle()); 493 494 String text = ""; 495 if (labelsType == RAW) { 496 text = ChartArea.getFloatToString ( 497 ChartArea.getPrecisionRound (dataset[i], rawLabelsPrecision), rawLabelsPrecision); 498 } 499 else if (labelsType == PERCENT) { 500 text = ChartArea.getFloatToString ( 501 ChartArea.getPrecisionRound (100 * dataset[i] / datasetTotal, 0), 0) + "%"; 502 } 503 else { 504 String text1 = ChartArea.getFloatToString ( 505 ChartArea.getPrecisionRound (dataset[i], rawLabelsPrecision), rawLabelsPrecision); 506 String text2 = ChartArea.getFloatToString ( 507 ChartArea.getPrecisionRound (100 * dataset[i] / datasetTotal, 0), 0) + "%"; 508 text = text1 + " (" + text2 + ")"; 509 } 510 label.setText (text); 511 512 label.updateTextArea (g2D); 513 labelsWidthMin = 514 label.getSize (MIN).width > labelsWidthMin ? label.getSize (MIN).width : labelsWidthMin; 515 labelsHeightMin = 516 label.getSize (MIN).height > labelsHeightMin ? label.getSize (MIN).height : labelsHeightMin; 517 labels[i] = label; 518 } 519 520 Dimension labelsSizeMin = new Dimension (labelsWidthMin, labelsHeightMin); 521 522 int widthMin1 = 523 (maxLabelsHorizontally - 1) * betweenLabelsGapThickness + 524 maxLabelsHorizontally * labelsWidthMin; 525 int widthMin2 = 2 * labelsWidthMin; 526 int widthMin = widthMin1 > widthMin2 ? widthMin1 : widthMin2; 527 528 int heightMin1 = 529 (maxLabelsVertically + 1) * betweenLabelsGapThickness + 530 (maxLabelsVertically + 2) * labelsHeightMin; 531 int heightMin2 = 2 * labelsHeightMin; 532 int heightMin = heightMin1 > heightMin2 ? heightMin1 : heightMin2; 533 534 int pieSize = 0; 535 if (!getAutoSize (MIN) && !customSizing) { 536 537 int availableWidth = getSpaceSize (MAX).width - widthMin; 538 int availableHeight = getSpaceSize (MAX).height - heightMin; 539 int available = availableWidth < availableHeight ? availableWidth : availableHeight; 540 pieArea.setSize (MAX, new Dimension (available, available)); 541 pieArea.updatePieArea(); 542 pieSize = pieArea.getSize (MIN).width; 543 544 widthMin += pieSize; 545 heightMin += pieSize; 546 547 setSpaceSize (MIN, new Dimension (widthMin, heightMin)); 548 } 549 else if (!getAutoSize (MIN) && customSizing) { 550 551 setSpaceSize (MIN, customSize); 552 } 553 554 Dimension sizeMin = getSpaceSize (MIN); 555 556 float midPointX = getSpaceSizeLocation (MIN).x + sizeMin.width / 2f; 557 float midPointY = getSpaceSizeLocation (MIN).y + sizeMin.height / 2f; 558 559 pointsNearLabels = new Point[dataset.length]; 560 561 int labelsPointsGapThickness = 562 labelsPointsGapExistence ? applyRatio (labelsPointsGapThicknessModel, getRatio (LESSER)) : 0; 563 564 int topInteriorY = 0, leftInteriorX = 0; 565 Point originTop = new Point (0, getSpaceSizeLocation (MIN).y); 566 int betweenGapTop = 567 (sizeMin.width - numLabelsInQuarters[TOP] * labelsWidthMin) / (numLabelsInQuarters[TOP] + 1); 568 if (numLabelsInQuarters[TOP] % 2 == 0) { 569 originTop.setLocation ( 570 midPointX - (numLabelsInQuarters[TOP] / 2) * labelsWidthMin - 571 ((numLabelsInQuarters[TOP] / 2) - 1/2f) * betweenGapTop, originTop.y); 572 } 573 else { 574 originTop.setLocation ((int)( 575 midPointX - (numLabelsInQuarters[TOP] / 2f) * labelsWidthMin - 576 (int)(numLabelsInQuarters[TOP] / 2) * betweenGapTop), 577 originTop.y); 578 } 579 580 topInteriorY = originTop.y + labelsHeightMin; 581 for (int i = 0; i < numLabelsInQuarters[TOP]; ++i) { 582 labels[i].setSpaceSizeLocation (MIN, new Point ( 583 (int)(originTop.x + i * (labelsWidthMin + betweenGapTop) + 584 (labelsWidthMin - labels[i].getSize(MIN).width) / 2f), 585 originTop.y)); 586 pointsNearLabels[i] = new Point ( 587 (int)(labels[i].getSpaceSizeLocation (MIN).x + 588 (labels[i].getSize (MIN).width / 2f)), 589 originTop.y + labelsHeightMin + labelsPointsGapThickness); 590 } 591 592 Point originRight = new Point ( 593 getSpaceSizeLocation (MIN).x + sizeMin.width - labelsWidthMin, 0); 594 int betweenGapRight = 595 (sizeMin.height - (numLabelsInQuarters[RIGHT] + 2) * labelsHeightMin) / 596 (numLabelsInQuarters[RIGHT] + 1); 597 if (numLabelsInQuarters[RIGHT] % 2 == 0) { 598 originRight.setLocation (originRight.x, 599 (int)(midPointY - (numLabelsInQuarters[RIGHT] / 2) * labelsHeightMin - 600 ((numLabelsInQuarters[RIGHT] / 2) - 1/2f) * betweenGapRight)); 601 } 602 else { 603 originRight.setLocation (originRight.x, 604 (int)(midPointY - (numLabelsInQuarters[RIGHT] / 2f) * labelsHeightMin - 605 (int)(numLabelsInQuarters[RIGHT] / 2) * betweenGapRight)); 606 } 607 608 int datasetOffsetRight = numLabelsInQuarters[TOP]; 609 for (int i = 0; i < numLabelsInQuarters[RIGHT]; ++i) { 610 labels[i + datasetOffsetRight].setSpaceSizeLocation (MIN, new Point ( 611 originRight.x + 612 (labelsWidthMin - labels[i + datasetOffsetRight].getSize(MIN).width), 613 (int)(originRight.y + i * (labelsHeightMin + betweenGapRight) + 614 (labelsHeightMin - labels[i + datasetOffsetRight].getSize(MIN).height) / 615 2f))); 616 pointsNearLabels[i + datasetOffsetRight] = new Point ( 617 originRight.x - labelsPointsGapThickness, 618 (int)(labels[i + datasetOffsetRight].getSpaceSizeLocation (MIN).y + 619 (labels[i + datasetOffsetRight].getSize (MIN).height / 2f))); 620 } 621 622 Point originBottom = new Point (0, 623 getSpaceSizeLocation (MIN).y + getSpaceSize (MIN).height - 624 labelsHeightMin); 625 int betweenGapBottom = 626 (sizeMin.width - numLabelsInQuarters[BOTTOM] * labelsWidthMin) / 627 (numLabelsInQuarters[BOTTOM] + 1); 628 if (numLabelsInQuarters[BOTTOM] % 2 == 0) { 629 originBottom.setLocation ( 630 midPointX - (numLabelsInQuarters[BOTTOM] / 2) * labelsWidthMin - 631 ((numLabelsInQuarters[BOTTOM] / 2) - 1/2f) * betweenGapBottom, 632 originBottom.y); 633 } 634 else { 635 originBottom.setLocation ((int)( 636 midPointX - (numLabelsInQuarters[BOTTOM] / 2f) * labelsWidthMin - 637 (int)(numLabelsInQuarters[BOTTOM] / 2) * betweenGapBottom), 638 originBottom.y); 639 } 640 641 int datasetOffsetBottom = 642 numLabelsInQuarters[TOP] + numLabelsInQuarters[RIGHT]; 643 int j = numLabelsInQuarters[BOTTOM] - 1; 644 for (int i = 0; i < numLabelsInQuarters[BOTTOM]; ++i) { 645 labels[i + datasetOffsetBottom].setSpaceSizeLocation ( 646 MIN, new Point ((int)(originBottom.x + 647 j * (labelsWidthMin + betweenGapBottom) + 648 (labelsWidthMin - labels[i + datasetOffsetBottom].getSize(MIN).width) / 649 2f), 650 originBottom.y + (labelsHeightMin - 651 labels[i + datasetOffsetBottom].getSize(MIN).height))); 652 --j; 653 pointsNearLabels[i + datasetOffsetBottom] = new Point ( 654 (int)(labels[i + datasetOffsetBottom].getSpaceSizeLocation (MIN).x + 655 (labels[i + datasetOffsetBottom].getSize (MIN).width / 2f)), 656 originBottom.y - labelsPointsGapThickness); 657 } 658 659 Point originLeft = new Point (getSpaceSizeLocation (MIN).x, 0); 660 int betweenGapLeft = 661 (sizeMin.height - (numLabelsInQuarters[LEFT] + 2) * labelsHeightMin) / 662 (numLabelsInQuarters[LEFT] + 1); 663 if (numLabelsInQuarters[LEFT] % 2 == 0) { 664 originLeft.setLocation (originLeft.x, 665 (int)(midPointY - (numLabelsInQuarters[LEFT] / 2) * labelsHeightMin - 666 ((numLabelsInQuarters[LEFT] / 2) - 1/2f) * betweenGapLeft)); 667 } 668 else { 669 originLeft.setLocation (originLeft.x, 670 (int)(midPointY - (numLabelsInQuarters[LEFT] / 2f) * labelsHeightMin - 671 (int)(numLabelsInQuarters[LEFT] / 2) * betweenGapLeft)); 672 } 673 leftInteriorX = originLeft.x + labelsWidthMin; 674 675 int datasetOffsetLeft = numLabelsInQuarters[TOP] + 676 numLabelsInQuarters[RIGHT] + numLabelsInQuarters[BOTTOM]; 677 j = numLabelsInQuarters[LEFT] - 1; 678 for (int i = 0; i < numLabelsInQuarters[LEFT]; ++i) { 679 labels[i + datasetOffsetLeft].setSpaceSizeLocation (MIN, new Point ( 680 originLeft.x + labelsWidthMin - 681 labels[i + datasetOffsetLeft].getSize(MIN).width, 682 (int)(originLeft.y + j * (labelsHeightMin + betweenGapLeft) + 683 (labelsHeightMin - 684 labels[i + datasetOffsetLeft].getSize(MIN).height) / 2f))); 685 --j; 686 pointsNearLabels[i + datasetOffsetLeft] = new Point ( 687 originLeft.x + labelsWidthMin + labelsPointsGapThickness, 688 (int)(labels[i + datasetOffsetLeft].getSpaceSizeLocation (MIN).y + 689 (labels[i + datasetOffsetLeft].getSize (MIN).height / 2f))); 690 } 691 692 pieArea.setCustomSpaceSize (true, new Dimension ( 693 originRight.x - originLeft.x - labelsWidthMin - 2 * pieArea.getOffsetThickness(), 694 originBottom.y - originTop.y - labelsHeightMin - 2 * pieArea.getOffsetThickness())); 695 pieArea.setSpaceSizeLocation (MIN, new Point ( 696 originLeft.x + labelsWidthMin + pieArea.getOffsetThickness(), 697 originTop.y + labelsHeightMin + pieArea.getOffsetThickness())); 698 } 699 } | Popular Tags |