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.PieChart2DProperties; 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 63 public class PieChart2D extends Chart implements HTMLChartTestable 64 { 65 private float pieX; 66 private float pieY; 67 private float diameter; 68 69 private IPieChartDataSet iPieChartDataSet; 70 private PieChartDataProcessor pieChartDataProcessor; 71 72 private PieLabels pieLabels; 73 74 75 84 public PieChart2D( IPieChartDataSet iPieChartDataSet, 85 LegendProperties legendProperties, 86 ChartProperties chartProperties, 87 int pixelWidth, 88 int pixelHeight ) 89 { 90 super( legendProperties, chartProperties, pixelWidth, pixelHeight ); 91 this.iPieChartDataSet = iPieChartDataSet; 92 } 93 94 95 99 protected void renderChart() 100 { 101 PieChart2DProperties properties = (PieChart2DProperties) this.iPieChartDataSet.getChartTypeProperties(); 102 FontRenderContext fontRenderContext = super.getGraphics2D().getFontRenderContext(); 103 104 this.pieChartDataProcessor = new PieChartDataProcessor( this.iPieChartDataSet ); 105 this.pieChartDataProcessor.processData(); 106 107 108 float edgePaddingTimesTwo = super.getChartProperties().getEdgePadding() * 2; 110 float halfImageWidth = super.getImageWidth() / 2; 111 float halfImageHeight = super.getImageHeight() / 2; 112 113 114 float chartTitleHeightPlusPadding = super.renderChartTitle( this.iPieChartDataSet.getChartTitle(), fontRenderContext ); 116 117 118 float widthAvailable = super.getImageWidth() - edgePaddingTimesTwo; 120 float heightAvailable = super.getImageHeight() - edgePaddingTimesTwo; 121 heightAvailable -= chartTitleHeightPlusPadding; 122 123 124 if( !properties.getPieLabelType().equals( PieLabelType.NO_LABELS ) ) 126 { 127 this.pieLabels = new PieLabels( properties, this.iPieChartDataSet, fontRenderContext ); 128 129 if( iPieChartDataSet.getNumberOfDataItems() != 1 ) 131 { 132 widthAvailable -= this.pieLabels.getWidestLabelTimesTwo(); 133 widthAvailable -= ( properties.getTickLength() * 2 ); 134 } 135 136 heightAvailable -= this.pieLabels.getTallestLabelTimesTwo(); 137 heightAvailable -= ( properties.getTickLength() * 2 ); 138 } 139 140 141 if( this.getLegend() != null ) 143 { 144 float legendX = 0f; 145 float legendY = 0f; 146 147 this.getLegend().calculateDrawingValues( iPieChartDataSet ); 149 150 151 if( ( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT ) 153 || ( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.LEFT ) ) 154 { 155 widthAvailable -= this.getLegend().getWidth(); 156 widthAvailable -= this.getLegend().getLegendProperties().getChartPadding(); 157 158 159 this.diameter = Math.max( widthAvailable, 1.0f ); 162 163 this.diameter = Math.min( this.diameter, heightAvailable ); 165 166 167 float plotWidth = this.diameter; 169 plotWidth += this.getLegend().getWidth(); 170 plotWidth += this.getLegend().getLegendProperties().getChartPadding(); 171 if( this.pieLabels != null ) 172 { 173 plotWidth += ( this.pieLabels.getWidestLabel() * 2 ); 174 plotWidth += ( properties.getTickLength() * 2 ); 175 } 176 177 if( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.RIGHT ) 178 { 179 this.pieX = halfImageWidth - ( plotWidth / 2 ); 181 182 if( this.pieLabels != null ) 183 { 184 this.pieX += this.pieLabels.getWidestLabel(); 185 this.pieX += properties.getTickLength(); 186 legendX += this.pieLabels.getWidestLabel(); 187 legendX += properties.getTickLength(); 188 } 189 190 legendX += this.pieX + this.diameter; 192 legendX += this.getLegend().getLegendProperties().getChartPadding(); 193 } 194 else 195 { 196 legendX = halfImageWidth - ( plotWidth / 2 ); 197 198 if( this.pieLabels != null ) 199 { 200 this.pieX = legendX; 201 this.pieX += this.getLegend().getWidth(); 202 this.pieX += this.getLegend().getLegendProperties().getChartPadding(); 203 this.pieX += this.pieLabels.getWidestLabel(); 204 this.pieX += properties.getTickLength(); 205 } 206 } 207 208 legendY = halfImageHeight - ( this.getLegend().getHeight() / 2 ); 210 211 this.pieY = halfImageHeight - ( this.diameter / 2 ); 213 } 214 else 216 { 217 heightAvailable-= this.getLegend().getHeight(); 218 heightAvailable-= this.getLegend().getLegendProperties().getChartPadding(); 219 220 this.diameter = Math.max( heightAvailable, 1.0f ); 223 224 this.diameter = Math.min( this.diameter, widthAvailable ); 226 227 228 if( this.getLegend().getLegendProperties().getPlacement() == LegendAreaProperties.BOTTOM ) 229 { 230 this.pieY = super.getChartProperties().getEdgePadding(); 231 this.pieY += chartTitleHeightPlusPadding; 232 233 legendY+= this.diameter; 234 235 if( this.pieLabels != null ) 236 { 237 this.pieY += this.pieLabels.getTallestLabel(); 239 this.pieY += properties.getTickLength(); 240 241 legendY += this.pieLabels.getTallestLabel(); 243 legendY += properties.getTickLength(); 244 } 245 246 legendY += this.pieY; 247 legendY+= this.getLegend().getLegendProperties().getChartPadding(); 248 } 249 else 250 { 251 legendY = super.getChartProperties().getEdgePadding(); 252 legendY += chartTitleHeightPlusPadding; 253 254 this.pieY= legendY; 255 this.pieY+= this.getLegend().getHeight(); 256 this.pieY+= this.getLegend().getLegendProperties().getChartPadding(); 257 258 if( this.pieLabels != null ) 259 { 260 this.pieY += this.pieLabels.getTallestLabel(); 262 this.pieY += properties.getTickLength(); 263 } 264 } 265 266 legendX = halfImageWidth - ( this.getLegend().getWidth() / 2 ); 268 269 this.pieX = halfImageWidth - ( this.diameter / 2 ); 271 } 272 273 super.getLegend().setX( legendX ); 274 super.getLegend().setY( legendY ); 275 super.getLegend().render(); 276 277 } 278 else 280 { 281 this.diameter = Math.min( heightAvailable, widthAvailable ); 283 284 float halfDiameter = this.diameter / 2; 285 286 this.pieX = halfImageWidth - halfDiameter; 288 289 this.pieY = halfImageHeight - halfDiameter; 291 } 292 293 294 if( super.getGenerateImageMapFlag() ) 298 { 299 ImageMap imageMap = new ImageMap( iPieChartDataSet.getNumberOfDataItems() ); 300 super.setImageMap( imageMap ); 301 } 302 303 304 PieChart2D.render( this ); 305 } 306 307 308 313 static void render( PieChart2D pieChart2D ) 314 { 315 Graphics2D g2d = pieChart2D.getGraphics2D(); 316 PieChart2DProperties properties = (PieChart2DProperties) pieChart2D.iPieChartDataSet.getChartTypeProperties(); 317 318 properties.getBorderChartStroke().setupGraphics2D( g2d ); 320 321 322 int subdivisions = 3; 326 float halfDiameter = 0; 327 float xPieMiddle = 0; 328 float yPieMiddle = 0; 329 float imageMapPoints[][] = null; 330 if( pieChart2D.getImageMap() != null ) 331 { 332 halfDiameter = (float) ( pieChart2D.diameter / 2.0 ); 333 xPieMiddle = halfDiameter + pieChart2D.pieX; 334 yPieMiddle = halfDiameter + pieChart2D.pieY; 335 imageMapPoints = new float[pieChart2D.iPieChartDataSet.getNumberOfDataItems() * ( subdivisions + 1 )][2]; 336 } 337 338 339 float currentDegrees = properties.getZeroDegreeOffset(); 341 342 double percentageOfPie = 0; 343 344 345 346 if( pieChart2D.iPieChartDataSet.getNumberOfDataItems() == 1 ) 349 { 350 Arc2D.Double arc = new Arc2D.Double ( pieChart2D.pieX, 351 pieChart2D.pieY, 352 pieChart2D.diameter, 353 pieChart2D.diameter, 354 currentDegrees, 355 360, 356 Arc2D.OPEN ); 357 358 g2d.setPaint( pieChart2D.iPieChartDataSet.getPaint( 0 ) ); 359 g2d.fill( arc ); 360 361 properties.getBorderChartStroke().draw( g2d, arc ); 362 363 if( pieChart2D.getImageMap() != null ) 366 { 367 CircleMapArea circleMapArea = new CircleMapArea( xPieMiddle, yPieMiddle, pieChart2D.iPieChartDataSet.getValue( 0 ), null, pieChart2D.iPieChartDataSet.getLegendLabel( 0 ) ); 368 circleMapArea.setRadius( (int) pieChart2D.diameter ); 369 pieChart2D.getImageMap().addImageMapArea( circleMapArea ); 370 } 371 372 374 if( pieChart2D.pieLabels != null ) 375 { 376 float x = pieChart2D.pieX + ( pieChart2D.diameter / 2 ) - ( pieChart2D.pieLabels.getTextTag( 0 ).getWidth() / 2 ); 377 float y = pieChart2D.pieY - properties.getTickLength(); 378 381 properties.getValueLabelFont().setupGraphics2D( g2d ); 382 g2d.drawString( pieChart2D.pieLabels.getTextTag( 0 ).getText(), x, y ); 383 } 384 } 385 else 386 { 387 Arc2D.Double arc = new Arc2D.Double ( pieChart2D.pieX, 388 pieChart2D.pieY, 389 pieChart2D.diameter, 390 pieChart2D.diameter, 391 currentDegrees, 392 360, 393 Arc2D.PIE ); 394 int mapCounter = 0; 396 397 for( int i = 0; i < pieChart2D.iPieChartDataSet.getNumberOfDataItems(); i++ ) 398 { 399 percentageOfPie = pieChart2D.pieChartDataProcessor.getPercentageOfPie( i ); 400 401 arc.setAngleStart( currentDegrees ); 402 arc.setAngleExtent( percentageOfPie ); 403 404 g2d.setPaint( pieChart2D.iPieChartDataSet.getPaint( i ) ); 406 g2d.fill( arc ); 407 408 properties.getBorderChartStroke().draw( g2d, arc ); 409 410 411 if( pieChart2D.pieLabels != null ) 413 { 414 double sliceCenterDegrees = ( currentDegrees ) + percentageOfPie / 2; 416 417 if( sliceCenterDegrees > 360 ) 418 { 419 sliceCenterDegrees -= 360; 420 } 421 422 423 double sliceCenterRadians = Math.toRadians( sliceCenterDegrees ); 424 425 double cosOfLabel = Math.cos( sliceCenterRadians ); 427 double sinOfLabel = Math.sin( sliceCenterRadians ); 428 429 halfDiameter = (float) ( pieChart2D.diameter / 2.0 ); 430 431 432 float borderXstart = (float) ( cosOfLabel * halfDiameter ); 434 float borderYstart = (float) -( sinOfLabel * halfDiameter ); 435 436 float borderXend = (float) ( cosOfLabel * ( halfDiameter + properties.getTickLength() ) ); 438 float borderYend = (float) -( sinOfLabel * ( halfDiameter + properties.getTickLength() ) ); 439 440 441 xPieMiddle = halfDiameter + pieChart2D.pieX; 442 yPieMiddle = halfDiameter + pieChart2D.pieY; 443 444 properties.getValueLabelFont().setupGraphics2D( g2d ); 445 446 g2d.draw( new Line2D.Double ( xPieMiddle + borderXstart, 447 yPieMiddle + borderYstart, 448 xPieMiddle + borderXend, 449 yPieMiddle + borderYend ) ); 450 451 453 float labelY = yPieMiddle + borderYend; 454 if( sliceCenterDegrees > 60 && sliceCenterDegrees < 120 ) 455 { 456 labelY -= pieChart2D.pieLabels.getTextTag( i ).getFontDescent(); 457 } 458 else if( sliceCenterDegrees > 240 && sliceCenterDegrees < 300 ) 459 { 460 labelY += pieChart2D.pieLabels.getTextTag( i ).getFontAscent(); 461 } 462 463 464 if( sliceCenterDegrees > 90 && sliceCenterDegrees < 270 ) 465 { 466 g2d.drawString( pieChart2D.pieLabels.getTextTag( i ).getText(), 467 xPieMiddle + borderXend - pieChart2D.pieLabels.getTextTag( i ).getWidth() - properties.getTickLength(), 468 labelY ); 469 } 470 else 471 { 472 g2d.drawString( pieChart2D.pieLabels.getTextTag( i ).getText(), 473 xPieMiddle + borderXend + properties.getTickLength(), 474 labelY ); 475 } 476 } 477 478 479 if( pieChart2D.getImageMap() != null ) 482 { 483 double workDegrees = currentDegrees; 485 486 double cosOfBorder; 488 double sinOfBorder; 489 double splitDegree = percentageOfPie / subdivisions; 490 491 for( int j = 0; j <= subdivisions; j++ ) 492 { 493 cosOfBorder = Math.cos( Math.toRadians( workDegrees ) ); 494 sinOfBorder = Math.sin( Math.toRadians( workDegrees ) ); 495 496 imageMapPoints[mapCounter][0] = xPieMiddle + (float) ( cosOfBorder * halfDiameter ); 498 imageMapPoints[mapCounter][1] = yPieMiddle + (float) -( sinOfBorder * halfDiameter ); 499 500 504 mapCounter++; 505 workDegrees += splitDegree; 506 } 507 } 508 509 currentDegrees += percentageOfPie; 510 } 511 512 513 if( pieChart2D.getImageMap() != null ) 516 { 517 int counter = 0; 520 521 for( int i = 0; i < pieChart2D.iPieChartDataSet.getNumberOfDataItems(); i++ ) 523 { 524 int coordinateCounter = 0; 525 526 PolyMapArea polyMapArea = new PolyMapArea( 3 + subdivisions, pieChart2D.iPieChartDataSet.getValue( i ), null, pieChart2D.iPieChartDataSet.getLegendLabel( i ) ); 528 polyMapArea.addCoordinate( coordinateCounter++, xPieMiddle, yPieMiddle ); 529 530 for( int h = 0; h <= subdivisions; h++ ) 532 { 533 polyMapArea.addCoordinate( coordinateCounter++, imageMapPoints[counter][0], imageMapPoints[counter][1] ); 534 counter++; 535 } 536 537 if( ( i + 1 ) == pieChart2D.iPieChartDataSet.getNumberOfDataItems() ) 539 { 540 polyMapArea.addCoordinate( coordinateCounter, imageMapPoints[0][0], imageMapPoints[0][1] ); 541 } 542 else 544 { 545 polyMapArea.addCoordinate( coordinateCounter, imageMapPoints[counter][0], imageMapPoints[counter][1] ); 546 } 547 548 pieChart2D.getImageMap().addImageMapArea( polyMapArea ); 549 } 550 } 551 } 552 } 553 554 555 562 public void toHTML( HTMLGenerator htmlGenerator, String imageFileName ) 563 { 564 if( this.getLegend() != null ) 565 { 566 htmlGenerator.chartTableRowStart(); 567 this.getLegend().toHTML( htmlGenerator ); 568 htmlGenerator.chartTableRowEnd(); 569 } 570 571 htmlGenerator.chartTableEnd(); 572 } 573 574 } 575 | Popular Tags |