Browse Source

Add progress helper.

mscherer 6 years ago
parent
commit
e0f94cb2c8

+ 50 - 0
docs/Helper/Progress.md

@@ -0,0 +1,50 @@
+# Progress Helper
+
+A CakePHP helper to handle basic progress calculation and output.
+By default it uses unicode chars to work completely text-based.
+
+The main advantage of the progress helper over default round() calculation is that it only fully displays
+0 and 100 percent borders (including the char icon representation) if truly fully that min/max value.
+So for `0.9999` as well as `0.0001` etc it will not yet display the completely full or empty bar.
+If you want that, you need to pre-round before passing it in.
+
+
+### Setup
+Include helper in your AppView class as
+```php
+$this->addHelper('Tools.Progress', [
+    ...
+]);
+```
+
+You can store default configs also in Configure key `'Progress'`.
+Mainly empty/full chars can be configured this way.
+
+### progressBar()
+Display a text-based progress bar with the progress in percentage as title.
+```php
+echo $this->Progress->progressBar(
+    $percentage // Value 0...1
+    $length, // Char length >= 3 
+    $attributes
+);
+```
+
+### draw()
+Display a text-based progress bar as raw bar.
+```php
+echo $this->Progress->draw(
+    $percentage // Value 0...1
+    $length // Char length >= 3 
+);
+```
+This can be used if you want to customize the usage.
+
+### calculatePercentage()
+
+This method is responsible for the above min/max handling.
+It can be also used standalone.
+```php
+// For $value 0.49 it outputs: 49% 
+echo $this->Number->toPercentage($this->calculatePercentage($value), 0, ['multiply' => true]);
+```

+ 1 - 0
docs/README.md

@@ -48,6 +48,7 @@ Helpers:
 * [Form](Helper/Form.md)
 * [Common](Helper/Common.md)
 * [Format](Helper/Format.md)
+* [Progress](Helper/Progress.md)
 * [Tree](Helper/Tree.md)
 * [Typography](Helper/Typography.md)
 

+ 0 - 2
src/View/Helper/FormatHelper.php

@@ -68,8 +68,6 @@ class FormatHelper extends Helper {
 	];
 
 	/**
-	 * FormatHelper constructor.
-	 *
 	 * @param \Cake\View\View $View
 	 * @param array $config
 	 */

+ 124 - 0
src/View/Helper/ProgressHelper.php

@@ -0,0 +1,124 @@
+<?php
+
+namespace Tools\View\Helper;
+
+use Cake\Core\Configure;
+use Cake\View\Helper;
+use Cake\View\View;
+use InvalidArgumentException;
+use Tools\Utility\Number;
+
+/**
+ * @author Mark Scherer
+ * @license MIT
+ * @property \Cake\View\Helper\HtmlHelper $Html
+ */
+class ProgressHelper extends Helper {
+
+	const LENGTH_MIN = 3;
+
+	/**
+	 * @var array
+	 */
+	public $helpers = ['Html'];
+
+	/**
+	 * @var array
+	 */
+	protected $_defaults = [
+		'empty' => '⬜',
+		'full' => '⬛',
+	];
+
+	/**
+	 * @param \Cake\View\View $View
+	 * @param array $config
+	 */
+	public function __construct(View $View, array $config = []) {
+		$defaults = (array)Configure::read('Progress') + $this->_defaults;
+		$config += $defaults;
+
+		parent::__construct($View, $config);
+	}
+
+	/**
+	 * @param float $value Value 0...1
+	 * @param int $length As char count
+	 * @param array $attributes
+	 * @return string
+	 */
+	public function progressBar($value, $length, array $attributes = []) {
+		$bar = $this->draw($value, $length);
+
+		$attributes += [
+			'title' => Number::toPercentage($this->calculatePercentage($value), 0, ['multiply' => true]),
+		];
+
+		return $this->Html->tag('span', $bar, $attributes);
+	}
+
+	/**
+	 * Render the progress bar based on the current state.
+	 *
+	 * @param float $complete
+	 * @param int $length
+	 * @return string
+	 * @throws \InvalidArgumentException
+	 */
+	public function draw($complete, $length) {
+		if ($complete < 0.0 || $complete > 1.0) {
+			throw new InvalidArgumentException('Min/Max overflow for value `' . $complete . '` (0...1)');
+		}
+		if ($length < static::LENGTH_MIN) {
+			throw new InvalidArgumentException('Min length for such a progress bar is ' . static::LENGTH_MIN);
+		}
+
+		$barLength = $this->calculateBarLength($complete, $length);
+
+		$bar = '';
+		if ($barLength > 0) {
+			$bar = str_repeat($this->getConfig('full'), $barLength);
+		}
+
+		$pad = $length - $barLength;
+		if ($pad > 0) {
+			$bar .= str_repeat($this->getConfig('empty'), $pad);
+		}
+
+		return $bar;
+	}
+
+	/**
+	 * @param float $percentage
+	 * @return float
+	 */
+	public function calculatePercentage($percentage) {
+		$percentageRounded = round($percentage, 2);
+		if ($percentageRounded === 0.00 && $percentage > 0.0) {
+			$percentage = 0.01;
+		}
+		if ($percentageRounded === 1.00 && $percentage < 1.0) {
+			$percentage = 0.99;
+		}
+
+		return $percentage;
+	}
+
+	/**
+	 * @param float $complete
+	 * @param int $length
+	 * @return int
+	 */
+	protected function calculateBarLength($complete, $length) {
+		$barLength = (int)round($length * $complete, 0);
+		if ($barLength === 0 && $complete > 0.0) {
+			$barLength = 1;
+		}
+		if ($barLength === $length && $complete < 1.0) {
+			$barLength = $length - 1;
+		}
+
+		return $barLength;
+	}
+
+}

