ProgressHelper.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. namespace Tools\View\Helper;
  3. use Cake\Core\Configure;
  4. use Cake\View\Helper;
  5. use Cake\View\View;
  6. use InvalidArgumentException;
  7. use Tools\Utility\Number;
  8. /**
  9. * The progress element represents the progress of a task.
  10. *
  11. * Tip: Use the <progress> tag in conjunction with JavaScript to display the progress of a task.
  12. *
  13. * Note: The <progress> tag is not suitable for representing a gauge (e.g. disk space usage or relevance of a query result).
  14. * To represent a gauge, use the Meter helper instead.
  15. *
  16. * @author Mark Scherer
  17. * @license MIT
  18. * @property \Cake\View\Helper\HtmlHelper $Html
  19. */
  20. class ProgressHelper extends Helper {
  21. const LENGTH_MIN = 3;
  22. const CHAR_EMPTY = '░';
  23. const CHAR_FULL = '█';
  24. /**
  25. * @var array
  26. */
  27. public $helpers = ['Html'];
  28. /**
  29. * @var array
  30. */
  31. protected $_defaults = [
  32. 'empty' => self::CHAR_EMPTY,
  33. 'full' => self::CHAR_FULL,
  34. ];
  35. /**
  36. * @param \Cake\View\View $View
  37. * @param array $config
  38. */
  39. public function __construct(View $View, array $config = []) {
  40. $defaults = (array)Configure::read('Progress') + $this->_defaults;
  41. $config += $defaults;
  42. parent::__construct($View, $config);
  43. }
  44. /**
  45. * Creates HTML5 progress element.
  46. *
  47. * Note: This requires a textual fallback for IE9 and below.
  48. *
  49. * Options:
  50. *
  51. * @param float $value Value 0...1
  52. * @param array $options
  53. * @param array $attributes
  54. * @return string
  55. */
  56. public function htmlProgressBar($value, array $options = [], array $attributes = []) {
  57. $defaults = [
  58. 'fallbackHtml' => null,
  59. ];
  60. $options += $defaults;
  61. $progress = $this->roundPercentage($value);
  62. $attributes += [
  63. 'value' => number_format($progress * 100, 0),
  64. 'max' => '100',
  65. 'title' => Number::toPercentage($progress, 0, ['multiply' => true]),
  66. ];
  67. $fallback = '';
  68. if ($options['fallbackHtml']) {
  69. $fallback = $options['fallbackHtml'];
  70. }
  71. return $this->Html->tag('progress', $fallback, $attributes);
  72. }
  73. /**
  74. * @param float $value Value 0...1
  75. * @param int $length As char count
  76. * @param array $attributes
  77. * @return string
  78. */
  79. public function progressBar($value, $length, array $attributes = []) {
  80. $bar = $this->draw($value, $length);
  81. $attributes += [
  82. 'title' => Number::toPercentage($this->roundPercentage($value), 0, ['multiply' => true]),
  83. ];
  84. return $this->Html->tag('span', $bar, $attributes);
  85. }
  86. /**
  87. * Render the progress bar based on the current state.
  88. *
  89. * @param float $complete Value between 0 and 1.
  90. * @param int $length Bar length.
  91. * @return string
  92. * @throws \InvalidArgumentException
  93. */
  94. public function draw($complete, $length) {
  95. if ($complete < 0.0 || $complete > 1.0) {
  96. throw new InvalidArgumentException('Min/Max overflow for value `' . $complete . '` (0...1)');
  97. }
  98. if ($length < static::LENGTH_MIN) {
  99. throw new InvalidArgumentException('Min length for such a progress bar is ' . static::LENGTH_MIN);
  100. }
  101. $barLength = $this->calculateBarLength($complete, $length);
  102. $bar = '';
  103. if ($barLength > 0) {
  104. $bar = str_repeat($this->getConfig('full'), $barLength);
  105. }
  106. $pad = $length - $barLength;
  107. if ($pad > 0) {
  108. $bar .= str_repeat($this->getConfig('empty'), $pad);
  109. }
  110. return $bar;
  111. }
  112. /**
  113. * @param float|int $total
  114. * @param float|int $is
  115. * @return float
  116. */
  117. public function calculatePercentage($total, $is) {
  118. $percentage = $total ? $is / $total : 0.0;
  119. return $this->roundPercentage($percentage);
  120. }
  121. /**
  122. * @param float $percentage
  123. * @return float
  124. */
  125. public function roundPercentage($percentage) {
  126. $percentageRounded = round($percentage, 2);
  127. if ($percentageRounded === 0.00 && $percentage > 0.0) {
  128. $percentage = 0.01;
  129. }
  130. if ($percentageRounded === 1.00 && $percentage < 1.0) {
  131. $percentage = 0.99;
  132. }
  133. return (float)$percentage;
  134. }
  135. /**
  136. * @param float $complete
  137. * @param int $length
  138. * @return int
  139. */
  140. protected function calculateBarLength($complete, $length) {
  141. $barLength = (int)round($length * $complete, 0);
  142. if ($barLength === 0 && $complete > 0.0) {
  143. $barLength = 1;
  144. }
  145. if ($barLength === $length && $complete < 1.0) {
  146. $barLength = $length - 1;
  147. }
  148. return $barLength;
  149. }
  150. }