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