GanttChart   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 91
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 8
eloc 33
c 1
b 0
f 0
dl 0
loc 91
ccs 37
cts 37
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A drawDataPortion() 0 15 3
A stroke() 0 16 2
A setChartScale() 0 8 2
1
<?php
2
3
/**
4
 * League.Period (https://period.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Period\Chart;
15
16
use League\Period\Period;
17
use League\Period\Sequence;
18
use function array_fill;
19
use function array_splice;
20
use function ceil;
21
use function count;
22
use function floor;
23
use function implode;
24
use function str_pad;
25
use function str_repeat;
26
27
/**
28
 * A class to output a Dataset via a Gantt Bar graph.
29
 */
30
final class GanttChart implements Chart
31
{
32
    /**
33
     * @var GanttChartConfig
34
     */
35
    private $config;
36
37
    /**
38
     * @var float
39
     */
40
    private $start;
41
42
    /**
43
     * @var float
44
     */
45
    private $unit;
46
47
    /**
48
     * New instance.
49
     *
50
     * @param ?GanttChartConfig $config
51
     */
52 3
    public function __construct(?GanttChartConfig $config = null)
53
    {
54 3
        $this->config = $config ?? new GanttChartConfig();
55 3
    }
56
57
    /**
58
     * @inheritDoc
59
     *
60
     * The generated Gantt Bar can be represented like the following but depends on the configuration used
61
     *
62
     * A       [--------)
63
     * B                    [--)
64
     * C                            [-----)
65
     * D              [---------------)
66
     * RESULT         [-)   [--)    [-)
67
     */
68 12
    public function stroke(Data $dataset): void
69
    {
70 12
        $this->setChartScale($dataset);
71 12
        $padding = $this->config->labelAlign();
72 12
        $gap = str_repeat(' ', $this->config->gapSize());
73 12
        $leftMargin = str_repeat(' ', $this->config->leftMarginSize());
74 12
        $lineCharacters = array_fill(0, $this->config->width(), $this->config->space());
75 12
        $labelMaxLength = $dataset->labelMaxLength();
76 12
        $colorCodeIndexes = $this->config->colors();
77 12
        $colorCodeCount = count($colorCodeIndexes);
78 12
        $output = $this->config->output();
79 12
        foreach ($dataset as $offset => [$label, $item]) {
80 9
            $colorIndex = $colorCodeIndexes[$offset % $colorCodeCount];
81 9
            $labelPortion = str_pad($label, $labelMaxLength, ' ', $padding);
82 9
            $dataPortion = $this->drawDataPortion($item, $lineCharacters);
83 9
            $output->writeln($leftMargin.$labelPortion.$gap.$dataPortion, $colorIndex);
84
        }
85 12
    }
86
87
    /**
88
     * Sets the scale to render the line.
89
     */
90 12
    private function setChartScale(Data $dataset): void
91
    {
92 12
        $this->start = 0;
93 12
        $this->unit = 1;
94 12
        $boundaries = $dataset->boundaries();
95 12
        if (null !== $boundaries) {
96 6
            $this->start = $boundaries->getStartDate()->getTimestamp();
97 6
            $this->unit = $this->config->width() / $boundaries->getTimestampInterval();
98
        }
99 12
    }
100
101
    /**
102
     * Convert a Dataset item into a graph data portion.
103
     *
104
     * @param string[] $lineCharacters
105
     */
106 9
    private function drawDataPortion(Sequence $item, array $lineCharacters): string
107
    {
108
        $reducer = function (array $lineCharacters, Period $period): array {
109 6
            $startIndex = (int) floor(($period->getStartDate()->getTimestamp() - $this->start) * $this->unit);
110 6
            $endIndex = (int) ceil(($period->getEndDate()->getTimestamp() - $this->start) * $this->unit);
111 6
            $periodLength = $endIndex - $startIndex;
112
113 6
            array_splice($lineCharacters, $startIndex, $periodLength, array_fill(0, $periodLength, $this->config->body()));
114 6
            $lineCharacters[$startIndex] = $period->isStartIncluded() ? $this->config->startIncluded() : $this->config->startExcluded();
115 6
            $lineCharacters[$endIndex - 1] = $period->isEndIncluded() ? $this->config->endIncluded() : $this->config->endExcluded();
116
117 6
            return $lineCharacters;
118 9
        };
119
120 9
        return implode('', $item->reduce($reducer, $lineCharacters));
121
    }
122
}
123