1 22 23 24 package net.sourceforge.chart2d; 25 26 27 import java.awt.*; 28 import java.awt.geom.*; 29 30 31 44 final class PieChartArea extends ChartArea { 45 46 private static final int LABEL = 0; 47 private static final int PIE = 1; 48 49 private PieInfoArea pieLabels; 50 private float pieToWidthRatio; 51 private float pieToHeightRatio; 52 private float pieLabelsToWidthRatio; 53 private float pieLabelsToHeightRatio; 54 private float[] dataset; 55 private Dimension prefSize; 56 private boolean needsUpdate; 57 58 private boolean linesExistence; 59 private GeneralPath[] lines; 60 private int linesThicknessModel; 61 private Color linesColor; 62 private BasicStroke linesStroke; 63 64 private boolean lineDotsExistence; 65 private Ellipse2D.Float[][] lineDots; 66 private int lineDotsThicknessModel; 67 private Color lineDotsColor; 68 69 private int tempX, tempY; 70 71 72 75 PieChartArea() { 76 77 pieLabels = new PieInfoArea(); 78 prefSize = new Dimension(); 79 needsUpdate = true; 80 81 setPieLabelsToWidthRatio (.50f); 82 setPieLabelsToHeightRatio (.25f); 83 84 setLabelsLinesExistence (true); 85 setLabelsLinesThicknessModel (1); 86 setLabelsLinesColor (Color.black); 87 setLabelsLineDotsExistence (true); 88 setLabelsLineDotsThicknessModel (4); 89 setLabelsLineDotsColor (Color.black); 90 resetPieChartAreaModel (true); 91 } 92 93 94 98 final void setDataset (float[] d) { 99 100 needsUpdate = true; 101 dataset = d; 102 } 103 104 105 110 final void setLabelsLineDotsExistence (boolean existence) { 111 112 lineDotsExistence = existence; 113 } 114 115 116 121 final boolean getLabelsLineDotsExistence() { 122 123 return lineDotsExistence; 124 } 125 126 127 132 final void setLabelsLineDotsThicknessModel (int thickness) { 133 134 needsUpdate = true; 135 lineDotsThicknessModel = thickness; 136 } 137 138 139 144 final int getLabelsLineDotsThicknessModel() { 145 146 return lineDotsThicknessModel; 147 } 148 149 150 155 final void setLabelsLineDotsColor (Color color) { 156 157 needsUpdate = true; 158 lineDotsColor = color; 159 } 160 161 162 167 final Color getLabelsLineDotsColor() { 168 169 return lineDotsColor; 170 } 171 172 173 178 final void setLabelsLinesExistence (boolean existence) { 179 180 linesExistence = existence; 181 } 182 183 184 189 final void setLabelsLinesThicknessModel (int thickness) { 190 191 needsUpdate = true; 192 linesThicknessModel = thickness; 193 } 194 195 196 201 final int getLabelsLinesThicknessModel() { 202 203 return linesThicknessModel; 204 } 205 206 207 212 final void setLabelsLinesColor (Color color) { 213 214 needsUpdate = true; 215 linesColor = color; 216 } 217 218 219 224 final Color getLabelsLinesColor() { 225 226 return linesColor; 227 } 228 229 230 237 final void setPieLabelsToWidthRatio (float ratio) { 238 239 needsUpdate = true; 240 pieLabelsToWidthRatio = ratio; 241 } 242 243 244 251 final void setPieLabelsToHeightRatio (float ratio) { 252 253 needsUpdate = true; 254 pieLabelsToHeightRatio = ratio; 255 } 256 257 258 266 final Dimension getPrefSize (Graphics2D g2D) { 267 268 if (getPieChartAreaNeedsUpdate()) updatePieChartArea (g2D); 269 return prefSize; 270 } 271 272 273 278 final PieInfoArea getPieInfoArea() { 279 return pieLabels; 280 } 281 282 283 294 final void resetPieChartAreaModel (boolean reset) { 295 296 resetChartAreaModel (reset); 297 pieLabels.resetPieInfoAreaModel (reset); 298 } 299 300 301 305 final boolean getPieChartAreaNeedsUpdate() { 306 307 if (needsUpdate || getChartAreaNeedsUpdate() || pieLabels.getPieInfoAreaNeedsUpdate()) 308 return true; 309 return false; 310 } 311 312 313 317 final void updatePieChartArea (Graphics2D g2D) { 318 319 if (getPieChartAreaNeedsUpdate()) { 320 updateChartArea (g2D); 321 update (g2D); 322 pieLabels.updatePieInfoArea (g2D); 323 } 324 needsUpdate = false; 325 } 326 327 328 332 final void paintComponent (Graphics2D g2D) { 333 334 updatePieChartArea (g2D); 335 super.paintComponent (g2D); 336 pieLabels.paintComponent (g2D); 337 338 if (pieLabels.getPieLabelsExistence() && linesExistence) { 339 g2D.setColor (linesColor); 340 g2D.setStroke (linesStroke); 341 for (int i = 0; i < dataset.length; ++i) { 342 g2D.draw (lines[i]); 343 } 344 } 345 346 if (pieLabels.getPieLabelsExistence() && lineDotsExistence) { 347 g2D.setColor (lineDotsColor); 348 for (int i = 0; i < dataset.length; ++i) { 349 g2D.fill (lineDots[i][LABEL]); 350 g2D.fill (lineDots[i][PIE]); 351 } 352 } 353 } 354 355 356 private void update (Graphics2D g2D) { 357 358 LegendArea legend = getLegend(); 359 360 float widthRatio = getRatio (WIDTH); 361 float heightRatio = getRatio (HEIGHT); 362 pieLabels.setCustomRatio (WIDTH, true, widthRatio); 363 pieLabels.setCustomRatio (HEIGHT, true, heightRatio); 364 legend.setCustomRatio (WIDTH, true, widthRatio); 365 legend.setCustomRatio (HEIGHT, true, heightRatio); 366 367 pieLabels.setRawLabelsPrecision (getLabelsPrecisionNum()); 368 pieLabels.setDatasetColors (getDatasetColors()); 369 pieLabels.setDataset (dataset); 370 371 Rectangle maxBounds = getMaxEntitledSpaceBounds (g2D); 372 373 int betweenChartAndLegendGapThickness = 0; 374 int availableWidth = maxBounds.width; 375 if (getBetweenChartAndLegendGapExistence() && getLegendExistence()) { 376 377 betweenChartAndLegendGapThickness = 378 applyRatio (getBetweenChartAndLegendGapThicknessModel(), getRatio (WIDTH)); 379 betweenChartAndLegendGapThickness = 380 betweenChartAndLegendGapThickness <= availableWidth ? 381 betweenChartAndLegendGapThickness : availableWidth; 382 availableWidth -= betweenChartAndLegendGapThickness; 383 } 384 385 int legendWidth = 0, legendHeight = 0; 386 float legendToWidthRatio = getLegendToWidthRatio(); 387 float legendToHeightRatio = getLegendToHeightRatio(); 388 if (getLegendExistence()) { 389 legendWidth = (int)(legendToWidthRatio * availableWidth); 390 legendHeight = (int)(legendToHeightRatio * maxBounds.height); 391 } 392 legend.setSize (MAX, new Dimension (legendWidth, legendHeight)); 393 legend.updateLegendArea (g2D); 394 legendWidth = legend.getSize (MIN).width; 395 legendHeight = legend.getSize (MIN).height; 396 397 int pieLabelsWidth = 0, pieLabelsHeight = 0; 398 pieLabelsWidth = (int)(pieLabelsToWidthRatio * availableWidth); 399 pieLabelsHeight = (int)(pieLabelsToHeightRatio * maxBounds.height); 400 pieLabels.setSize (MAX, new Dimension (pieLabelsWidth, pieLabelsHeight)); 401 pieLabels.setCustomSize (false, new Dimension()); 402 pieLabels.updatePieInfoArea (g2D); 403 pieLabelsWidth = pieLabels.getSize (MIN).width; 404 pieLabelsHeight = pieLabels.getSize (MIN).height; 405 406 int width = 0, height = 0; 407 width = pieLabelsWidth + betweenChartAndLegendGapThickness + legendWidth; 408 height = pieLabelsHeight > legendHeight ? pieLabelsHeight : legendHeight; 409 410 if (getAutoSetLayoutRatios()) { 411 412 width -= betweenChartAndLegendGapThickness; 413 414 pieLabelsToWidthRatio = width > 0 ? pieLabelsWidth / (float)width : 0f; 415 pieLabelsToWidthRatio = pieLabelsToWidthRatio < 1f ? pieLabelsToWidthRatio : 1f; 416 pieLabelsToHeightRatio = height > 0 ? pieLabelsHeight / (float)height : 0f; 417 pieLabelsToHeightRatio = pieLabelsToHeightRatio < 1f ? pieLabelsToHeightRatio : 1f; 418 419 legendToWidthRatio = legendToWidthRatio != 0f ? 1f - pieLabelsToWidthRatio : 0f; 420 legendToHeightRatio = legendToHeightRatio != 0f ? 1f : 0f; 421 422 if (pieLabelsToWidthRatio <= 0f || pieLabelsToHeightRatio <= 0f) { 423 pieLabelsToWidthRatio = pieLabelsToHeightRatio = 0f; 424 } 425 426 if (legendToWidthRatio <= 0f || legendToHeightRatio <= 0f) { 427 legendToWidthRatio = legendToHeightRatio = 0f; 428 } 429 430 setPieLabelsToWidthRatio (pieLabelsToWidthRatio); 431 setPieLabelsToHeightRatio (pieLabelsToHeightRatio); 432 433 setLegendToWidthRatio (legendToWidthRatio); 434 setLegendToHeightRatio (legendToHeightRatio); 435 436 setAutoSetLayoutRatios (false); 437 438 width += betweenChartAndLegendGapThickness; 439 } 440 441 Dimension titleSize = getTitleSize (MIN, g2D); 442 int titleGap = getBetweenTitleAndSpaceGapThickness (g2D); 443 int prefWidth1 = width + 2 * getOffsetThickness(); 444 int prefWidth2 = titleSize.width + 2 * getOffsetThickness(); 445 int prefWidth = prefWidth1 > prefWidth2 ? prefWidth1 : prefWidth2; 446 int prefHeight = height + 2 * getOffsetThickness() + titleSize.height + titleGap; 447 prefSize = new Dimension ((int)(1.3f * prefWidth), (int)(1.3f * prefHeight)); 448 449 if (getAutoSize (MIN)) { 450 451 int deficientWidth = maxBounds.width - width; 452 int deficientHeight = maxBounds.height - pieLabelsHeight; 453 int deficient = deficientWidth < deficientHeight ? deficientWidth : deficientHeight; 454 455 pieLabels.setCustomSize ( 456 true, new Dimension (pieLabelsWidth + deficientWidth, pieLabelsHeight + deficientHeight)); 457 458 pieLabels.updatePieInfoArea (g2D); 459 460 pieLabelsWidth = pieLabels.getSize (MIN).width; 461 pieLabelsHeight = pieLabels.getSize (MIN).height; 462 463 width = pieLabelsWidth + betweenChartAndLegendGapThickness + legendWidth; 464 height = pieLabelsHeight > legendHeight ? pieLabelsHeight : legendHeight; 465 } 466 467 Rectangle minBounds = new Rectangle(); 468 minBounds.setSize (width, height); 469 470 if (!getAutoSize (MIN)) { 471 472 int minWidth = titleSize.width > minBounds.width ? titleSize.width : minBounds.width; 473 int minHeight; 474 if (titleSize.height > 0 && minBounds.height > 0) { 475 minHeight = titleSize.height + titleGap + minBounds.height; 476 } 477 else minHeight = titleSize.height + minBounds.height; 478 setSpaceSize (MIN, new Dimension (minWidth, minHeight)); 479 } 480 481 int x = maxBounds.x + (maxBounds.width - minBounds.width) / 2; 482 int y = maxBounds.y + (maxBounds.height - minBounds.height) / 2; 483 minBounds.setLocation (x, y); 484 485 if (getTitleSqueeze()) { 486 int titleX = maxBounds.x + (maxBounds.width - titleSize.width) / 2; 487 int titleY = minBounds.y - titleSize.height - titleGap; 488 setTitleLocation (new Point (titleX, titleY)); 489 } 490 491 int legendX, legendY, pieLabelsX, pieLabelsY; 492 pieLabelsX = minBounds.x; 493 legendX = minBounds.x + minBounds.width - legendWidth + legend.getOffsetThickness(); 494 495 if (pieLabelsHeight > legendHeight) { 496 pieLabelsY = minBounds.y; 497 legendY = pieLabelsY + (pieLabelsHeight - legend.getSpaceSize (MIN).height) / 2; 498 } 499 else { 500 legendY = minBounds.y + legend.getOffsetThickness(); 501 pieLabelsY = legendY + (legendHeight - pieLabels.getSpaceSize (MIN).height) / 2; 502 } 503 504 pieLabels.setSpaceSizeLocation (MIN, new Point (pieLabelsX, pieLabelsY)); 505 pieLabels.updatePieInfoArea (g2D); 506 507 legend.setSpaceSizeLocation (MIN, new Point (legendX, legendY)); 508 legend.updateLegendArea (g2D); 509 510 PieArea pie = pieLabels.getPieArea(); 511 512 Point[] linesLabel = pieLabels.getPointsNearLabels (g2D); 513 Point[] linesGap = pie.getPointsOutSectors(); 514 Point[] linesSector = pie.getPointsInSectors(); 515 lines = new GeneralPath[dataset.length]; 516 for (int i = 0; i < dataset.length; ++i) { 517 518 lines[i] = new GeneralPath (GeneralPath.WIND_EVEN_ODD, 3); 519 lines[i].moveTo (linesSector[i].x, linesSector[i].y); 520 lines[i].lineTo (linesGap[i].x, linesGap[i].y); 521 lines[i].lineTo (linesLabel[i].x, linesLabel[i].y); 522 } 523 int tempLinesThicknessModel = 524 linesThicknessModel > 2 * pieLabels.getLabelsPointsGapThicknessModel() ? 525 2 * pieLabels.getLabelsPointsGapThicknessModel() : linesThicknessModel; 526 tempLinesThicknessModel = 527 tempLinesThicknessModel > 2 * pie.getGapThicknessModel() ? 528 2 * pie.getGapThicknessModel() : tempLinesThicknessModel; 529 int linesThickness = 530 applyRatio (tempLinesThicknessModel, getRatio (LESSER)); 531 linesThickness = linesThickness > pie.getGapThickness() ? 532 pie.getGapThickness() : linesThickness; 533 float[] style = {10.0f, 0.0f}; 534 linesStroke = new BasicStroke ( 535 (float)linesThickness, 536 BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, style, 0.0f); 537 538 lineDots = new Ellipse2D.Float[dataset.length][2]; 539 int tempLineDotsThicknessModel = 540 lineDotsThicknessModel > 541 2 * pieLabels.getLabelsPointsGapThicknessModel() ? 542 2 * pieLabels.getLabelsPointsGapThicknessModel() : lineDotsThicknessModel; 543 tempLineDotsThicknessModel = 544 tempLineDotsThicknessModel > 2 * pie.getGapThicknessModel() ? 545 2 * pie.getGapThicknessModel() : tempLineDotsThicknessModel; 546 int lineDotsThickness = 547 applyRatio (tempLineDotsThicknessModel, getRatio (LESSER)); 548 for (int i = 0; i < dataset.length; ++i) { 549 550 lineDots[i][PIE] = new Ellipse2D.Float ( 551 linesSector[i].x - lineDotsThickness / 2f, 552 linesSector[i].y - lineDotsThickness / 2f, 553 lineDotsThickness, lineDotsThickness); 554 lineDots[i][LABEL] = new Ellipse2D.Float ( 555 linesLabel[i].x - lineDotsThickness / 2f, 556 linesLabel[i].y - lineDotsThickness / 2f, 557 lineDotsThickness, lineDotsThickness); 558 } 559 } 560 } | Popular Tags |