1 2 package com.github.mikephil.charting.components; 3 4 import android.graphics.Color; 5 import android.graphics.DashPathEffect; 6 import android.util.Log; 7 8 import com.github.mikephil.charting.formatter.DefaultAxisValueFormatter; 9 import com.github.mikephil.charting.formatter.IAxisValueFormatter; 10 import com.github.mikephil.charting.utils.Utils; 11 12 import java.util.ArrayList; 13 import java.util.List; 14 15 /** 16 * Base-class of all axes (previously called labels). 17 * 18 * @author Philipp Jahoda 19 */ 20 public abstract class AxisBase extends ComponentBase { 21 22 /** 23 * custom formatter that is used instead of the auto-formatter if set 24 */ 25 protected IAxisValueFormatter mAxisValueFormatter; 26 27 private int mGridColor = Color.GRAY; 28 29 private float mGridLineWidth = 1f; 30 31 private int mAxisLineColor = Color.GRAY; 32 33 private float mAxisLineWidth = 1f; 34 35 /** 36 * the actual array of entries 37 */ 38 public float[] mEntries = new float[]{}; 39 40 /** 41 * axis label entries only used for centered labels 42 */ 43 public float[] mCenteredEntries = new float[]{}; 44 45 /** 46 * the number of entries the legend contains 47 */ 48 public int mEntryCount; 49 50 /** 51 * the number of decimal digits to use 52 */ 53 public int mDecimals; 54 55 /** 56 * the number of label entries the axis should have, default 6 57 */ 58 private int mLabelCount = 6; 59 60 /** 61 * the minimum interval between axis values 62 */ 63 protected float mGranularity = 1.0f; 64 65 /** 66 * When true, axis labels are controlled by the `granularity` property. 67 * When false, axis values could possibly be repeated. 68 * This could happen if two adjacent axis values are rounded to same value. 69 * If using granularity this could be avoided by having fewer axis values visible. 70 */ 71 protected boolean mGranularityEnabled = false; 72 73 /** 74 * if true, the set number of y-labels will be forced 75 */ 76 protected boolean mForceLabels = false; 77 78 /** 79 * flag indicating if the grid lines for this axis should be drawn 80 */ 81 protected boolean mDrawGridLines = true; 82 83 /** 84 * flag that indicates if the line alongside the axis is drawn or not 85 */ 86 protected boolean mDrawAxisLine = true; 87 88 /** 89 * flag that indicates of the labels of this axis should be drawn or not 90 */ 91 protected boolean mDrawLabels = true; 92 93 protected boolean mCenterAxisLabels = false; 94 95 /** 96 * the path effect of the axis line that makes dashed lines possible 97 */ 98 private DashPathEffect mAxisLineDashPathEffect = null; 99 100 /** 101 * the path effect of the grid lines that makes dashed lines possible 102 */ 103 private DashPathEffect mGridDashPathEffect = null; 104 105 /** 106 * array of limit lines that can be set for the axis 107 */ 108 protected List<LimitLine> mLimitLines; 109 110 /** 111 * flag indicating the limit lines layer depth 112 */ 113 protected boolean mDrawLimitLineBehindData = false; 114 115 /** 116 * flag indicating the grid lines layer depth 117 */ 118 protected boolean mDrawGridLinesBehindData = true; 119 120 /** 121 * Extra spacing for `axisMinimum` to be added to automatically calculated `axisMinimum` 122 */ 123 protected float mSpaceMin = 0.f; 124 125 /** 126 * Extra spacing for `axisMaximum` to be added to automatically calculated `axisMaximum` 127 */ 128 protected float mSpaceMax = 0.f; 129 130 /** 131 * flag indicating that the axis-min value has been customized 132 */ 133 protected boolean mCustomAxisMin = false; 134 135 /** 136 * flag indicating that the axis-max value has been customized 137 */ 138 protected boolean mCustomAxisMax = false; 139 140 /** 141 * don't touch this direclty, use setter 142 */ 143 public float mAxisMaximum = 0f; 144 145 /** 146 * don't touch this directly, use setter 147 */ 148 public float mAxisMinimum = 0f; 149 150 /** 151 * the total range of values this axis covers 152 */ 153 public float mAxisRange = 0f; 154 155 private int mAxisMinLabels = 2; 156 private int mAxisMaxLabels = 25; 157 158 /** 159 * The minumum number of labels on the axis 160 */ getAxisMinLabels()161 public int getAxisMinLabels() { 162 return mAxisMinLabels; 163 } 164 165 /** 166 * The minumum number of labels on the axis 167 */ setAxisMinLabels(int labels)168 public void setAxisMinLabels(int labels) { 169 if (labels > 0) 170 mAxisMinLabels = labels; 171 } 172 173 /** 174 * The maximum number of labels on the axis 175 */ getAxisMaxLabels()176 public int getAxisMaxLabels() { 177 return mAxisMaxLabels; 178 } 179 180 /** 181 * The maximum number of labels on the axis 182 */ setAxisMaxLabels(int labels)183 public void setAxisMaxLabels(int labels) { 184 if (labels > 0) 185 mAxisMaxLabels = labels; 186 } 187 188 /** 189 * default constructor 190 */ AxisBase()191 public AxisBase() { 192 this.mTextSize = Utils.convertDpToPixel(10f); 193 this.mXOffset = Utils.convertDpToPixel(5f); 194 this.mYOffset = Utils.convertDpToPixel(5f); 195 this.mLimitLines = new ArrayList<LimitLine>(); 196 } 197 198 /** 199 * Set this to true to enable drawing the grid lines for this axis. 200 * 201 * @param enabled 202 */ setDrawGridLines(boolean enabled)203 public void setDrawGridLines(boolean enabled) { 204 mDrawGridLines = enabled; 205 } 206 207 /** 208 * Returns true if drawing grid lines is enabled for this axis. 209 * 210 * @return 211 */ isDrawGridLinesEnabled()212 public boolean isDrawGridLinesEnabled() { 213 return mDrawGridLines; 214 } 215 216 /** 217 * Set this to true if the line alongside the axis should be drawn or not. 218 * 219 * @param enabled 220 */ setDrawAxisLine(boolean enabled)221 public void setDrawAxisLine(boolean enabled) { 222 mDrawAxisLine = enabled; 223 } 224 225 /** 226 * Returns true if the line alongside the axis should be drawn. 227 * 228 * @return 229 */ isDrawAxisLineEnabled()230 public boolean isDrawAxisLineEnabled() { 231 return mDrawAxisLine; 232 } 233 234 /** 235 * Centers the axis labels instead of drawing them at their original position. 236 * This is useful especially for grouped BarChart. 237 * 238 * @param enabled 239 */ setCenterAxisLabels(boolean enabled)240 public void setCenterAxisLabels(boolean enabled) { 241 mCenterAxisLabels = enabled; 242 } 243 isCenterAxisLabelsEnabled()244 public boolean isCenterAxisLabelsEnabled() { 245 return mCenterAxisLabels && mEntryCount > 0; 246 } 247 248 /** 249 * Sets the color of the grid lines for this axis (the horizontal lines 250 * coming from each label). 251 * 252 * @param color 253 */ setGridColor(int color)254 public void setGridColor(int color) { 255 mGridColor = color; 256 } 257 258 /** 259 * Returns the color of the grid lines for this axis (the horizontal lines 260 * coming from each label). 261 * 262 * @return 263 */ getGridColor()264 public int getGridColor() { 265 return mGridColor; 266 } 267 268 /** 269 * Sets the width of the border surrounding the chart in dp. 270 * 271 * @param width 272 */ setAxisLineWidth(float width)273 public void setAxisLineWidth(float width) { 274 mAxisLineWidth = Utils.convertDpToPixel(width); 275 } 276 277 /** 278 * Returns the width of the axis line (line alongside the axis). 279 * 280 * @return 281 */ getAxisLineWidth()282 public float getAxisLineWidth() { 283 return mAxisLineWidth; 284 } 285 286 /** 287 * Sets the width of the grid lines that are drawn away from each axis 288 * label. 289 * 290 * @param width 291 */ setGridLineWidth(float width)292 public void setGridLineWidth(float width) { 293 mGridLineWidth = Utils.convertDpToPixel(width); 294 } 295 296 /** 297 * Returns the width of the grid lines that are drawn away from each axis 298 * label. 299 * 300 * @return 301 */ getGridLineWidth()302 public float getGridLineWidth() { 303 return mGridLineWidth; 304 } 305 306 /** 307 * Sets the color of the border surrounding the chart. 308 * 309 * @param color 310 */ setAxisLineColor(int color)311 public void setAxisLineColor(int color) { 312 mAxisLineColor = color; 313 } 314 315 /** 316 * Returns the color of the axis line (line alongside the axis). 317 * 318 * @return 319 */ getAxisLineColor()320 public int getAxisLineColor() { 321 return mAxisLineColor; 322 } 323 324 /** 325 * Set this to true to enable drawing the labels of this axis (this will not 326 * affect drawing the grid lines or axis lines). 327 * 328 * @param enabled 329 */ setDrawLabels(boolean enabled)330 public void setDrawLabels(boolean enabled) { 331 mDrawLabels = enabled; 332 } 333 334 /** 335 * Returns true if drawing the labels is enabled for this axis. 336 * 337 * @return 338 */ isDrawLabelsEnabled()339 public boolean isDrawLabelsEnabled() { 340 return mDrawLabels; 341 } 342 343 /** 344 * Sets the number of label entries for the y-axis max = 25, min = 2, default: 6, be aware 345 * that this number is not fixed. 346 * 347 * @param count the number of y-axis labels that should be displayed 348 */ setLabelCount(int count)349 public void setLabelCount(int count) { 350 351 if (count > getAxisMaxLabels()) 352 count = getAxisMaxLabels(); 353 if (count < getAxisMinLabels()) 354 count = getAxisMinLabels(); 355 356 mLabelCount = count; 357 mForceLabels = false; 358 } 359 360 /** 361 * sets the number of label entries for the y-axis max = 25, min = 2, default: 6, be aware 362 * that this number is not 363 * fixed (if force == false) and can only be approximated. 364 * 365 * @param count the number of y-axis labels that should be displayed 366 * @param force if enabled, the set label count will be forced, meaning that the exact 367 * specified count of labels will 368 * be drawn and evenly distributed alongside the axis - this might cause labels 369 * to have uneven values 370 */ setLabelCount(int count, boolean force)371 public void setLabelCount(int count, boolean force) { 372 373 setLabelCount(count); 374 mForceLabels = force; 375 } 376 377 /** 378 * Returns true if focing the y-label count is enabled. Default: false 379 * 380 * @return 381 */ isForceLabelsEnabled()382 public boolean isForceLabelsEnabled() { 383 return mForceLabels; 384 } 385 386 /** 387 * Returns the number of label entries the y-axis should have 388 * 389 * @return 390 */ getLabelCount()391 public int getLabelCount() { 392 return mLabelCount; 393 } 394 395 /** 396 * @return true if granularity is enabled 397 */ isGranularityEnabled()398 public boolean isGranularityEnabled() { 399 return mGranularityEnabled; 400 } 401 402 /** 403 * Enabled/disable granularity control on axis value intervals. If enabled, the axis 404 * interval is not allowed to go below a certain granularity. Default: false 405 * 406 * @param enabled 407 */ setGranularityEnabled(boolean enabled)408 public void setGranularityEnabled(boolean enabled) { 409 mGranularityEnabled = enabled; 410 } 411 412 /** 413 * @return the minimum interval between axis values 414 */ getGranularity()415 public float getGranularity() { 416 return mGranularity; 417 } 418 419 /** 420 * Set a minimum interval for the axis when zooming in. The axis is not allowed to go below 421 * that limit. This can be used to avoid label duplicating when zooming in. 422 * 423 * @param granularity 424 */ setGranularity(float granularity)425 public void setGranularity(float granularity) { 426 mGranularity = granularity; 427 // set this to true if it was disabled, as it makes no sense to call this method with granularity disabled 428 mGranularityEnabled = true; 429 } 430 431 /** 432 * Adds a new LimitLine to this axis. 433 * 434 * @param l 435 */ addLimitLine(LimitLine l)436 public void addLimitLine(LimitLine l) { 437 mLimitLines.add(l); 438 439 if (mLimitLines.size() > 6) { 440 Log.e("MPAndroiChart", 441 "Warning! You have more than 6 LimitLines on your axis, do you really want " + 442 "that?"); 443 } 444 } 445 446 /** 447 * Removes the specified LimitLine from the axis. 448 * 449 * @param l 450 */ removeLimitLine(LimitLine l)451 public void removeLimitLine(LimitLine l) { 452 mLimitLines.remove(l); 453 } 454 455 /** 456 * Removes all LimitLines from the axis. 457 */ removeAllLimitLines()458 public void removeAllLimitLines() { 459 mLimitLines.clear(); 460 } 461 462 /** 463 * Returns the LimitLines of this axis. 464 * 465 * @return 466 */ getLimitLines()467 public List<LimitLine> getLimitLines() { 468 return mLimitLines; 469 } 470 471 /** 472 * If this is set to true, the LimitLines are drawn behind the actual data, 473 * otherwise on top. Default: false 474 * 475 * @param enabled 476 */ setDrawLimitLinesBehindData(boolean enabled)477 public void setDrawLimitLinesBehindData(boolean enabled) { 478 mDrawLimitLineBehindData = enabled; 479 } 480 isDrawLimitLinesBehindDataEnabled()481 public boolean isDrawLimitLinesBehindDataEnabled() { 482 return mDrawLimitLineBehindData; 483 } 484 485 /** 486 * If this is set to false, the grid lines are draw on top of the actual data, 487 * otherwise behind. Default: true 488 * 489 * @param enabled 490 */ setDrawGridLinesBehindData(boolean enabled)491 public void setDrawGridLinesBehindData(boolean enabled) { mDrawGridLinesBehindData = enabled; } 492 isDrawGridLinesBehindDataEnabled()493 public boolean isDrawGridLinesBehindDataEnabled() { 494 return mDrawGridLinesBehindData; 495 } 496 497 /** 498 * Returns the longest formatted label (in terms of characters), this axis 499 * contains. 500 * 501 * @return 502 */ getLongestLabel()503 public String getLongestLabel() { 504 505 String longest = ""; 506 507 for (int i = 0; i < mEntries.length; i++) { 508 String text = getFormattedLabel(i); 509 510 if (text != null && longest.length() < text.length()) 511 longest = text; 512 } 513 514 return longest; 515 } 516 getFormattedLabel(int index)517 public String getFormattedLabel(int index) { 518 519 if (index < 0 || index >= mEntries.length) 520 return ""; 521 else 522 return getValueFormatter().getFormattedValue(mEntries[index], this); 523 } 524 525 /** 526 * Sets the formatter to be used for formatting the axis labels. If no formatter is set, the 527 * chart will 528 * automatically determine a reasonable formatting (concerning decimals) for all the values 529 * that are drawn inside 530 * the chart. Use chart.getDefaultValueFormatter() to use the formatter calculated by the chart. 531 * 532 * @param f 533 */ setValueFormatter(IAxisValueFormatter f)534 public void setValueFormatter(IAxisValueFormatter f) { 535 536 if (f == null) 537 mAxisValueFormatter = new DefaultAxisValueFormatter(mDecimals); 538 else 539 mAxisValueFormatter = f; 540 } 541 542 /** 543 * Returns the formatter used for formatting the axis labels. 544 * 545 * @return 546 */ getValueFormatter()547 public IAxisValueFormatter getValueFormatter() { 548 549 if (mAxisValueFormatter == null || 550 (mAxisValueFormatter instanceof DefaultAxisValueFormatter && 551 ((DefaultAxisValueFormatter)mAxisValueFormatter).getDecimalDigits() != mDecimals)) 552 mAxisValueFormatter = new DefaultAxisValueFormatter(mDecimals); 553 554 return mAxisValueFormatter; 555 } 556 557 /** 558 * Enables the grid line to be drawn in dashed mode, e.g. like this 559 * "- - - - - -". THIS ONLY WORKS IF HARDWARE-ACCELERATION IS TURNED OFF. 560 * Keep in mind that hardware acceleration boosts performance. 561 * 562 * @param lineLength the length of the line pieces 563 * @param spaceLength the length of space in between the pieces 564 * @param phase offset, in degrees (normally, use 0) 565 */ enableGridDashedLine(float lineLength, float spaceLength, float phase)566 public void enableGridDashedLine(float lineLength, float spaceLength, float phase) { 567 mGridDashPathEffect = new DashPathEffect(new float[]{ 568 lineLength, spaceLength 569 }, phase); 570 } 571 572 /** 573 * Enables the grid line to be drawn in dashed mode, e.g. like this 574 * "- - - - - -". THIS ONLY WORKS IF HARDWARE-ACCELERATION IS TURNED OFF. 575 * Keep in mind that hardware acceleration boosts performance. 576 * 577 * @param effect the DashPathEffect 578 */ setGridDashedLine(DashPathEffect effect)579 public void setGridDashedLine(DashPathEffect effect) { 580 mGridDashPathEffect = effect; 581 } 582 583 /** 584 * Disables the grid line to be drawn in dashed mode. 585 */ disableGridDashedLine()586 public void disableGridDashedLine() { 587 mGridDashPathEffect = null; 588 } 589 590 /** 591 * Returns true if the grid dashed-line effect is enabled, false if not. 592 * 593 * @return 594 */ isGridDashedLineEnabled()595 public boolean isGridDashedLineEnabled() { 596 return mGridDashPathEffect == null ? false : true; 597 } 598 599 /** 600 * returns the DashPathEffect that is set for grid line 601 * 602 * @return 603 */ getGridDashPathEffect()604 public DashPathEffect getGridDashPathEffect() { 605 return mGridDashPathEffect; 606 } 607 608 609 /** 610 * Enables the axis line to be drawn in dashed mode, e.g. like this 611 * "- - - - - -". THIS ONLY WORKS IF HARDWARE-ACCELERATION IS TURNED OFF. 612 * Keep in mind that hardware acceleration boosts performance. 613 * 614 * @param lineLength the length of the line pieces 615 * @param spaceLength the length of space in between the pieces 616 * @param phase offset, in degrees (normally, use 0) 617 */ enableAxisLineDashedLine(float lineLength, float spaceLength, float phase)618 public void enableAxisLineDashedLine(float lineLength, float spaceLength, float phase) { 619 mAxisLineDashPathEffect = new DashPathEffect(new float[]{ 620 lineLength, spaceLength 621 }, phase); 622 } 623 624 /** 625 * Enables the axis line to be drawn in dashed mode, e.g. like this 626 * "- - - - - -". THIS ONLY WORKS IF HARDWARE-ACCELERATION IS TURNED OFF. 627 * Keep in mind that hardware acceleration boosts performance. 628 * 629 * @param effect the DashPathEffect 630 */ setAxisLineDashedLine(DashPathEffect effect)631 public void setAxisLineDashedLine(DashPathEffect effect) { 632 mAxisLineDashPathEffect = effect; 633 } 634 635 /** 636 * Disables the axis line to be drawn in dashed mode. 637 */ disableAxisLineDashedLine()638 public void disableAxisLineDashedLine() { 639 mAxisLineDashPathEffect = null; 640 } 641 642 /** 643 * Returns true if the axis dashed-line effect is enabled, false if not. 644 * 645 * @return 646 */ isAxisLineDashedLineEnabled()647 public boolean isAxisLineDashedLineEnabled() { 648 return mAxisLineDashPathEffect == null ? false : true; 649 } 650 651 /** 652 * returns the DashPathEffect that is set for axis line 653 * 654 * @return 655 */ getAxisLineDashPathEffect()656 public DashPathEffect getAxisLineDashPathEffect() { 657 return mAxisLineDashPathEffect; 658 } 659 660 /** 661 * ###### BELOW CODE RELATED TO CUSTOM AXIS VALUES ###### 662 */ 663 getAxisMaximum()664 public float getAxisMaximum() { 665 return mAxisMaximum; 666 } 667 getAxisMinimum()668 public float getAxisMinimum() { 669 return mAxisMinimum; 670 } 671 672 /** 673 * By calling this method, any custom maximum value that has been previously set is reseted, 674 * and the calculation is 675 * done automatically. 676 */ resetAxisMaximum()677 public void resetAxisMaximum() { 678 mCustomAxisMax = false; 679 } 680 681 /** 682 * Returns true if the axis max value has been customized (and is not calculated automatically) 683 * 684 * @return 685 */ isAxisMaxCustom()686 public boolean isAxisMaxCustom() { 687 return mCustomAxisMax; 688 } 689 690 /** 691 * By calling this method, any custom minimum value that has been previously set is reseted, 692 * and the calculation is 693 * done automatically. 694 */ resetAxisMinimum()695 public void resetAxisMinimum() { 696 mCustomAxisMin = false; 697 } 698 699 /** 700 * Returns true if the axis min value has been customized (and is not calculated automatically) 701 * 702 * @return 703 */ isAxisMinCustom()704 public boolean isAxisMinCustom() { 705 return mCustomAxisMin; 706 } 707 708 /** 709 * Set a custom minimum value for this axis. If set, this value will not be calculated 710 * automatically depending on 711 * the provided data. Use resetAxisMinValue() to undo this. Do not forget to call 712 * setStartAtZero(false) if you use 713 * this method. Otherwise, the axis-minimum value will still be forced to 0. 714 * 715 * @param min 716 */ setAxisMinimum(float min)717 public void setAxisMinimum(float min) { 718 mCustomAxisMin = true; 719 mAxisMinimum = min; 720 this.mAxisRange = Math.abs(mAxisMaximum - min); 721 } 722 723 /** 724 * Use setAxisMinimum(...) instead. 725 * 726 * @param min 727 */ 728 @Deprecated setAxisMinValue(float min)729 public void setAxisMinValue(float min) { 730 setAxisMinimum(min); 731 } 732 733 /** 734 * Set a custom maximum value for this axis. If set, this value will not be calculated 735 * automatically depending on 736 * the provided data. Use resetAxisMaxValue() to undo this. 737 * 738 * @param max 739 */ setAxisMaximum(float max)740 public void setAxisMaximum(float max) { 741 mCustomAxisMax = true; 742 mAxisMaximum = max; 743 this.mAxisRange = Math.abs(max - mAxisMinimum); 744 } 745 746 /** 747 * Use setAxisMaximum(...) instead. 748 * 749 * @param max 750 */ 751 @Deprecated setAxisMaxValue(float max)752 public void setAxisMaxValue(float max) { 753 setAxisMaximum(max); 754 } 755 756 /** 757 * Calculates the minimum / maximum and range values of the axis with the given 758 * minimum and maximum values from the chart data. 759 * 760 * @param dataMin the min value according to chart data 761 * @param dataMax the max value according to chart data 762 */ calculate(float dataMin, float dataMax)763 public void calculate(float dataMin, float dataMax) { 764 765 // if custom, use value as is, else use data value 766 float min = mCustomAxisMin ? mAxisMinimum : (dataMin - mSpaceMin); 767 float max = mCustomAxisMax ? mAxisMaximum : (dataMax + mSpaceMax); 768 769 // temporary range (before calculations) 770 float range = Math.abs(max - min); 771 772 // in case all values are equal 773 if (range == 0f) { 774 max = max + 1f; 775 min = min - 1f; 776 } 777 778 this.mAxisMinimum = min; 779 this.mAxisMaximum = max; 780 781 // actual range 782 this.mAxisRange = Math.abs(max - min); 783 } 784 785 /** 786 * Gets extra spacing for `axisMinimum` to be added to automatically calculated `axisMinimum` 787 */ getSpaceMin()788 public float getSpaceMin() 789 { 790 return mSpaceMin; 791 } 792 793 /** 794 * Sets extra spacing for `axisMinimum` to be added to automatically calculated `axisMinimum` 795 */ setSpaceMin(float mSpaceMin)796 public void setSpaceMin(float mSpaceMin) 797 { 798 this.mSpaceMin = mSpaceMin; 799 } 800 801 /** 802 * Gets extra spacing for `axisMaximum` to be added to automatically calculated `axisMaximum` 803 */ getSpaceMax()804 public float getSpaceMax() 805 { 806 return mSpaceMax; 807 } 808 809 /** 810 * Sets extra spacing for `axisMaximum` to be added to automatically calculated `axisMaximum` 811 */ setSpaceMax(float mSpaceMax)812 public void setSpaceMax(float mSpaceMax) 813 { 814 this.mSpaceMax = mSpaceMax; 815 } 816 } 817