Legend.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. package com.github.mikephil.charting.components;
  2. import android.graphics.DashPathEffect;
  3. import android.graphics.Paint;
  4. import com.github.mikephil.charting.utils.ColorTemplate;
  5. import com.github.mikephil.charting.utils.FSize;
  6. import com.github.mikephil.charting.utils.Utils;
  7. import com.github.mikephil.charting.utils.ViewPortHandler;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. /**
  11. * Class representing the legend of the chart. The legend will contain one entry
  12. * per color and DataSet. Multiple colors in one DataSet are grouped together.
  13. * The legend object is NOT available before setting data to the chart.
  14. *
  15. * @author Philipp Jahoda
  16. */
  17. public class Legend extends ComponentBase {
  18. public enum LegendForm {
  19. /**
  20. * Avoid drawing a form
  21. */
  22. NONE,
  23. /**
  24. * Do not draw the a form, but leave space for it
  25. */
  26. EMPTY,
  27. /**
  28. * Use default (default dataset's form to the legend's form)
  29. */
  30. DEFAULT,
  31. /**
  32. * Draw a square
  33. */
  34. SQUARE,
  35. /**
  36. * Draw a circle
  37. */
  38. CIRCLE,
  39. /**
  40. * Draw a horizontal line
  41. */
  42. LINE
  43. }
  44. public enum LegendHorizontalAlignment {
  45. LEFT, CENTER, RIGHT
  46. }
  47. public enum LegendVerticalAlignment {
  48. TOP, CENTER, BOTTOM
  49. }
  50. public enum LegendOrientation {
  51. HORIZONTAL, VERTICAL
  52. }
  53. public enum LegendDirection {
  54. LEFT_TO_RIGHT, RIGHT_TO_LEFT
  55. }
  56. /**
  57. * The legend entries array
  58. */
  59. private LegendEntry[] mEntries = new LegendEntry[]{};
  60. /**
  61. * Entries that will be appended to the end of the auto calculated entries after calculating the legend.
  62. * (if the legend has already been calculated, you will need to call notifyDataSetChanged() to let the changes take effect)
  63. */
  64. private LegendEntry[] mExtraEntries;
  65. /**
  66. * Are the legend labels/colors a custom value or auto calculated? If false,
  67. * then it's auto, if true, then custom. default false (automatic legend)
  68. */
  69. private boolean mIsLegendCustom = false;
  70. private LegendHorizontalAlignment mHorizontalAlignment = LegendHorizontalAlignment.LEFT;
  71. private LegendVerticalAlignment mVerticalAlignment = LegendVerticalAlignment.BOTTOM;
  72. private LegendOrientation mOrientation = LegendOrientation.HORIZONTAL;
  73. private boolean mDrawInside = false;
  74. /**
  75. * the text direction for the legend
  76. */
  77. private LegendDirection mDirection = LegendDirection.LEFT_TO_RIGHT;
  78. /**
  79. * the shape/form the legend colors are drawn in
  80. */
  81. private LegendForm mShape = LegendForm.SQUARE;
  82. /**
  83. * the size of the legend forms/shapes
  84. */
  85. private float mFormSize = 8f;
  86. /**
  87. * the size of the legend forms/shapes
  88. */
  89. private float mFormLineWidth = 3f;
  90. /**
  91. * Line dash path effect used for shapes that consist of lines.
  92. */
  93. private DashPathEffect mFormLineDashEffect = null;
  94. /**
  95. * the space between the legend entries on a horizontal axis, default 6f
  96. */
  97. private float mXEntrySpace = 6f;
  98. /**
  99. * the space between the legend entries on a vertical axis, default 5f
  100. */
  101. private float mYEntrySpace = 0f;
  102. /**
  103. * the space between the legend entries on a vertical axis, default 2f
  104. * private float mYEntrySpace = 2f; /** the space between the form and the
  105. * actual label/text
  106. */
  107. private float mFormToTextSpace = 5f;
  108. /**
  109. * the space that should be left between stacked forms
  110. */
  111. private float mStackSpace = 3f;
  112. /**
  113. * the maximum relative size out of the whole chart view in percent
  114. */
  115. private float mMaxSizePercent = 0.95f;
  116. /**
  117. * default constructor
  118. */
  119. public Legend() {
  120. this.mTextSize = Utils.convertDpToPixel(10f);
  121. this.mXOffset = Utils.convertDpToPixel(5f);
  122. this.mYOffset = Utils.convertDpToPixel(3f); // 2
  123. }
  124. /**
  125. * Constructor. Provide entries for the legend.
  126. *
  127. * @param entries
  128. */
  129. public Legend(LegendEntry[] entries) {
  130. this();
  131. if (entries == null) {
  132. throw new IllegalArgumentException("entries array is NULL");
  133. }
  134. this.mEntries = entries;
  135. }
  136. /**
  137. * This method sets the automatically computed colors for the legend. Use setCustom(...) to set custom colors.
  138. *
  139. * @param entries
  140. */
  141. public void setEntries(List<LegendEntry> entries) {
  142. mEntries = entries.toArray(new LegendEntry[entries.size()]);
  143. }
  144. public LegendEntry[] getEntries() {
  145. return mEntries;
  146. }
  147. /**
  148. * returns the maximum length in pixels across all legend labels + formsize
  149. * + formtotextspace
  150. *
  151. * @param p the paint object used for rendering the text
  152. * @return
  153. */
  154. public float getMaximumEntryWidth(Paint p) {
  155. float max = 0f;
  156. float maxFormSize = 0f;
  157. float formToTextSpace = Utils.convertDpToPixel(mFormToTextSpace);
  158. for (LegendEntry entry : mEntries) {
  159. final float formSize = Utils.convertDpToPixel(
  160. Float.isNaN(entry.formSize)
  161. ? mFormSize : entry.formSize);
  162. if (formSize > maxFormSize)
  163. maxFormSize = formSize;
  164. String label = entry.label;
  165. if (label == null) continue;
  166. float length = (float) Utils.calcTextWidth(p, label);
  167. if (length > max)
  168. max = length;
  169. }
  170. return max + maxFormSize + formToTextSpace;
  171. }
  172. /**
  173. * returns the maximum height in pixels across all legend labels
  174. *
  175. * @param p the paint object used for rendering the text
  176. * @return
  177. */
  178. public float getMaximumEntryHeight(Paint p) {
  179. float max = 0f;
  180. for (LegendEntry entry : mEntries) {
  181. String label = entry.label;
  182. if (label == null) continue;
  183. float length = (float) Utils.calcTextHeight(p, label);
  184. if (length > max)
  185. max = length;
  186. }
  187. return max;
  188. }
  189. public LegendEntry[] getExtraEntries() {
  190. return mExtraEntries;
  191. }
  192. public void setExtra(List<LegendEntry> entries) {
  193. mExtraEntries = entries.toArray(new LegendEntry[entries.size()]);
  194. }
  195. public void setExtra(LegendEntry[] entries) {
  196. if (entries == null)
  197. entries = new LegendEntry[]{};
  198. mExtraEntries = entries;
  199. }
  200. /**
  201. * Entries that will be appended to the end of the auto calculated
  202. * entries after calculating the legend.
  203. * (if the legend has already been calculated, you will need to call notifyDataSetChanged()
  204. * to let the changes take effect)
  205. */
  206. public void setExtra(int[] colors, String[] labels) {
  207. List<LegendEntry> entries = new ArrayList<>();
  208. for (int i = 0; i < Math.min(colors.length, labels.length); i++) {
  209. final LegendEntry entry = new LegendEntry();
  210. entry.formColor = colors[i];
  211. entry.label = labels[i];
  212. if (entry.formColor == ColorTemplate.COLOR_SKIP ||
  213. entry.formColor == 0)
  214. entry.form = LegendForm.NONE;
  215. else if (entry.formColor == ColorTemplate.COLOR_NONE)
  216. entry.form = LegendForm.EMPTY;
  217. entries.add(entry);
  218. }
  219. mExtraEntries = entries.toArray(new LegendEntry[entries.size()]);
  220. }
  221. /**
  222. * Sets a custom legend's entries array.
  223. * * A null label will start a group.
  224. * This will disable the feature that automatically calculates the legend
  225. * entries from the datasets.
  226. * Call resetCustom() to re-enable automatic calculation (and then
  227. * notifyDataSetChanged() is needed to auto-calculate the legend again)
  228. */
  229. public void setCustom(LegendEntry[] entries) {
  230. mEntries = entries;
  231. mIsLegendCustom = true;
  232. }
  233. /**
  234. * Sets a custom legend's entries array.
  235. * * A null label will start a group.
  236. * This will disable the feature that automatically calculates the legend
  237. * entries from the datasets.
  238. * Call resetCustom() to re-enable automatic calculation (and then
  239. * notifyDataSetChanged() is needed to auto-calculate the legend again)
  240. */
  241. public void setCustom(List<LegendEntry> entries) {
  242. mEntries = entries.toArray(new LegendEntry[entries.size()]);
  243. mIsLegendCustom = true;
  244. }
  245. /**
  246. * Calling this will disable the custom legend entries (set by
  247. * setCustom(...)). Instead, the entries will again be calculated
  248. * automatically (after notifyDataSetChanged() is called).
  249. */
  250. public void resetCustom() {
  251. mIsLegendCustom = false;
  252. }
  253. /**
  254. * @return true if a custom legend entries has been set default
  255. * false (automatic legend)
  256. */
  257. public boolean isLegendCustom() {
  258. return mIsLegendCustom;
  259. }
  260. /**
  261. * returns the horizontal alignment of the legend
  262. *
  263. * @return
  264. */
  265. public LegendHorizontalAlignment getHorizontalAlignment() {
  266. return mHorizontalAlignment;
  267. }
  268. /**
  269. * sets the horizontal alignment of the legend
  270. *
  271. * @param value
  272. */
  273. public void setHorizontalAlignment(LegendHorizontalAlignment value) {
  274. mHorizontalAlignment = value;
  275. }
  276. /**
  277. * returns the vertical alignment of the legend
  278. *
  279. * @return
  280. */
  281. public LegendVerticalAlignment getVerticalAlignment() {
  282. return mVerticalAlignment;
  283. }
  284. /**
  285. * sets the vertical alignment of the legend
  286. *
  287. * @param value
  288. */
  289. public void setVerticalAlignment(LegendVerticalAlignment value) {
  290. mVerticalAlignment = value;
  291. }
  292. /**
  293. * returns the orientation of the legend
  294. *
  295. * @return
  296. */
  297. public LegendOrientation getOrientation() {
  298. return mOrientation;
  299. }
  300. /**
  301. * sets the orientation of the legend
  302. *
  303. * @param value
  304. */
  305. public void setOrientation(LegendOrientation value) {
  306. mOrientation = value;
  307. }
  308. /**
  309. * returns whether the legend will draw inside the chart or outside
  310. *
  311. * @return
  312. */
  313. public boolean isDrawInsideEnabled() {
  314. return mDrawInside;
  315. }
  316. /**
  317. * sets whether the legend will draw inside the chart or outside
  318. *
  319. * @param value
  320. */
  321. public void setDrawInside(boolean value) {
  322. mDrawInside = value;
  323. }
  324. /**
  325. * returns the text direction of the legend
  326. *
  327. * @return
  328. */
  329. public LegendDirection getDirection() {
  330. return mDirection;
  331. }
  332. /**
  333. * sets the text direction of the legend
  334. *
  335. * @param pos
  336. */
  337. public void setDirection(LegendDirection pos) {
  338. mDirection = pos;
  339. }
  340. /**
  341. * returns the current form/shape that is set for the legend
  342. *
  343. * @return
  344. */
  345. public LegendForm getForm() {
  346. return mShape;
  347. }
  348. /**
  349. * sets the form/shape of the legend forms
  350. *
  351. * @param shape
  352. */
  353. public void setForm(LegendForm shape) {
  354. mShape = shape;
  355. }
  356. /**
  357. * sets the size in dp of the legend forms, default 8f
  358. *
  359. * @param size
  360. */
  361. public void setFormSize(float size) {
  362. mFormSize = size;
  363. }
  364. /**
  365. * returns the size in dp of the legend forms
  366. *
  367. * @return
  368. */
  369. public float getFormSize() {
  370. return mFormSize;
  371. }
  372. /**
  373. * sets the line width in dp for forms that consist of lines, default 3f
  374. *
  375. * @param size
  376. */
  377. public void setFormLineWidth(float size) {
  378. mFormLineWidth = size;
  379. }
  380. /**
  381. * returns the line width in dp for drawing forms that consist of lines
  382. *
  383. * @return
  384. */
  385. public float getFormLineWidth() {
  386. return mFormLineWidth;
  387. }
  388. /**
  389. * Sets the line dash path effect used for shapes that consist of lines.
  390. *
  391. * @param dashPathEffect
  392. */
  393. public void setFormLineDashEffect(DashPathEffect dashPathEffect) {
  394. mFormLineDashEffect = dashPathEffect;
  395. }
  396. /**
  397. * @return The line dash path effect used for shapes that consist of lines.
  398. */
  399. public DashPathEffect getFormLineDashEffect() {
  400. return mFormLineDashEffect;
  401. }
  402. /**
  403. * returns the space between the legend entries on a horizontal axis in
  404. * pixels
  405. *
  406. * @return
  407. */
  408. public float getXEntrySpace() {
  409. return mXEntrySpace;
  410. }
  411. /**
  412. * sets the space between the legend entries on a horizontal axis in pixels,
  413. * converts to dp internally
  414. *
  415. * @param space
  416. */
  417. public void setXEntrySpace(float space) {
  418. mXEntrySpace = space;
  419. }
  420. /**
  421. * returns the space between the legend entries on a vertical axis in pixels
  422. *
  423. * @return
  424. */
  425. public float getYEntrySpace() {
  426. return mYEntrySpace;
  427. }
  428. /**
  429. * sets the space between the legend entries on a vertical axis in pixels,
  430. * converts to dp internally
  431. *
  432. * @param space
  433. */
  434. public void setYEntrySpace(float space) {
  435. mYEntrySpace = space;
  436. }
  437. /**
  438. * returns the space between the form and the actual label/text
  439. *
  440. * @return
  441. */
  442. public float getFormToTextSpace() {
  443. return mFormToTextSpace;
  444. }
  445. /**
  446. * sets the space between the form and the actual label/text, converts to dp
  447. * internally
  448. *
  449. * @param space
  450. */
  451. public void setFormToTextSpace(float space) {
  452. this.mFormToTextSpace = space;
  453. }
  454. /**
  455. * returns the space that is left out between stacked forms (with no label)
  456. *
  457. * @return
  458. */
  459. public float getStackSpace() {
  460. return mStackSpace;
  461. }
  462. /**
  463. * sets the space that is left out between stacked forms (with no label)
  464. *
  465. * @param space
  466. */
  467. public void setStackSpace(float space) {
  468. mStackSpace = space;
  469. }
  470. /**
  471. * the total width of the legend (needed width space)
  472. */
  473. public float mNeededWidth = 0f;
  474. /**
  475. * the total height of the legend (needed height space)
  476. */
  477. public float mNeededHeight = 0f;
  478. public float mTextHeightMax = 0f;
  479. public float mTextWidthMax = 0f;
  480. /**
  481. * flag that indicates if word wrapping is enabled
  482. */
  483. private boolean mWordWrapEnabled = false;
  484. /**
  485. * Should the legend word wrap? / this is currently supported only for:
  486. * BelowChartLeft, BelowChartRight, BelowChartCenter. / note that word
  487. * wrapping a legend takes a toll on performance. / you may want to set
  488. * maxSizePercent when word wrapping, to set the point where the text wraps.
  489. * / default: false
  490. *
  491. * @param enabled
  492. */
  493. public void setWordWrapEnabled(boolean enabled) {
  494. mWordWrapEnabled = enabled;
  495. }
  496. /**
  497. * If this is set, then word wrapping the legend is enabled. This means the
  498. * legend will not be cut off if too long.
  499. *
  500. * @return
  501. */
  502. public boolean isWordWrapEnabled() {
  503. return mWordWrapEnabled;
  504. }
  505. /**
  506. * The maximum relative size out of the whole chart view. / If the legend is
  507. * to the right/left of the chart, then this affects the width of the
  508. * legend. / If the legend is to the top/bottom of the chart, then this
  509. * affects the height of the legend. / If the legend is the center of the
  510. * piechart, then this defines the size of the rectangular bounds out of the
  511. * size of the "hole". / default: 0.95f (95%)
  512. *
  513. * @return
  514. */
  515. public float getMaxSizePercent() {
  516. return mMaxSizePercent;
  517. }
  518. /**
  519. * The maximum relative size out of the whole chart view. / If
  520. * the legend is to the right/left of the chart, then this affects the width
  521. * of the legend. / If the legend is to the top/bottom of the chart, then
  522. * this affects the height of the legend. / default: 0.95f (95%)
  523. *
  524. * @param maxSize
  525. */
  526. public void setMaxSizePercent(float maxSize) {
  527. mMaxSizePercent = maxSize;
  528. }
  529. private List<FSize> mCalculatedLabelSizes = new ArrayList<>(16);
  530. private List<Boolean> mCalculatedLabelBreakPoints = new ArrayList<>(16);
  531. private List<FSize> mCalculatedLineSizes = new ArrayList<>(16);
  532. public List<FSize> getCalculatedLabelSizes() {
  533. return mCalculatedLabelSizes;
  534. }
  535. public List<Boolean> getCalculatedLabelBreakPoints() {
  536. return mCalculatedLabelBreakPoints;
  537. }
  538. public List<FSize> getCalculatedLineSizes() {
  539. return mCalculatedLineSizes;
  540. }
  541. /**
  542. * Calculates the dimensions of the Legend. This includes the maximum width
  543. * and height of a single entry, as well as the total width and height of
  544. * the Legend.
  545. *
  546. * @param labelpaint
  547. */
  548. public void calculateDimensions(Paint labelpaint, ViewPortHandler viewPortHandler) {
  549. float defaultFormSize = Utils.convertDpToPixel(mFormSize);
  550. float stackSpace = Utils.convertDpToPixel(mStackSpace);
  551. float formToTextSpace = Utils.convertDpToPixel(mFormToTextSpace);
  552. float xEntrySpace = Utils.convertDpToPixel(mXEntrySpace);
  553. float yEntrySpace = Utils.convertDpToPixel(mYEntrySpace);
  554. boolean wordWrapEnabled = mWordWrapEnabled;
  555. LegendEntry[] entries = mEntries;
  556. int entryCount = entries.length;
  557. mTextWidthMax = getMaximumEntryWidth(labelpaint);
  558. mTextHeightMax = getMaximumEntryHeight(labelpaint);
  559. switch (mOrientation) {
  560. case VERTICAL: {
  561. float maxWidth = 0f, maxHeight = 0f, width = 0f;
  562. float labelLineHeight = Utils.getLineHeight(labelpaint);
  563. boolean wasStacked = false;
  564. for (int i = 0; i < entryCount; i++) {
  565. LegendEntry e = entries[i];
  566. boolean drawingForm = e.form != LegendForm.NONE;
  567. float formSize = Float.isNaN(e.formSize)
  568. ? defaultFormSize
  569. : Utils.convertDpToPixel(e.formSize);
  570. String label = e.label;
  571. if (!wasStacked)
  572. width = 0.f;
  573. if (drawingForm) {
  574. if (wasStacked)
  575. width += stackSpace;
  576. width += formSize;
  577. }
  578. // grouped forms have null labels
  579. if (label != null) {
  580. // make a step to the left
  581. if (drawingForm && !wasStacked)
  582. width += formToTextSpace;
  583. else if (wasStacked) {
  584. maxWidth = Math.max(maxWidth, width);
  585. maxHeight += labelLineHeight + yEntrySpace;
  586. width = 0.f;
  587. wasStacked = false;
  588. }
  589. width += Utils.calcTextWidth(labelpaint, label);
  590. maxHeight += labelLineHeight + yEntrySpace;
  591. } else {
  592. wasStacked = true;
  593. width += formSize;
  594. if (i < entryCount - 1)
  595. width += stackSpace;
  596. }
  597. maxWidth = Math.max(maxWidth, width);
  598. }
  599. mNeededWidth = maxWidth;
  600. mNeededHeight = maxHeight;
  601. break;
  602. }
  603. case HORIZONTAL: {
  604. float labelLineHeight = Utils.getLineHeight(labelpaint);
  605. float labelLineSpacing = Utils.getLineSpacing(labelpaint) + yEntrySpace;
  606. float contentWidth = viewPortHandler.contentWidth() * mMaxSizePercent;
  607. // Start calculating layout
  608. float maxLineWidth = 0.f;
  609. float currentLineWidth = 0.f;
  610. float requiredWidth = 0.f;
  611. int stackedStartIndex = -1;
  612. mCalculatedLabelBreakPoints.clear();
  613. mCalculatedLabelSizes.clear();
  614. mCalculatedLineSizes.clear();
  615. for (int i = 0; i < entryCount; i++) {
  616. LegendEntry e = entries[i];
  617. boolean drawingForm = e.form != LegendForm.NONE;
  618. float formSize = Float.isNaN(e.formSize)
  619. ? defaultFormSize
  620. : Utils.convertDpToPixel(e.formSize);
  621. String label = e.label;
  622. mCalculatedLabelBreakPoints.add(false);
  623. if (stackedStartIndex == -1) {
  624. // we are not stacking, so required width is for this label
  625. // only
  626. requiredWidth = 0.f;
  627. } else {
  628. // add the spacing appropriate for stacked labels/forms
  629. requiredWidth += stackSpace;
  630. }
  631. // grouped forms have null labels
  632. if (label != null) {
  633. mCalculatedLabelSizes.add(Utils.calcTextSize(labelpaint, label));
  634. requiredWidth += drawingForm ? formToTextSpace + formSize : 0.f;
  635. requiredWidth += mCalculatedLabelSizes.get(i).width;
  636. } else {
  637. mCalculatedLabelSizes.add(FSize.getInstance(0.f, 0.f));
  638. requiredWidth += drawingForm ? formSize : 0.f;
  639. if (stackedStartIndex == -1) {
  640. // mark this index as we might want to break here later
  641. stackedStartIndex = i;
  642. }
  643. }
  644. if (label != null || i == entryCount - 1) {
  645. float requiredSpacing = currentLineWidth == 0.f ? 0.f : xEntrySpace;
  646. if (!wordWrapEnabled // No word wrapping, it must fit.
  647. // The line is empty, it must fit
  648. || currentLineWidth == 0.f
  649. // It simply fits
  650. || (contentWidth - currentLineWidth >=
  651. requiredSpacing + requiredWidth)) {
  652. // Expand current line
  653. currentLineWidth += requiredSpacing + requiredWidth;
  654. } else { // It doesn't fit, we need to wrap a line
  655. // Add current line size to array
  656. mCalculatedLineSizes.add(FSize.getInstance(currentLineWidth, labelLineHeight));
  657. maxLineWidth = Math.max(maxLineWidth, currentLineWidth);
  658. // Start a new line
  659. mCalculatedLabelBreakPoints.set(
  660. stackedStartIndex > -1 ? stackedStartIndex
  661. : i, true);
  662. currentLineWidth = requiredWidth;
  663. }
  664. if (i == entryCount - 1) {
  665. // Add last line size to array
  666. mCalculatedLineSizes.add(FSize.getInstance(currentLineWidth, labelLineHeight));
  667. maxLineWidth = Math.max(maxLineWidth, currentLineWidth);
  668. }
  669. }
  670. stackedStartIndex = label != null ? -1 : stackedStartIndex;
  671. }
  672. mNeededWidth = maxLineWidth;
  673. mNeededHeight = labelLineHeight
  674. * (float) (mCalculatedLineSizes.size())
  675. + labelLineSpacing *
  676. (float) (mCalculatedLineSizes.size() == 0
  677. ? 0
  678. : (mCalculatedLineSizes.size() - 1));
  679. break;
  680. }
  681. }
  682. mNeededHeight += mYOffset;
  683. mNeededWidth += mXOffset;
  684. }
  685. }