1 34 35 package org.krysalis.jcharts.nonAxisChart; 36 37 38 import org.krysalis.jcharts.Chart; 39 import org.krysalis.jcharts.chartData.interfaces.IPieChartDataSet; 40 import org.krysalis.jcharts.chartData.processors.PieChartDataProcessor; 41 import org.krysalis.jcharts.imageMap.CircleMapArea; 42 import org.krysalis.jcharts.imageMap.ImageMap; 43 import org.krysalis.jcharts.imageMap.PolyMapArea; 44 import org.krysalis.jcharts.properties.ChartProperties; 45 import org.krysalis.jcharts.properties.LegendAreaProperties; 46 import org.krysalis.jcharts.properties.LegendProperties; 47 import org.krysalis.jcharts.properties.PieChart3DProperties; 48 import org.krysalis.jcharts.test.HTMLChartTestable; 49 import org.krysalis.jcharts.test.HTMLGenerator; 50 import org.krysalis.jcharts.types.PieLabelType; 51 52 import java.awt.*; 53 import java.awt.font.FontRenderContext ; 54 import java.awt.geom.Arc2D ; 55 import java.awt.geom.Line2D ; 56 57 58 65 public class PieChart3D extends Chart implements HTMLChartTestable 66 { 67 private float pieX; 68 private float pieY; 69 70 private float pie3dWidth; 71 private float pie3dHeight; 72 private static final float RATIO = 0.5f; 73 74 private float diameter = 0; 75 76 77 private IPieChartDataSet iPieChartDataSet; 78 private PieChartDataProcessor pieChartDataProcessor; 79 80 private PieLabels pieLabels; 81 82 83 92 public PieChart3D( IPieChartDataSet iPieChartDataSet, 93 LegendProperties legendProperties, 94 ChartProperties chartProperties, 95 int pixelWidth, 96 int pixelHeight ) 97 { 98 super( legendProperties, chartProperties, pixelWidth, pixelHeight ); 99 this.iPieChartDataSet = iPieChartDataSet; 100 } 101 102 103 107 protected void renderChart() 108 { 109 PieChart3DProperties properties = (PieChart3DProperties) this.iPieChartDataSet.getChartTypeProperties(); 110 FontRenderContext fontRenderContext = super.getGraphics2D().getFontRenderContext(); 111 112 this.pieChartDataProcessor = new PieChartDataProcessor( this.iPieChartDataSet ); 113 this.pieChartDataProcessor.processData(); 114 115 116 float edgePaddingTimesTwo = super.getChartProperties().getEdgePadding() * 2; 118 float halfImageWidth = super.getImageWidth() / 2; 119 float halfImageHeight = super.getImageHeight() / 2; 120 121 122 float chartTitleHeightPlusPadding = super.renderChartTitle( this.iPieChartDataSet.getChartTitle(), fontRenderContext ); 124 125 126 float widthAvailable = super.getImageWidth() - edgePaddingTimesTwo; 128 129 float heightAvailable = super.getImageHeight() - edgePaddingTimesTwo; 130 heightAvailable -= chartTitleHeightPlusPadding; 131 heightAvailable -= properties.getDepth(); 132 133 134 if( !properties.getPieLabelType().equals( PieLabelType.NO_LABELS ) ) 136 { 137 this.pieLabels = new PieLabels( properties, this.iPieChartDataSet, fontRenderContext ); 138 139 if( iPieChartDataSet.getNumberOfDataItems() != 1 ) 141 { 142 widthAvailable -= this.pieLabels.getWidestLabelTimesTwo(); 143 widthAvailable -= ( properties.getTickLength() * 2 ); 144 } 145 146 heightAvailable -= this.pieLabels.getTallestLabelTimesTwo(); 147 heightAvailable -= ( properties.getTickLength() * 2 ); 148 } 149 150 151 if( this.getLegend() != null ) 153 { 154 float legendX = 0f; 155 float legendY = 0f; 156 157 this.getLegend().calculateDrawingValues( iPieChartDataSet ); 159 160 161 if( ( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT ) 163 || ( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.LEFT ) ) 164 { 165 widthAvailable -= this.getLegend().getWidth(); 166 widthAvailable -= this.getLegend().getLegendProperties().getChartPadding(); 167 168 this.diameter = Math.max( widthAvailable, 1.0f ); 171 172 this.diameter = Math.min( this.diameter, heightAvailable ); 174 175 this.pie3dWidth = this.diameter; 176 this.pie3dHeight = this.pie3dWidth * RATIO; 177 178 179 183 184 185 float plotWidth = this.diameter; 187 plotWidth += this.getLegend().getWidth(); 188 plotWidth += this.getLegend().getLegendProperties().getChartPadding(); 189 if( this.pieLabels != null ) 190 { 191 plotWidth += ( this.pieLabels.getWidestLabel() * 2 ); 192 plotWidth += ( properties.getTickLength() * 2 ); 193 } 194 195 if( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT ) 196 { 197 this.pieX = halfImageWidth - ( plotWidth / 2 ); 199 200 if( this.pieLabels != null ) 201 { 202 this.pieX += this.pieLabels.getWidestLabel(); 203 this.pieX += properties.getTickLength(); 204 legendX += this.pieLabels.getWidestLabel(); 205 legendX += properties.getTickLength(); 206 } 207 208 legendX += this.pieX + this.diameter; 210 legendX += this.getLegend().getLegendProperties().getChartPadding(); 211 } 212 else 213 { 214 legendX = halfImageWidth - ( plotWidth / 2 ); 215 216 if( this.pieLabels != null ) 217 { 218 this.pieX = legendX; 219 this.pieX += this.getLegend().getWidth(); 220 this.pieX += this.getLegend().getLegendProperties().getChartPadding(); 221 this.pieX += this.pieLabels.getWidestLabel(); 222 this.pieX += properties.getTickLength(); 223 } 224 } 225 226 legendY = halfImageHeight - ( this.getLegend().getHeight() / 2 ); 228 229 this.pieY = halfImageHeight - ( ( this.pie3dHeight + properties.getDepth() ) / 2 ); 231 } 232 else 234 { 235 heightAvailable -= this.getLegend().getHeight(); 236 heightAvailable -= this.getLegend().getLegendProperties().getChartPadding(); 237 238 this.diameter = Math.max( heightAvailable, 1.0f ); 241 242 this.diameter = Math.min( this.diameter, widthAvailable ); 244 245 this.pie3dWidth = this.diameter; 246 this.pie3dHeight = this.pie3dWidth * RATIO; 247 248 249 if( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.BOTTOM ) 250 { 251 this.pieY = super.getChartProperties().getEdgePadding(); 252 this.pieY += chartTitleHeightPlusPadding; 253 254 if( this.pieLabels != null ) 255 { 256 this.pieY += this.pieLabels.getTallestLabel(); 258 this.pieY += properties.getTickLength(); 259 260 legendY += this.pieLabels.getTallestLabel(); 262 legendY += properties.getTickLength(); 263 } 264 265 legendY += this.pieY; 266 legendY += this.pie3dHeight; 267 legendY += this.getLegend().getLegendProperties().getChartPadding(); 268 legendY += properties.getDepth(); 269 } 270 else 271 { 272 legendY = super.getChartProperties().getEdgePadding(); 273 legendY += chartTitleHeightPlusPadding; 274 275 this.pieY = legendY; 276 this.pieY += this.getLegend().getHeight(); 277 this.pieY += this.getLegend().getLegendProperties().getChartPadding(); 278 279 if( this.pieLabels != null ) 280 { 281 this.pieY += this.pieLabels.getTallestLabel(); 283 this.pieY += properties.getTickLength(); 284 } 285 } 286 287 legendX = halfImageWidth - ( this.getLegend().getWidth() / 2 ); 289 290 this.pieX = halfImageWidth - ( this.diameter / 2 ); 292 } 293 294 super.getLegend().setX( legendX ); 295 super.getLegend().setY( legendY ); 296 super.getLegend().render(); 297 298 } 299 else 301 { 302 this.diameter = Math.max( widthAvailable, 1.0f ); 305 306 this.diameter = Math.min( this.diameter, heightAvailable ); 308 309 this.pie3dWidth = this.diameter; 310 this.pie3dHeight = this.pie3dWidth * RATIO; 311 312 313 316 float halfDiameter = ( this.diameter + properties.getDepth() ) / 2; 317 318 this.pieX = halfImageWidth - halfDiameter; 320 321 324 this.pieY = halfImageHeight - ( ( this.pie3dHeight + properties.getDepth() ) / 2 ); 325 } 326 327 328 if( super.getGenerateImageMapFlag() ) 332 { 333 ImageMap imageMap = new ImageMap( iPieChartDataSet.getNumberOfDataItems() ); 334 super.setImageMap( imageMap ); 335 } 336 337 338 PieChart3D.render( this ); 339 } 340 341 342 347 static void render( PieChart3D pieChart3D ) 348 { 349 Graphics2D g2d = pieChart3D.getGraphics2D(); 350 PieChart3DProperties properties = (PieChart3DProperties) pieChart3D.iPieChartDataSet.getChartTypeProperties(); 351 352 353 int subdivisions = 3; 357 float halfDiameter = 0; 358 float xPieMiddle = 0; 359 float yPieMiddle = 0; 360 float imageMapPoints[][] = null; 361 if( pieChart3D.getImageMap() != null ) 362 { 363 halfDiameter = (float) ( pieChart3D.diameter / 2.0 ); 364 xPieMiddle = halfDiameter + pieChart3D.pieX; 365 yPieMiddle = halfDiameter + pieChart3D.pieY; 366 imageMapPoints = new float[pieChart3D.iPieChartDataSet.getNumberOfDataItems() * ( subdivisions + 1 )][2]; 367 } 368 369 370 float currentDegrees = properties.getZeroDegreeOffset(); 372 373 double percentageOfPie = 0; 374 375 376 377 if( pieChart3D.iPieChartDataSet.getNumberOfDataItems() == 1 ) 380 { 381 Arc2D.Double arc = new Arc2D.Double ( pieChart3D.pieX, 382 pieChart3D.pieY + properties.getDepth(), 383 pieChart3D.diameter, 384 pieChart3D.diameter, 385 currentDegrees, 386 360, 387 Arc2D.OPEN ); 388 389 390 for( int i = properties.getDepth(); i >= 0; i-- ) 392 { 393 g2d.setPaint( pieChart3D.iPieChartDataSet.getPaint( 0 ) ); 394 g2d.fill( arc ); 395 396 if( i == properties.getDepth() || i == 0 ) 397 { 398 properties.getBorderChartStroke().draw( g2d, arc ); 399 } 400 401 arc.y -= 1; 402 } 403 404 405 if( pieChart3D.getImageMap() != null ) 408 { 409 CircleMapArea circleMapArea = new CircleMapArea( xPieMiddle, yPieMiddle, pieChart3D.iPieChartDataSet.getValue( 0 ), null, pieChart3D.iPieChartDataSet.getLegendLabel( 0 ) ); 410 circleMapArea.setRadius( (int) pieChart3D.diameter ); 411 pieChart3D.getImageMap().addImageMapArea( circleMapArea ); 412 } 413 414 416 float x = pieChart3D.pieX + ( pieChart3D.diameter / 2 ) - ( pieChart3D.pieLabels.getTextTag( 0 ).getWidth() / 2 ); 417 float y = pieChart3D.pieY - properties.getTickLength(); 418 421 properties.getValueLabelFont().setupGraphics2D( g2d ); 422 g2d.drawString( pieChart3D.pieLabels.getTextTag( 0 ).getText(), x, y ); 423 } 424 else 425 { 426 Arc2D.Double arc = new Arc2D.Double ( pieChart3D.pieX, 427 pieChart3D.pieY + properties.getDepth(), 428 pieChart3D.pie3dWidth, 429 pieChart3D.pie3dHeight, 430 currentDegrees, 431 360, 432 Arc2D.PIE ); 433 434 435 Line2D.Float line = new Line2D.Float (); 437 line.x1 = pieChart3D.pieX + ( pieChart3D.pie3dWidth / 2 ); 438 line.y1 = pieChart3D.pieY + ( pieChart3D.pie3dHeight / 2 ); 439 line.x2 = line.x1; 440 line.y2 = line.y1 + properties.getDepth(); 441 properties.getBorderChartStroke().draw( g2d, line ); 442 443 444 for( int slider = properties.getDepth(); slider >= 0; slider-- ) 446 { 447 currentDegrees = properties.getZeroDegreeOffset(); 448 449 int mapCounter = 0; 451 452 for( int i = 0; i < pieChart3D.iPieChartDataSet.getNumberOfDataItems(); i++ ) 453 { 454 percentageOfPie = pieChart3D.pieChartDataProcessor.getPercentageOfPie( i ); 455 456 arc.setAngleStart( currentDegrees ); 457 arc.setAngleExtent( percentageOfPie ); 458 459 g2d.setPaint( pieChart3D.iPieChartDataSet.getPaint( i ) ); 461 g2d.fill( arc ); 462 463 464 drawFraming( slider, properties, g2d, arc, currentDegrees ); 466 467 468 if( pieChart3D.pieLabels != null && slider == 0 ) 470 { 471 double sliceCenterDegrees = ( currentDegrees ) + percentageOfPie / 2; 473 474 if( sliceCenterDegrees > 360 ) 475 { 476 sliceCenterDegrees -= 360; 477 } 478 479 480 481 483 484 492 518 519 520 xPieMiddle = (float) arc.x + pieChart3D.pie3dWidth / 2; 521 yPieMiddle = (float) arc.y + pieChart3D.pie3dHeight / 2; 522 523 524 Arc2D.Double circle = new Arc2D.Double ( pieChart3D.pieX, 525 pieChart3D.pieY, 526 pieChart3D.pie3dWidth, 527 pieChart3D.pie3dHeight, 528 currentDegrees, 529 percentageOfPie / 2, 530 Arc2D.PIE ); 531 Arc2D.Double circle2 = new Arc2D.Double ( pieChart3D.pieX - properties.getTickLength(), 532 pieChart3D.pieY - properties.getTickLength(), 533 pieChart3D.pie3dWidth + properties.getTickLength() * 2, 534 pieChart3D.pie3dHeight + properties.getTickLength() * 2, 535 currentDegrees, 536 percentageOfPie / 2, 537 Arc2D.PIE ); 538 539 properties.getBorderChartStroke().draw( g2d, new Line2D.Float ( circle.getEndPoint(), circle2.getEndPoint() ) ); 541 542 float borderXend = (float) circle2.getEndPoint().getX(); 543 float borderYend = (float) circle2.getEndPoint().getY(); 544 545 properties.getValueLabelFont().setupGraphics2D( g2d ); 546 547 548 float labelY = borderYend; 549 if( sliceCenterDegrees > 60 && sliceCenterDegrees < 120 ) 550 { 551 labelY -= pieChart3D.pieLabels.getTextTag( i ).getFontDescent(); 552 } 553 else if( sliceCenterDegrees > 240 && sliceCenterDegrees < 300 ) 554 { 555 labelY += pieChart3D.pieLabels.getTextTag( i ).getFontAscent(); 556 } 557 558 559 if( sliceCenterDegrees > 180 && sliceCenterDegrees < 360 ) 560 { 561 labelY+= properties.getDepth(); 562 } 563 564 if( sliceCenterDegrees > 90 && sliceCenterDegrees < 270 ) 565 { 566 g2d.drawString( pieChart3D.pieLabels.getTextTag( i ).getText(), 567 borderXend - pieChart3D.pieLabels.getTextTag( i ).getWidth() - properties.getTickLength(), 568 labelY ); 569 } 570 else 571 { 572 g2d.drawString( pieChart3D.pieLabels.getTextTag( i ).getText(), 573 borderXend + properties.getTickLength(), 574 labelY ); 575 } 576 } 577 578 579 if( pieChart3D.getImageMap() != null ) 582 { 583 double workDegrees = currentDegrees; 585 586 double cosOfBorder; 588 double sinOfBorder; 589 double splitDegree = percentageOfPie / subdivisions; 590 591 for( int j = 0; j <= subdivisions; j++ ) 592 { 593 cosOfBorder = Math.cos( Math.toRadians( workDegrees ) ); 594 sinOfBorder = Math.sin( Math.toRadians( workDegrees ) ); 595 596 imageMapPoints[mapCounter][0] = xPieMiddle + (float) ( cosOfBorder * halfDiameter ); 598 imageMapPoints[mapCounter][1] = yPieMiddle + (float) -( sinOfBorder * halfDiameter ); 599 600 604 mapCounter++; 605 workDegrees += splitDegree; 606 } 607 } 608 609 currentDegrees += percentageOfPie; 610 } 611 612 613 if( pieChart3D.getImageMap() != null ) 616 { 617 int counter = 0; 620 621 for( int i = 0; i < pieChart3D.iPieChartDataSet.getNumberOfDataItems(); i++ ) 623 { 624 int coordinateCounter = 0; 625 626 PolyMapArea polyMapArea = new PolyMapArea( 3 + subdivisions, pieChart3D.iPieChartDataSet.getValue( i ), null, pieChart3D.iPieChartDataSet.getLegendLabel( i ) ); 628 polyMapArea.addCoordinate( coordinateCounter++, xPieMiddle, yPieMiddle ); 629 630 for( int h = 0; h <= subdivisions; h++ ) 632 { 633 polyMapArea.addCoordinate( coordinateCounter++, imageMapPoints[counter][0], imageMapPoints[counter][1] ); 634 counter++; 635 } 636 637 if( ( i + 1 ) == pieChart3D.iPieChartDataSet.getNumberOfDataItems() ) 639 { 640 polyMapArea.addCoordinate( coordinateCounter, imageMapPoints[0][0], imageMapPoints[0][1] ); 641 } 642 else 644 { 645 polyMapArea.addCoordinate( coordinateCounter, imageMapPoints[counter][0], imageMapPoints[counter][1] ); 646 } 647 648 pieChart3D.getImageMap().addImageMapArea( polyMapArea ); 649 } 650 } 651 652 arc.y -= 1; 654 } 655 656 665 666 } 667 } 668 669 670 678 private static void drawFraming( int slider, 679 PieChart3DProperties properties, 680 Graphics2D g2d, 681 Arc2D.Double arc, 682 float currentDegrees ) 683 { 684 if( slider == properties.getDepth() || slider == 0 ) 686 { 687 properties.getBorderChartStroke().draw( g2d, arc ); 688 689 if( slider == properties.getDepth() ) 692 { 693 if( currentDegrees > 0 && currentDegrees < 180 ) 694 { 695 properties.getBorderChartStroke().draw( g2d, new Line2D.Double ( arc.getStartPoint().getX(), 696 arc.getStartPoint().getY(), 697 arc.getStartPoint().getX(), 698 arc.getStartPoint().getY() - properties.getDepth() ) ); 699 } 700 } 701 else if( slider == 0 ) 702 { 703 if( currentDegrees == 0 || ( currentDegrees >= 180 && currentDegrees < 360 ) ) 704 { 705 properties.getBorderChartStroke().draw( g2d, new Line2D.Double ( arc.getStartPoint().getX(), 706 arc.getStartPoint().getY(), 707 arc.getStartPoint().getX(), 708 arc.getStartPoint().getY() + properties.getDepth() ) ); 709 } 710 } 711 } 712 } 713 714 715 722 public void toHTML( HTMLGenerator htmlGenerator, String imageFileName ) 723 { 724 if( this.getLegend() != null ) 725 { 726 htmlGenerator.chartTableRowStart(); 727 this.getLegend().toHTML( htmlGenerator ); 728 htmlGenerator.chartTableRowEnd(); 729 } 730 731 htmlGenerator.chartTableEnd(); 732 } 733 734 } 735 | Popular Tags |