1 22 23 24 package net.sourceforge.chart2d; 25 26 27 import java.awt.*; 28 import java.awt.geom.*; 29 import java.util.*; 30 31 32 50 final class LBGraphArea extends GraphArea { 51 52 private FancyBar[][] bars; 53 private FancyDot[][] dots; 54 private FancyLine[] lines; 55 private boolean needsUpdate; 56 57 58 62 LBGraphArea() { 63 64 bars = new FancyBar[0][0]; 65 dots = new FancyDot[0][0]; 66 lines = new FancyLine[0]; 67 68 setBarRoundingRatio (.25f); 69 70 resetLBGraphAreaModel (true); 71 needsUpdate = true; 72 } 73 74 75 82 final int getPrefSpaceWidth (int numSets, int numCats, int numCompsPerCat) { 83 84 float ratio = getRatio (WIDTH); 85 int barsWidth = 0, dotsWidth = 0, linesWidth = 0, prefWidth = 0; 86 if (getAllowComponentAlignment()) { 87 barsWidth = getBarsExistence() ? 88 (int)(numCats * (1 + (1 - getBarsWithinCategoryOverlapRatio()) * 89 (numCompsPerCat - 1)) * 90 applyRatio (getBarsThicknessModel(), ratio)) : 0; 91 dotsWidth = getDotsExistence() ? 92 (int)(numCats * (1 + (1 - getDotsWithinCategoryOverlapRatio()) * 93 (numCompsPerCat - 1)) * 94 applyRatio (getDotsThicknessModel(), ratio)) : 0; 95 linesWidth = getLinesExistence() ? 96 (int)(numCats * (1 + (1 - getLinesWithinCategoryOverlapRatio()) * 97 (numCompsPerCat - 1)) * 98 applyRatio (getLinesThicknessModel(), ratio)) : 0; 99 } 100 else { 101 barsWidth = getBarsExistence() ? 102 (int)(numSets * numCats * 103 (1 + (1 - getBarsWithinCategoryOverlapRatio()) * 104 (numCompsPerCat - 1)) * 105 applyRatio (getBarsThicknessModel(), ratio)) : 0; 106 dotsWidth = getDotsExistence() ? 107 (int)(numSets * numCats * (1 + 108 (1 - getDotsWithinCategoryOverlapRatio()) * 109 (numCompsPerCat - 1)) * 110 applyRatio (getDotsThicknessModel(), ratio)) : 0; 111 linesWidth = getLinesExistence() ? 112 (int)(numSets * numCats * (1 + 113 (1 - getLinesWithinCategoryOverlapRatio()) * 114 (numCompsPerCat - 1)) * 115 applyRatio (getLinesThicknessModel(), ratio)) : 0; 116 117 } 118 prefWidth = barsWidth > dotsWidth ? barsWidth : dotsWidth; 119 prefWidth = prefWidth > linesWidth ? prefWidth : linesWidth; 120 int gapsWidth = getBetweenComponentsGapExistence() ? 121 numCats * applyRatio (getBetweenComponentsGapThicknessModel(), ratio) : 0; 122 prefWidth = prefWidth + gapsWidth; 123 prefWidth = prefWidth < getSpaceSize(MAX).width ? prefWidth : getSpaceSize(MAX).width; 124 return (prefWidth); 125 } 126 127 128 132 final boolean getLBGraphAreaNeedsUpdate() { 133 134 return (needsUpdate || getGraphAreaNeedsUpdate()); 135 } 136 137 138 150 final void resetLBGraphAreaModel (boolean reset) { 151 152 needsUpdate = true; 153 resetGraphAreaModel (reset); 154 } 155 156 157 160 final void updateLBGraphArea() { 161 162 if (getLBGraphAreaNeedsUpdate()) { 163 updateGraphArea(); 164 update(); 165 } 166 needsUpdate = false; 167 } 168 169 170 174 final void paintComponent (Graphics2D g2D) { 175 176 updateLBGraphArea(); 177 super.paintComponent (g2D); 178 179 Shape oldClip = g2D.getClip(); 180 if (getClip()) g2D.setClip (new Rectangle (getSpaceSizeLocation (MIN), getSpaceSize (MIN))); 181 182 Composite oldComposite = g2D.getComposite(); 183 g2D.setComposite (getComponentsAlphaComposite()); 184 185 int numBars = bars.length > 0 ? bars[0].length : 0; 186 int numDots = dots.length > 0 ? dots[0].length : 0; 187 int numLines = lines.length; 188 int numSets = getGraphValues().length; 189 if (!getAllowComponentAlignment() && numBars > 0) { 190 for (int i = 0; i < numSets; ++i) { 191 for (int j = 0; j < numBars; ++j) { 192 bars[i][j].paint (g2D); 193 } 194 } 195 } 196 else if (numBars > 0) { 197 int[][] graphValues = getGraphValues(); 198 graphValues = stackedBarConvert (graphValues, getBarLowValues()); 199 for (int j = 0; j < numBars; ++j) { 200 int[] sorted = stackedBarSort (graphValues, j); 201 for (int i = 0; i < numSets; ++i) { 202 bars[sorted[i]][j].paint (g2D); 203 } 204 } 205 } 206 207 for (int i = numLines - 1; i >= 0 ; --i) lines[i].paint (g2D); 208 209 for (int i = numSets - 1; i >= 0; --i) { 210 for (int j = numDots - 1; j >= 0 ; --j) { 211 dots[i][j].paint (g2D); 212 } 213 } 214 215 g2D.setClip (oldClip); 216 g2D.setComposite (oldComposite); 217 } 218 219 220 private void update() { 221 222 if (getAllowComponentAlignment()) updateAllowAlignment(); 223 else updateDisallowAlignment(); 224 } 225 226 227 private void updateDisallowAlignment() { 228 229 int[][] graphLengths = getGraphValues(); 230 int numBars = 0, numDots = 0, numLinePoints = 0, numGaps = 0; 231 int numSets = graphLengths.length; 232 Rectangle[] xTicks = getXTicks(); 233 int numCompsPerCat = 0; 234 int numCats = 0; 235 if (numSets > 0) { 236 numCats = getLabelsAxisTicksAlignment() == BETWEEN ? 237 xTicks.length + 1 : xTicks.length; 238 numBars = getBarsExistence() ? numCats : 0; 239 numDots = getDotsExistence() ? numCats : 0; 240 numLinePoints = getLinesExistence() ? numCats : 0; 241 numGaps = getBetweenComponentsGapExistence() ? numCats : 0; 242 numCompsPerCat = 243 numCats > 0 ? (int)(graphLengths[0].length / numCats) : 0; 244 } 245 if (numSets > 0 && numCats > 0 && numCompsPerCat > 0) { 246 247 float ratio = getRatio (WIDTH); 248 int availableThickness = getSpaceSize(MIN).width; 249 250 int betweenComponentsGapThickness = 0; 251 if (numGaps > 0) { 252 betweenComponentsGapThickness = 253 applyRatio (getBetweenComponentsGapThicknessModel(), ratio); 254 betweenComponentsGapThickness = 255 numGaps * betweenComponentsGapThickness <= availableThickness ? 256 betweenComponentsGapThickness : availableThickness / numGaps; 257 availableThickness -= numGaps * betweenComponentsGapThickness; 258 } 259 260 int barsThickness = 0; 261 if (numBars > 0) { 262 barsThickness = applyRatio (getBarsThicknessModel(), ratio); 263 if ((numSets * numBars * numCompsPerCat) * barsThickness <= 264 availableThickness) { 265 float leftover = 266 (availableThickness - barsThickness * 267 (numSets * numBars * numCompsPerCat)) / 268 (numSets * numBars * numCompsPerCat); 269 barsThickness = 270 barsThickness + (int)(getBarsExcessSpaceFeedbackRatio() * leftover); 271 } 272 else { 273 float numOverlapBarsPerCat = 274 (1 + (1 - getBarsWithinCategoryOverlapRatio()) * 275 (numCompsPerCat - 1)); 276 if (numSets * numBars * numOverlapBarsPerCat * barsThickness > 277 availableThickness) { 278 barsThickness = (int)(availableThickness / 279 (numSets * numBars * numOverlapBarsPerCat)); 280 } 281 } 282 } 283 int dotsThickness = 0; 284 if (numDots > 0) { 285 dotsThickness = applyRatio (getDotsThicknessModel(), getRatio (LESSER)); 286 if ((numSets * numDots * numCompsPerCat) * dotsThickness <= 287 availableThickness) { 288 float leftover = 289 (availableThickness - dotsThickness * 290 (numSets * numDots * numCompsPerCat)) / 291 (numSets * numDots * numCompsPerCat); 292 dotsThickness = 293 dotsThickness + (int)(getDotsExcessSpaceFeedbackRatio() * leftover); 294 } 295 else { 296 float numOverlapDotsPerCat = 297 (1 + (1 - getDotsWithinCategoryOverlapRatio()) * 298 (numCompsPerCat - 1)); 299 if (numSets * numDots * numOverlapDotsPerCat * dotsThickness > 300 availableThickness) { 301 dotsThickness = (int)(availableThickness / 302 (numSets * numDots * numOverlapDotsPerCat)); 303 } 304 } 305 } 306 int linesThickness = 0; 307 if (numLinePoints > 0) { 308 linesThickness = applyRatio (getLinesThicknessModel(), getRatio (LESSER)); 309 if ((numSets * numLinePoints * numCompsPerCat) * linesThickness <= 310 availableThickness) { 311 float leftover = 312 (availableThickness - linesThickness * 313 (numSets * numLinePoints * numCompsPerCat)) / 314 (numSets * numLinePoints * numCompsPerCat); 315 linesThickness = 316 linesThickness + (int)(getLinesExcessSpaceFeedbackRatio() * leftover); 317 } 318 else { 319 float numOverlapLinesPerCat = 320 (1 + (1 - getLinesWithinCategoryOverlapRatio()) * 321 (numCompsPerCat - 1)); 322 if (numSets * numLinePoints * numOverlapLinesPerCat * linesThickness > 323 availableThickness) { 324 linesThickness = (int)(availableThickness / 325 (numSets * numLinePoints * numOverlapLinesPerCat)); 326 } 327 } 328 } 329 330 int componentsThickness = barsThickness; 331 componentsThickness = dotsThickness > componentsThickness ? 332 dotsThickness : componentsThickness; 333 componentsThickness = linesThickness > componentsThickness ? 334 linesThickness : componentsThickness; 335 int setsThickness = componentsThickness * numSets; 336 setsThickness = 337 setsThickness > availableThickness / (numCats * numCompsPerCat) ? 338 availableThickness / (numCats * numCompsPerCat) : setsThickness; 339 componentsThickness = setsThickness / numSets; 340 341 Rectangle2D.Float boundsGraph = new Rectangle2D.Float ( 342 getSpaceSizeLocation (MIN).x, getSpaceSizeLocation (MIN).y, 343 getSpaceSize (MIN).width, getSpaceSize (MIN).height); 344 345 bars = new FancyBar[numSets][numBars * numCompsPerCat]; 346 int[][] barLowValues = getBarLowValues(); 347 if (numBars > 0) { 348 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height, x = 0; 349 float catDelta = 350 getSpaceSize (MIN).width / (float)(numBars * numCompsPerCat); 351 if (numBars == 1) { 352 x = getSpaceSizeLocation (MIN).x + 353 (getSpaceSize(MIN).width - setsThickness) / 2; 354 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 355 for (int k = 0; k < numCompsPerCat; ++k) { 356 for (int j = 0; j < numSets; ++j) { 357 int compX = x + j * componentsThickness + 358 (componentsThickness - barsThickness) / 2; 359 bars[j][k] = new FancyBar(); 360 bars[j][k].setDataSign (getDataSign()); 361 bars[j][k].setBaseValue (y - getLinesFillInteriorBaseValue()); 362 if (graphLengths[j][k] > barLowValues[j][k]) { 363 bars[j][k].setBounds (new Rectangle2D.Float ( 364 compX + k * catDelta, y - graphLengths[j][k], 365 barsThickness, graphLengths[j][k] - barLowValues[j][k])); 366 } 367 else { 368 bars[j][k].setBounds (new Rectangle2D.Float ( 369 compX + k * catDelta, y - barLowValues[j][k], 370 barsThickness, barLowValues[j][k] - graphLengths[j][k])); 371 } 372 Rectangle2D.Float clipBounds = new Rectangle2D.Float ( 373 boundsGraph.x, bars[j][k].getBounds().y, 374 boundsGraph.width, bars[j][k].getBounds().height); 375 bars[j][k].setClipBounds (clipBounds); 376 bars[j][k].setLightBounds ( 377 getComponentsLightType() == COMPONENT ? bars[j][k].getBounds() : boundsGraph); 378 bars[j][k].setLightSource (getComponentsLightSource()); 379 bars[j][k].setColor (!getComponentsColoringByCat() ? 380 getBarColors()[j] : getComponentsColorsByCat()[0]); 381 bars[j][k].setOutlineExistence (getOutlineComponents()); 382 bars[j][k].setOutlineColor (getOutlineComponentsColor()); 383 bars[j][k].setArcw (getBarRoundingRatio() * barsThickness); 384 bars[j][k].setArch (getBarRoundingRatio() * barsThickness); 385 bars[j][k].setWarningRegions (getWarningRegions()); 386 bars[j][k].setType (FancyShape.LABELSBOTTOM); 387 bars[j][k].setGraphBounds (boundsGraph); 388 } 389 } 390 } 391 else { 392 float minX, maxX, tickHalfWidth; 393 minX = getSpaceSizeLocation (MIN).x; 394 tickHalfWidth = xTicks[0].width / 2f; 395 maxX = xTicks[0].x + tickHalfWidth; 396 int i = 0; 397 do { 398 if (getLabelsAxisTicksAlignment() == this.BETWEEN) { 399 x = (int)(minX + Math.floor((maxX - minX - setsThickness) / 2f)); 400 } 401 else x = (int)Math.floor (maxX - setsThickness / 2f); 402 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 403 for (int k = 0; k < numCompsPerCat; ++k) { 404 for (int j = 0; j < numSets; ++j) { 405 int compX = x + j * componentsThickness + 406 (componentsThickness - barsThickness) / 2; 407 bars[j][i * numCompsPerCat + k] = new FancyBar(); 408 bars[j][i * numCompsPerCat + k].setDataSign (getDataSign()); 409 bars[j][i * numCompsPerCat + k].setBaseValue (y - getLinesFillInteriorBaseValue()); 410 if (graphLengths[j][i * numCompsPerCat + k] > 411 barLowValues[j][i * numCompsPerCat + k]) { 412 bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 413 compX + k * catDelta, y - graphLengths[j][i * numCompsPerCat + k], 414 barsThickness, graphLengths[j][i * numCompsPerCat + k] - 415 barLowValues[j][i * numCompsPerCat + k])); 416 } 417 else { 418 bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 419 compX + k * catDelta, y - barLowValues[j][i * numCompsPerCat + k], 420 barsThickness, barLowValues[j][i * numCompsPerCat + k] - 421 graphLengths[j][i * numCompsPerCat + k])); 422 } 423 Rectangle2D.Float clipBounds = new Rectangle2D.Float ( 424 boundsGraph.x, bars[j][i * numCompsPerCat + k].getBounds().y, 425 boundsGraph.width, bars[j][i * numCompsPerCat + k].getBounds().height); 426 bars[j][i * numCompsPerCat + k].setClipBounds (clipBounds); 427 bars[j][i * numCompsPerCat + k].setLightBounds ( 428 getComponentsLightType() == COMPONENT ? 429 bars[j][i * numCompsPerCat + k].getBounds() : boundsGraph); 430 bars[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource()); 431 bars[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ? 432 getBarColors()[j] : getComponentsColorsByCat()[i]); 433 bars[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents()); 434 bars[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor()); 435 bars[j][i * numCompsPerCat + k].setArcw (getBarRoundingRatio() * barsThickness); 436 bars[j][i * numCompsPerCat + k].setArch (getBarRoundingRatio() * barsThickness); 437 bars[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions()); 438 bars[j][i * numCompsPerCat + k].setType (FancyShape.LABELSBOTTOM); 439 bars[j][i * numCompsPerCat + k].setGraphBounds (boundsGraph); 440 } 441 } 442 if (i + 1 == numBars) break; 443 minX = maxX; 444 if (i + 2 == numBars && 445 getLabelsAxisTicksAlignment() == this.BETWEEN) { 446 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 447 } 448 else maxX = xTicks[i + 1].x + tickHalfWidth; 449 ++i; 450 } while (true); 451 } 452 } 453 454 dots = new FancyDot[numSets][numDots * numCompsPerCat]; 455 if (numDots > 0) { 456 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height - 457 dotsThickness / 2, x; 458 float catDelta = 459 getSpaceSize (MIN).width / (float)(numDots * numCompsPerCat); 460 if (numDots == 1) { 461 x = getSpaceSizeLocation (MIN).x + 462 (getSpaceSize(MIN).width - setsThickness) / 2; 463 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 464 for (int k = 0; k < numCompsPerCat; ++k) { 465 for (int j = 0; j < numSets; ++j) { 466 int compX = x + j * componentsThickness + 467 (componentsThickness - dotsThickness) / 2; 468 dots[j][k] = new FancyDot(); 469 dots[j][k].setBounds (new Rectangle2D.Float ( 470 compX + k * catDelta, y - graphLengths[j][k], dotsThickness, dotsThickness)); 471 dots[j][k].setClipBounds (dots[j][k].getBounds()); 472 dots[j][k].setColor (!getComponentsColoringByCat() ? 473 getDotColors()[j] : getComponentsColorsByCat()[0]); 474 dots[j][k].setOutlineExistence (getOutlineComponents()); 475 dots[j][k].setOutlineColor (getOutlineComponentsColor()); 476 dots[j][k].setLightBounds ( 477 getComponentsLightType() == COMPONENT ? dots[j][k].getBounds() : boundsGraph); 478 dots[j][k].setLightSource (getComponentsLightSource()); 479 dots[j][k].setWarningRegions (getWarningRegions()); 480 dots[j][k].setType (FancyShape.LABELSBOTTOM); 481 } 482 } 483 } 484 else { 485 float minX, maxX, tickHalfWidth; 486 minX = getSpaceSizeLocation (MIN).x; 487 tickHalfWidth = xTicks[0].width / 2f; 488 maxX = xTicks[0].x + tickHalfWidth; 489 int i = 0; 490 do { 491 if (getLabelsAxisTicksAlignment() == this.BETWEEN) { 492 x = (int)(minX + Math.floor((maxX - minX - setsThickness) / 2f)); 493 } 494 else x = (int)Math.floor (maxX - setsThickness / 2f); 495 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 496 for (int k = 0; k < numCompsPerCat; ++k) { 497 for (int j = 0; j < numSets; ++j) { 498 int compX = x + j * componentsThickness + 499 (componentsThickness - dotsThickness) / 2; 500 dots[j][i * numCompsPerCat + k] = new FancyDot(); 501 dots[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 502 compX + k * catDelta, y - graphLengths[j][i * numCompsPerCat + k], 503 dotsThickness, dotsThickness)); 504 dots[j][i * numCompsPerCat + k].setClipBounds ( 505 dots[j][i * numCompsPerCat + k].getBounds()); 506 dots[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ? 507 getDotColors()[j] : getComponentsColorsByCat()[i]); 508 dots[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents()); 509 dots[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor()); 510 dots[j][i * numCompsPerCat + k].setLightBounds ( 511 getComponentsLightType() == COMPONENT ? 512 dots[j][i * numCompsPerCat + k].getBounds() : boundsGraph); 513 dots[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource()); 514 dots[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions()); 515 dots[j][i * numCompsPerCat + k].setType (FancyShape.LABELSBOTTOM); 516 } 517 } 518 if (i + 1 == numDots) break; 519 minX = maxX; 520 if (i + 2 == numDots && 521 getLabelsAxisTicksAlignment() == this.BETWEEN) { 522 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 523 } 524 else maxX = xTicks[i + 1].x + tickHalfWidth; 525 ++i; 526 } while (true); 527 } 528 } 529 530 if ((numCats * numCompsPerCat) < 2 || linesThickness < 1) lines = new FancyLine[0]; 531 else { 532 lines = new FancyLine[numSets]; 533 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height, x; 534 for (int i = 0; i < numSets; ++i) { 535 lines[i] = new FancyLine(); 536 lines[i].setThickness (linesThickness); 537 lines[i].setFillArea (getLinesFillInterior()); 538 lines[i].setColor (getLineColors()[i]); 539 lines[i].setOutlineExistence (getOutlineComponents()); 540 lines[i].setOutlineColor (getOutlineComponentsColor()); 541 lines[i].setLightSource (getComponentsLightSource()); 542 lines[i].setWarningRegions (getWarningRegions()); 543 lines[i].setType (FancyShape.LABELSBOTTOM); 544 } 545 Point firstPoints[] = new Point[numSets]; 546 float minX, maxX, tickHalfWidth; 547 minX = getSpaceSizeLocation (MIN).x; 548 tickHalfWidth = xTicks[0].width / 2f; 549 maxX = xTicks[0].x + tickHalfWidth; 550 float catDelta = 551 getSpaceSize (MIN).width / (float)(numLinePoints * numCompsPerCat); 552 int i = 0; 553 do { 554 if (getLabelsAxisTicksAlignment() == BETWEEN) { 555 x = (int)(minX + Math.floor((maxX - minX - setsThickness) / 2f)); 556 } 557 else x = (int)Math.floor (maxX - setsThickness / 2f); 558 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 559 for (int k = 0; k < numCompsPerCat; ++k) { 560 for (int j = 0; j < numSets; ++j) { 561 int compX = x + j * componentsThickness + componentsThickness / 2; 562 Point thisPoint = new Point ( 563 (int)(compX + k * catDelta), 564 (int)(y - graphLengths[j][i * numCompsPerCat + k])); 565 if (k == 0 && i == 0) { 566 if (getLinesFillInterior()) { 567 firstPoints[j] = new Point ( 568 (int)(compX + k * catDelta), 569 y - getLinesFillInteriorBaseValue()); 570 lines[j].getLine().moveTo (firstPoints[j].x, firstPoints[j].y); 571 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y); 572 } 573 else { 574 lines[j].getLine().moveTo (thisPoint.x, thisPoint.y); 575 } 576 } 577 else { 578 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y); 579 if (getLinesFillInterior() && 580 k == numCompsPerCat - 1 && i == numLinePoints - 1) { 581 lines[j].getLine().lineTo (thisPoint.x, firstPoints[j].y); 582 lines[j].getLine().lineTo (firstPoints[j].x, firstPoints[j].y); 583 } 584 } 585 } 586 } 587 if (i + 1 == numLinePoints) break; 588 minX = maxX; 589 if (i + 2 == numLinePoints && 590 getLabelsAxisTicksAlignment() == this.BETWEEN) { 591 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 592 } 593 else maxX = xTicks[i + 1].x + tickHalfWidth; 594 ++i; 595 } while (true); 596 for (int g = 0; g < numSets; ++g) { 597 lines[g].setClipBounds (boundsGraph); 598 Rectangle2D.Float bounds = (Rectangle2D.Float)lines[g].getLine().getBounds2D(); 599 lines[g].setLightBounds ( 600 getComponentsLightType() == COMPONENT ? bounds : boundsGraph); 601 } 602 } 603 } 604 else { 605 bars = new FancyBar[0][0]; 606 dots = new FancyDot[0][0]; 607 lines = new FancyLine[0]; 608 } 609 } 610 611 612 private void updateAllowAlignment() { 613 614 int[][] graphLengths = getGraphValues(); 615 int numBars = 0, numDots = 0, numLinePoints = 0, numGaps = 0; 616 int numSets = graphLengths.length; 617 Rectangle[] xTicks = getXTicks(); 618 int numCompsPerCat = 0; 619 int numCats = 0; 620 if (numSets > 0) { 621 numCats = getLabelsAxisTicksAlignment() == BETWEEN ? 622 xTicks.length + 1 : xTicks.length; 623 numBars = getBarsExistence() ? numCats : 0; 624 numDots = getDotsExistence() ? numCats : 0; 625 numLinePoints = getLinesExistence() ? numCats : 0; 626 numGaps = getBetweenComponentsGapExistence() ? numCats : 0; 627 numCompsPerCat = numCats > 0 ? (int)(graphLengths[0].length / numCats) : 0; 628 } 629 630 if (numSets > 0 && numCats > 0 && numCompsPerCat > 0) { 631 float ratio = getRatio (WIDTH); 632 int availableThickness = getSpaceSize(MIN).width; 633 634 int betweenComponentsGapThickness = 0; 635 if (numGaps > 0) { 636 betweenComponentsGapThickness = 637 applyRatio (getBetweenComponentsGapThicknessModel(), ratio); 638 betweenComponentsGapThickness = 639 numGaps * betweenComponentsGapThickness <= availableThickness ? 640 betweenComponentsGapThickness : availableThickness / numGaps; 641 availableThickness -= numGaps * betweenComponentsGapThickness; 642 } 643 644 int barsThickness = 0; 645 if (numBars > 0) { 646 barsThickness = applyRatio (getBarsThicknessModel(), ratio); 647 if (numBars * numCompsPerCat * barsThickness <= availableThickness) { 648 float leftover = 649 (availableThickness - barsThickness * 650 (numBars * numCompsPerCat)) / 651 (numBars * numCompsPerCat); 652 barsThickness = 653 barsThickness + (int)(getBarsExcessSpaceFeedbackRatio() * leftover); 654 } 655 else { 656 float numOverlapBarsPerCat = 657 (1 + (1 - getBarsWithinCategoryOverlapRatio()) * 658 (numCompsPerCat - 1)); 659 if (numBars * numOverlapBarsPerCat * barsThickness > 660 availableThickness) { 661 barsThickness = 662 (int)(availableThickness / (numBars * numOverlapBarsPerCat)); 663 } 664 } 665 } 666 int dotsThickness = 0; 667 if (numDots > 0) { 668 dotsThickness = applyRatio (getDotsThicknessModel(), getRatio (LESSER)); 669 if (numDots * numCompsPerCat * dotsThickness <= 670 availableThickness) { 671 float leftover = 672 (availableThickness - dotsThickness * 673 (numDots * numCompsPerCat)) / 674 (numDots * numCompsPerCat); 675 dotsThickness = 676 dotsThickness + (int)(getDotsExcessSpaceFeedbackRatio() * leftover); 677 } 678 else { 679 float numOverlapDotsPerCat = 680 (1 + (1 - getDotsWithinCategoryOverlapRatio()) * 681 (numCompsPerCat - 1)); 682 if (numDots * numOverlapDotsPerCat * dotsThickness > 683 availableThickness) { 684 dotsThickness = 685 (int)(availableThickness / (numDots * numOverlapDotsPerCat)); 686 } 687 } 688 } 689 int linesThickness = 0; 690 if (numLinePoints > 0) { 691 linesThickness = 692 applyRatio (getLinesThicknessModel(), getRatio (LESSER)); 693 if (numLinePoints * numCompsPerCat * linesThickness <= 694 availableThickness) { 695 float leftover = 696 (availableThickness - linesThickness * 697 (numLinePoints * numCompsPerCat)) / 698 (numLinePoints * numCompsPerCat); 699 linesThickness = 700 linesThickness + (int)(getLinesExcessSpaceFeedbackRatio() * leftover); 701 } 702 else { 703 float numOverlapLinesPerCat = 704 (1 + (1 - getLinesWithinCategoryOverlapRatio()) * 705 (numCompsPerCat - 1)); 706 if (numLinePoints * numOverlapLinesPerCat * linesThickness > 707 availableThickness) { 708 linesThickness = 709 (int)(availableThickness / (numLinePoints * numOverlapLinesPerCat)); 710 } 711 } 712 } 713 714 Rectangle2D.Float boundsGraph = new Rectangle2D.Float ( 715 getSpaceSizeLocation (MIN).x, getSpaceSizeLocation (MIN).y, 716 getSpaceSize (MIN).width, getSpaceSize (MIN).height); 717 718 bars = new FancyBar[numSets][numBars * numCompsPerCat]; 719 int[][] barLowValues = getBarLowValues(); 720 if (numBars > 0) { 721 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height, x; 722 float catDelta = 723 getSpaceSize (MIN).width / (float)(numBars * numCompsPerCat); 724 if (numBars == 1) { 725 x = getSpaceSizeLocation (MIN).x + 726 (getSpaceSize(MIN).width - barsThickness) / 2; 727 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 728 for (int k = 0; k < numCompsPerCat; ++k) { 729 for (int j = 0; j < numSets; ++j) { 730 bars[j][k] = new FancyBar(); 731 bars[j][k].setDataSign (getDataSign()); 732 bars[j][k].setBaseValue (y - getLinesFillInteriorBaseValue()); 733 if (graphLengths[j][k] > barLowValues[j][k]) { 734 bars[j][k].setBounds (new Rectangle2D.Float ( 735 x + k * catDelta, y - graphLengths[j][k], 736 barsThickness, graphLengths[j][k] - barLowValues[j][k])); 737 } 738 else { 739 bars[j][k].setBounds (new Rectangle2D.Float ( 740 x + k * catDelta, y - barLowValues[j][k], 741 barsThickness, barLowValues[j][k] - graphLengths[j][k])); 742 } 743 Rectangle2D.Float clipBounds = new Rectangle2D.Float ( 744 boundsGraph.x, bars[j][k].getBounds().y, 745 boundsGraph.width, bars[j][k].getBounds().height); 746 bars[j][k].setClipBounds (clipBounds); 747 bars[j][k].setLightBounds ( 748 getComponentsLightType() == COMPONENT ? bars[j][k].getBounds() : boundsGraph); 749 bars[j][k].setLightSource (getComponentsLightSource()); 750 bars[j][k].setColor (!getComponentsColoringByCat() ? 751 getBarColors()[j] : getComponentsColorsByCat()[0]); 752 bars[j][k].setOutlineExistence (getOutlineComponents()); 753 bars[j][k].setOutlineColor (getOutlineComponentsColor()); 754 bars[j][k].setArcw (getBarRoundingRatio() * barsThickness); 755 bars[j][k].setArch (getBarRoundingRatio() * barsThickness); 756 bars[j][k].setWarningRegions (getWarningRegions()); 757 bars[j][k].setType (FancyShape.LABELSBOTTOM); 758 bars[j][k].setGraphBounds (boundsGraph); 759 } 760 } 761 } 762 else { 763 float minX, maxX, tickHalfWidth; 764 minX = getSpaceSizeLocation (MIN).x; 765 tickHalfWidth = xTicks[0].width / 2f; 766 maxX = xTicks[0].x + tickHalfWidth; 767 int i = 0; 768 do { 769 if (getLabelsAxisTicksAlignment() == BETWEEN) { 770 x = (int)(minX + Math.floor((maxX - minX - barsThickness) / 2f)); 771 } 772 else x = (int)Math.floor (maxX - barsThickness / 2f); 773 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 774 for (int k = 0; k < numCompsPerCat; ++k) { 775 for (int j = 0; j < numSets; ++j) { 776 bars[j][i * numCompsPerCat + k] = new FancyBar(); 777 bars[j][i * numCompsPerCat + k].setDataSign (getDataSign()); 778 bars[j][i * numCompsPerCat + k].setBaseValue (y - getLinesFillInteriorBaseValue()); 779 if (graphLengths[j][i * numCompsPerCat + k] > 780 barLowValues[j][i * numCompsPerCat + k]) { 781 bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 782 x + k * catDelta, y - graphLengths[j][i * numCompsPerCat + k], 783 barsThickness, graphLengths[j][i * numCompsPerCat + k] - 784 barLowValues[j][i * numCompsPerCat + k])); 785 } 786 else { 787 bars[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 788 (int)(x + k * catDelta), 789 y - barLowValues[j][i * numCompsPerCat + k], 790 barsThickness, barLowValues[j][i * numCompsPerCat + k] - 791 graphLengths[j][i * numCompsPerCat + k])); 792 } 793 Rectangle2D.Float clipBounds = new Rectangle2D.Float ( 794 boundsGraph.x, bars[j][i * numCompsPerCat + k].getBounds().y, 795 boundsGraph.width, bars[j][i * numCompsPerCat + k].getBounds().height); 796 bars[j][i * numCompsPerCat + k].setClipBounds (clipBounds); 797 bars[j][i * numCompsPerCat + k].setLightBounds ( 798 getComponentsLightType() == COMPONENT ? 799 bars[j][i * numCompsPerCat + k].getBounds() : boundsGraph); 800 bars[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource()); 801 bars[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ? 802 getBarColors()[j] : getComponentsColorsByCat()[i]); 803 bars[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents()); 804 bars[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor()); 805 bars[j][i * numCompsPerCat + k].setArcw (getBarRoundingRatio() * barsThickness); 806 bars[j][i * numCompsPerCat + k].setArch (getBarRoundingRatio() * barsThickness); 807 bars[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions()); 808 bars[j][i * numCompsPerCat + k].setType (FancyShape.LABELSBOTTOM); 809 bars[j][i * numCompsPerCat + k].setGraphBounds (boundsGraph); 810 } 811 } 812 if (i + 1 == numBars) break; 813 minX = maxX; 814 if (i + 2 == numBars && 815 getLabelsAxisTicksAlignment() == BETWEEN) { 816 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 817 } 818 else maxX = xTicks[i + 1].x + tickHalfWidth; 819 ++i; 820 } while (true); 821 } 822 } 823 824 dots = new FancyDot[numSets][numDots * numCompsPerCat]; 825 if (numDots > 0) { 826 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height - 827 dotsThickness / 2, x; 828 float catDelta = 829 getSpaceSize (MIN).width / (float)(numDots * numCompsPerCat); 830 if (numDots == 1) { 831 x = getSpaceSizeLocation (MIN).x + 832 (getSpaceSize(MIN).width - dotsThickness) / 2; 833 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 834 for (int k = 0; k < numCompsPerCat; ++k) { 835 for (int j = 0; j < numSets; ++j) { 836 dots[j][k] = new FancyDot(); 837 dots[j][k].setBounds (new Rectangle2D.Float ( 838 x + k * catDelta, y - graphLengths[j][k], dotsThickness, dotsThickness)); 839 dots[j][k].setClipBounds (dots[j][k].getBounds()); 840 dots[j][k].setColor (!getComponentsColoringByCat() ? 841 getDotColors()[j] : getComponentsColorsByCat()[0]); 842 dots[j][k].setOutlineExistence (getOutlineComponents()); 843 dots[j][k].setOutlineColor (getOutlineComponentsColor()); 844 dots[j][k].setLightBounds ( 845 getComponentsLightType() == COMPONENT ? dots[j][k].getBounds() : boundsGraph); 846 dots[j][k].setLightSource (getComponentsLightSource()); 847 dots[j][k].setWarningRegions (getWarningRegions()); 848 dots[j][k].setType (FancyShape.LABELSBOTTOM); 849 } 850 } 851 } 852 else { 853 float minX, maxX, tickHalfWidth; 854 minX = getSpaceSizeLocation (MIN).x; 855 tickHalfWidth = xTicks[0].width / 2f; 856 maxX = xTicks[0].x + tickHalfWidth; 857 int i = 0; 858 do { 859 if (getLabelsAxisTicksAlignment() == this.BETWEEN) { 860 x = (int)(minX + Math.floor((maxX - minX - dotsThickness) / 2f)); 861 } 862 else x = (int)Math.floor (maxX - dotsThickness / 2f); 863 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 864 for (int k = 0; k < numCompsPerCat; ++k) { 865 for (int j = 0; j < numSets; ++j) { 866 dots[j][i * numCompsPerCat + k] = new FancyDot(); 867 dots[j][i * numCompsPerCat + k].setBounds (new Rectangle2D.Float ( 868 x + k * catDelta, y - graphLengths[j][i * numCompsPerCat + k], 869 dotsThickness, dotsThickness)); 870 dots[j][i * numCompsPerCat + k].setClipBounds ( 871 dots[j][i * numCompsPerCat + k].getBounds()); 872 dots[j][i * numCompsPerCat + k].setColor (!getComponentsColoringByCat() ? 873 getDotColors()[j] : getComponentsColorsByCat()[i]); 874 dots[j][i * numCompsPerCat + k].setOutlineExistence (getOutlineComponents()); 875 dots[j][i * numCompsPerCat + k].setOutlineColor (getOutlineComponentsColor()); 876 dots[j][i * numCompsPerCat + k].setLightBounds ( 877 getComponentsLightType() == COMPONENT ? 878 dots[j][i * numCompsPerCat + k].getBounds() : boundsGraph); 879 dots[j][i * numCompsPerCat + k].setLightSource (getComponentsLightSource()); 880 dots[j][i * numCompsPerCat + k].setWarningRegions (getWarningRegions()); 881 dots[j][i * numCompsPerCat + k].setType (FancyShape.LABELSBOTTOM); 882 } 883 } 884 if (i + 1 == numDots) break; 885 minX = maxX; 886 if (i + 2 == numDots && 887 getLabelsAxisTicksAlignment() == this.BETWEEN) { 888 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 889 } 890 else maxX = xTicks[i + 1].x + tickHalfWidth; 891 ++i; 892 } while (true); 893 } 894 } 895 896 897 if ((numCats * numCompsPerCat) < 2 || linesThickness < 1) lines = new FancyLine[0]; 898 else { 899 lines = new FancyLine[numSets]; 900 int y = getSpaceSizeLocation (MIN).y + getSpaceSize(MIN).height, x; 901 for (int i = 0; i < numSets; ++i) { 902 lines[i] = new FancyLine(); 903 lines[i].setThickness (linesThickness); 904 lines[i].setFillArea (getLinesFillInterior()); 905 lines[i].setColor (getLineColors()[i]); 906 lines[i].setOutlineExistence (getOutlineComponents()); 907 lines[i].setOutlineColor (getOutlineComponentsColor()); 908 lines[i].setLightSource (getComponentsLightSource()); 909 lines[i].setWarningRegions (getWarningRegions()); 910 lines[i].setType (FancyShape.LABELSBOTTOM); 911 } 912 Point firstPoints[] = new Point[numSets]; 913 float minX, maxX, tickHalfWidth; 914 minX = getSpaceSizeLocation (MIN).x; 915 tickHalfWidth = xTicks[0].width / 2f; 916 maxX = xTicks[0].x + tickHalfWidth; 917 float catDelta = 918 getSpaceSize (MIN).width / (float)(numLinePoints * numCompsPerCat); 919 int i = 0; 920 do { 921 if (getLabelsAxisTicksAlignment() == Area.BETWEEN) { 922 x = (int)(minX + Math.floor((maxX - minX) / 2f)); 923 } 924 else { 925 x = (int)maxX; 926 } 927 x = (int)(x - ((numCompsPerCat - 1) / 2f) * catDelta); 928 for (int k = 0; k < numCompsPerCat; ++k) { 929 for (int j = 0; j < numSets; ++j) { 930 Point thisPoint = new Point ( 931 (int)(x + k * catDelta), 932 (int)(y - graphLengths[j][i * numCompsPerCat + k])); 933 if (k == 0 && i == 0) { 934 if (getLinesFillInterior()) { 935 firstPoints[j] = new Point ( 936 (int)(x + k * catDelta), 937 y - getLinesFillInteriorBaseValue()); 938 lines[j].getLine().moveTo (firstPoints[j].x, firstPoints[j].y); 939 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y); 940 } 941 else { 942 lines[j].getLine().moveTo (thisPoint.x, thisPoint.y); 943 } 944 } 945 else { 946 lines[j].getLine().lineTo (thisPoint.x, thisPoint.y); 947 if (getLinesFillInterior() && 948 k == numCompsPerCat - 1 && i == numLinePoints - 1) { 949 lines[j].getLine().lineTo (thisPoint.x, firstPoints[j].y); 950 lines[j].getLine().lineTo (firstPoints[j].x, firstPoints[j].y); 951 } 952 } 953 } 954 } 955 if (i + 1 == numLinePoints) break; 956 minX = maxX; 957 if (i + 2 == numLinePoints && 958 getLabelsAxisTicksAlignment() == this.BETWEEN) { 959 maxX = getSpaceSizeLocation (MIN).x + getSpaceSize (MIN).width; 960 } 961 else maxX = xTicks[i + 1].x + tickHalfWidth; 962 ++i; 963 } while (true); 964 for (int g = 0; g < numSets; ++g) { 965 lines[g].setClipBounds (boundsGraph); 966 Rectangle2D.Float bounds = (Rectangle2D.Float)lines[g].getLine().getBounds2D(); 967 lines[g].setLightBounds (getComponentsLightType() == COMPONENT ? bounds : boundsGraph); 968 } 969 } 970 } 971 else { 972 bars = new FancyBar[0][0]; 973 dots = new FancyDot[0][0]; 974 lines = new FancyLine[0]; 975 } 976 } 977 } | Popular Tags |