+ 0 - 2
src/View/Helper/QrCodeHelper.php

@@ -73,8 +73,6 @@ class QrCodeHelper extends Helper {
 	public $formattingTypes = ['url' => 'http', 'tel' => 'tel', 'sms' => 'smsto', 'card' => 'mecard'];
 
 	/**
-	 * QrCodeHelper constructor.
-	 *
 	 * @param \Cake\View\View $View
 	 * @param array $config
 	 */

+ 0 - 2
src/View/Helper/TextHelper.php

@@ -30,8 +30,6 @@ if (!defined('CHAR_HELLIP')) {
 class TextHelper extends CakeTextHelper {
 
 	/**
-	 * Constructor
-	 *
 	 * ### Settings:
 	 *
 	 * - `engine` Class name to use to replace Text functionality.

+ 0 - 2
src/View/Helper/TimeHelper.php

@@ -39,8 +39,6 @@ class TimeHelper extends CakeTimeHelper {
 	protected $_engine;
 
 	/**
-	 * Default Constructor
-	 *
 	 * ### Settings:
 	 *
 	 * - `engine` Class name to use to replace Cake\I18n\Time functionality

+ 82 - 0
tests/TestCase/View/Helper/ProgressHelperTest.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace Tools\Test\TestCase\View\Helper;
+
+use Cake\View\View;
+use Tools\TestSuite\TestCase;
+use Tools\View\Helper\ProgressHelper;
+
+class ProgressHelperTest extends TestCase {
+
+	/**
+	 * @var \Cake\View\View
+	 */
+	protected $View;
+
+	/**
+	 * @var \Tools\View\Helper\ProgressHelper
+	 */
+	protected $progressHelper;
+
+	/**
+	 * @return void
+	 */
+	public function setUp() {
+		parent::setUp();
+
+		$this->View = new View(null);
+		$this->progressHelper = new ProgressHelper($this->View);
+	}
+
+	/**
+	 * @return void
+	 */
+	public function testDraw() {
+		$result = $this->progressHelper->draw(0.00, 3);
+		$this->assertSame('⬜⬜⬜', $result);
+
+		$result = $this->progressHelper->draw(1.00, 3);
+		$this->assertSame('⬛⬛⬛', $result);
+
+		$result = $this->progressHelper->draw(0.50, 3);
+		$this->assertSame('⬛⬛⬜', $result);
+
+		$result = $this->progressHelper->draw(0.30, 5);
+		$this->assertSame('⬛⬛⬜⬜⬜', $result);
+
+		$result = $this->progressHelper->draw(0.01, 3);
+		$this->assertSame('⬛⬜⬜', $result);
+
+		$result = $this->progressHelper->draw(0.99, 3);
+		$this->assertSame('⬛⬛⬜', $result);
+	}
+
+	/**
+	 * @return void
+	 */
+	public function testProgressBar() {
+		$result = $this->progressHelper->progressBar(0.001, 3);
+		$this->assertSame('<span title="1%">⬛⬜⬜</span>', $result);
+
+		$result = $this->progressHelper->progressBar(0.999, 3);
+		$this->assertSame('<span title="99%">⬛⬛⬜</span>', $result);
+
+		$result = $this->progressHelper->progressBar(0.000, 3);
+		$this->assertSame('<span title="0%">⬜⬜⬜</span>', $result);
+
+		$result = $this->progressHelper->progressBar(1.000, 3);
+		$this->assertSame('<span title="100%">⬛⬛⬛</span>', $result);
+	}
+
+	/**
+	 * @return void
+	 */
+	public function testCalculatePercentage() {
+		$result = $this->progressHelper->calculatePercentage(0.001);
+		$this->assertSame(0.01, $result);
+
+		$result = $this->progressHelper->calculatePercentage(0.999);
+		$this->assertSame(0.99, $result);
+	}
+
+}